Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_files/build_environment/cmake/download.cmake2
-rw-r--r--build_files/config/pipeline_config.yaml18
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--intern/cycles/blender/sync.h1
-rw-r--r--intern/cycles/kernel/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/device/cpu/compat.h34
-rw-r--r--intern/cycles/kernel/device/oneapi/compat.h16
-rw-r--r--intern/cycles/util/CMakeLists.txt2
-rw-r--r--intern/cycles/util/types.h11
-rw-r--r--intern/cycles/util/types_float2.h11
-rw-r--r--intern/cycles/util/types_float2_impl.h15
-rw-r--r--intern/cycles/util/types_float3.h28
-rw-r--r--intern/cycles/util/types_float3_impl.h31
-rw-r--r--intern/cycles/util/types_float4.h11
-rw-r--r--intern/cycles/util/types_float4_impl.h15
-rw-r--r--intern/cycles/util/types_float8.h7
-rw-r--r--intern/cycles/util/types_float8_impl.h9
-rw-r--r--intern/cycles/util/types_int2.h11
-rw-r--r--intern/cycles/util/types_int2_impl.h11
-rw-r--r--intern/cycles/util/types_int3.h23
-rw-r--r--intern/cycles/util/types_int3_impl.h32
-rw-r--r--intern/cycles/util/types_int4.h11
-rw-r--r--intern/cycles/util/types_int4_impl.h15
-rw-r--r--intern/cycles/util/types_uchar2.h11
-rw-r--r--intern/cycles/util/types_uchar2_impl.h6
-rw-r--r--intern/cycles/util/types_uchar3.h6
-rw-r--r--intern/cycles/util/types_uchar3_impl.h6
-rw-r--r--intern/cycles/util/types_uchar4.h11
-rw-r--r--intern/cycles/util/types_uchar4_impl.h6
-rw-r--r--intern/cycles/util/types_uint2.h11
-rw-r--r--intern/cycles/util/types_uint2_impl.h11
-rw-r--r--intern/cycles/util/types_uint3.h11
-rw-r--r--intern/cycles/util/types_uint3_impl.h11
-rw-r--r--intern/cycles/util/types_uint4.h11
-rw-r--r--intern/cycles/util/types_uint4_impl.h11
-rw-r--r--intern/cycles/util/types_ushort4.h2
-rw-r--r--intern/cycles/util/types_vector3.h26
-rw-r--r--intern/cycles/util/types_vector3_impl.h30
-rw-r--r--release/datafiles/fonts/DejaVuSans.woff2bin0 -> 257564 bytes
-rw-r--r--release/datafiles/fonts/DejaVuSansMono.woff2bin0 -> 145192 bytes
-rw-r--r--release/datafiles/fonts/MaterialIcons-Variable.woff2bin0 -> 1922636 bytes
-rw-r--r--release/datafiles/fonts/Noto Sans CJK Regular.woff2bin0 -> 11672912 bytes
-rw-r--r--release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2bin0 -> 1026984 bytes
-rw-r--r--release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2bin0 -> 253496 bytes
-rw-r--r--release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2bin0 -> 47492 bytes
-rw-r--r--release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2bin0 -> 226740 bytes
-rw-r--r--release/datafiles/fonts/NotoSansDevanagari-Regular.woff2bin0 -> 69872 bytes
-rw-r--r--release/datafiles/fonts/NotoSansEthiopic-Regular.woff2bin0 -> 92608 bytes
-rw-r--r--release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2bin0 -> 101524 bytes
-rw-r--r--release/datafiles/fonts/NotoSansGujarati-Regular.woff2bin0 -> 58668 bytes
-rw-r--r--release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2bin0 -> 66568 bytes
-rw-r--r--release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2bin0 -> 17544 bytes
-rw-r--r--release/datafiles/fonts/NotoSansJavanese-Regular.woff2bin0 -> 34144 bytes
-rw-r--r--release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2bin0 -> 156260 bytes
-rw-r--r--release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2bin0 -> 159848 bytes
-rw-r--r--release/datafiles/fonts/NotoSansMath-Regular.woff2bin0 -> 226460 bytes
-rw-r--r--release/datafiles/fonts/NotoSansMyanmar-Regular.woff2bin0 -> 64692 bytes
-rw-r--r--release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2bin0 -> 152244 bytes
-rw-r--r--release/datafiles/fonts/NotoSansSymbols2-Regular.woff2bin0 -> 201324 bytes
-rw-r--r--release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2bin0 -> 98380 bytes
-rw-r--r--release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2bin0 -> 209708 bytes
-rw-r--r--release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2bin0 -> 46852 bytes
-rw-r--r--release/datafiles/fonts/bmonofont-i18n.ttfbin5576400 -> 0 bytes
-rw-r--r--release/datafiles/fonts/droidsans.ttfbin5342868 -> 0 bytes
-rw-r--r--release/datafiles/fonts/lastresort.woff2bin0 -> 118564 bytes
-rw-r--r--release/datafiles/splash.pngbin1091604 -> 842492 bytes
-rw-r--r--release/scripts/startup/bl_operators/node.py32
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py30
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py5
-rw-r--r--source/blender/blenfont/BLF_api.h6
-rw-r--r--source/blender/blenfont/intern/blf_font.c201
-rw-r--r--source/blender/blenfont/intern/blf_font_default.c2
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c16
-rw-r--r--source/blender/blenfont/intern/blf_internal.h6
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h6
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_idprop.h1
-rw-r--r--source/blender/blenkernel/BKE_idprop.hh3
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_screen.h6
-rw-r--r--source/blender/blenkernel/intern/action.c1
-rw-r--r--source/blender/blenkernel/intern/anim_data.c1
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c1
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc43
-rw-r--r--source/blender/blenkernel/intern/fcurve.c1
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c1
-rw-r--r--source/blender/blenkernel/intern/idprop_create.cc8
-rw-r--r--source/blender/blenkernel/intern/key.c1
-rw-r--r--source/blender/blenkernel/intern/lib_override.cc1
-rw-r--r--source/blender/blenlib/BLI_index_range.hh4
-rw-r--r--source/blender/blenlib/BLI_listbase_wrapper.hh2
-rw-r--r--source/blender/blenlib/BLI_map.hh4
-rw-r--r--source/blender/blenlib/BLI_set.hh4
-rw-r--r--source/blender/blenlib/tests/BLI_set_test.cc10
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc1
-rw-r--r--source/blender/draw/CMakeLists.txt6
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_defines.hh4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_film.cc25
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_film.hh4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc68
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.hh5
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_motion_blur.cc262
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_motion_blur.hh132
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc51
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh3
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sampling.cc2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.cc8
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.hh5
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh38
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.cc30
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.hh7
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.cc29
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl116
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl103
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl221
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl48
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl104
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl38
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh3
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh44
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh43
-rw-r--r--source/blender/draw/intern/draw_instance_data.c1
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h2
-rw-r--r--source/blender/draw/intern/draw_texture_pool.h1
-rw-r--r--source/blender/draw/intern/shaders/common_math_geom_lib.glsl24
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c1
-rw-r--r--source/blender/editors/animation/anim_deps.c1
-rw-r--r--source/blender/editors/animation/anim_draw.c1
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c1
-rw-r--r--source/blender/editors/animation/drivers.c1
-rw-r--r--source/blender/editors/animation/keyframes_general.c1
-rw-r--r--source/blender/editors/animation/keyframing.c1
-rw-r--r--source/blender/editors/animation/keyingsets.c1
-rw-r--r--source/blender/editors/armature/pose_slide.c1
-rw-r--r--source/blender/editors/armature/pose_utils.c1
-rw-r--r--source/blender/editors/asset/ED_asset_list.h2
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference_enum.cc6
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc7
-rw-r--r--source/blender/editors/include/UI_interface.h6
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_driver.c1
-rw-r--r--source/blender/editors/interface/interface_anim.c1
-rw-r--r--source/blender/editors/interface/interface_ops.c1
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.cc1
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c1
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc4
-rw-r--r--source/blender/editors/interface/interface_template_list.cc16
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/object/object_constraint.c1
-rw-r--r--source/blender/editors/render/render_update.cc26
-rw-r--r--source/blender/editors/screen/screen_user_menu.c1
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection.cc3
-rw-r--r--source/blender/editors/space_console/space_console.c1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c1
-rw-r--r--source/blender/editors/space_node/node_group.cc14
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc1
-rw-r--r--source/blender/editors/space_text/space_text.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_material.h14
-rw-r--r--source/blender/gpu/GPU_shader.h2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc22
-rw-r--r--source/blender/gpu/intern/gpu_material.c52
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c61
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h3
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc16
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh2
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc3
-rw-r--r--source/blender/io/collada/BCAnimationCurve.cpp2
-rw-r--r--source/blender/makesdna/DNA_asset_types.h2
-rw-r--r--source/blender/makesdna/DNA_layer_types.h2
-rw-r--r--source/blender/makesrna/RNA_access.h241
-rw-r--r--source/blender/makesrna/RNA_path.h259
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/rna_access.c1336
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c1
-rw-r--r--source/blender/makesrna/intern/rna_access_internal.h10
-rw-r--r--source/blender/makesrna/intern/rna_color.c1
-rw-r--r--source/blender/makesrna/intern/rna_internal.h8
-rw-r--r--source/blender/makesrna/intern/rna_path.cc1360
-rw-r--r--source/blender/makesrna/intern/rna_ui.c6
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc104
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc1
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc1
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc1
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc1
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c1
-rw-r--r--source/blender/python/intern/bpy_rna.c1
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c1
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c1
-rw-r--r--source/creator/creator.c1
198 files changed, 3690 insertions, 2296 deletions
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index 76744aa9b0c..547bf77f8dd 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
## Update and uncomment this in the release branch
-set(BLENDER_VERSION 3.3)
+# set(BLENDER_VERSION 3.1)
function(download_source dep)
set(TARGET_FILE ${${dep}_FILE})
diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml
index aedaf35629b..82cd009ea95 100644
--- a/build_files/config/pipeline_config.yaml
+++ b/build_files/config/pipeline_config.yaml
@@ -5,38 +5,38 @@
update-code:
git:
submodules:
- - branch: blender-v3.3-release
+ - branch: master
commit_id: HEAD
path: release/scripts/addons
- - branch: blender-v3.3-release
+ - branch: master
commit_id: HEAD
path: release/scripts/addons_contrib
- - branch: blender-v3.3-release
+ - branch: master
commit_id: HEAD
path: release/datafiles/locale
- - branch: blender-v3.3-release
+ - branch: master
commit_id: HEAD
path: source/tools
svn:
libraries:
darwin-arm64:
- branch: tags/blender-3.3-release
+ branch: trunk
commit_id: HEAD
path: lib/darwin_arm64
darwin-x86_64:
- branch: tags/blender-3.3-release
+ branch: trunk
commit_id: HEAD
path: lib/darwin
linux-x86_64:
- branch: tags/blender-3.3-release
+ branch: trunk
commit_id: HEAD
path: lib/linux_centos7_x86_64
windows-amd64:
- branch: tags/blender-3.3-release
+ branch: trunk
commit_id: HEAD
path: lib/win64_vc15
tests:
- branch: tags/blender-3.3-release
+ branch: trunk
commit_id: HEAD
path: lib/tests
benchmarks:
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 0176a888377..18c16a60993 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = V3.3
+PROJECT_NUMBER = V3.4
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
index 5cc18452ac1..0ad4ca6fe83 100644
--- a/intern/cycles/blender/sync.h
+++ b/intern/cycles/blender/sync.h
@@ -7,6 +7,7 @@
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "RNA_blender_cpp.h"
+#include "RNA_path.h"
#include "RNA_types.h"
#include "blender/id_map.h"
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 8ecdac6ee27..dfcd75a135e 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -355,8 +355,6 @@ set(SRC_UTIL_HEADERS
../util/types_uint4.h
../util/types_uint4_impl.h
../util/types_ushort4.h
- ../util/types_vector3.h
- ../util/types_vector3_impl.h
)
set(LIB
diff --git a/intern/cycles/kernel/device/cpu/compat.h b/intern/cycles/kernel/device/cpu/compat.h
index 631e55e0d42..1e3e790ca1f 100644
--- a/intern/cycles/kernel/device/cpu/compat.h
+++ b/intern/cycles/kernel/device/cpu/compat.h
@@ -33,38 +33,4 @@ CCL_NAMESPACE_BEGIN
#define kernel_assert(cond) assert(cond)
-/* Macros to handle different memory storage on different devices */
-
-#ifdef __KERNEL_SSE2__
-typedef vector3<sseb> sse3b;
-typedef vector3<ssef> sse3f;
-typedef vector3<ssei> sse3i;
-
-ccl_device_inline void print_sse3b(const char *label, sse3b &a)
-{
- print_sseb(label, a.x);
- print_sseb(label, a.y);
- print_sseb(label, a.z);
-}
-
-ccl_device_inline void print_sse3f(const char *label, sse3f &a)
-{
- print_ssef(label, a.x);
- print_ssef(label, a.y);
- print_ssef(label, a.z);
-}
-
-ccl_device_inline void print_sse3i(const char *label, sse3i &a)
-{
- print_ssei(label, a.x);
- print_ssei(label, a.y);
- print_ssei(label, a.z);
-}
-
-# if defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__)
-typedef vector3<avxf> avx3f;
-# endif
-
-#endif
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/oneapi/compat.h b/intern/cycles/kernel/device/oneapi/compat.h
index 1b25259bcf5..ccd141aa892 100644
--- a/intern/cycles/kernel/device/oneapi/compat.h
+++ b/intern/cycles/kernel/device/oneapi/compat.h
@@ -149,25 +149,13 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
/* clang-format on */
/* Types */
+
/* It's not possible to use sycl types like sycl::float3, sycl::int3, etc
- * because these types have different interfaces from blender version */
+ * because these types have different interfaces from blender version. */
using uchar = unsigned char;
using sycl::half;
-struct float3 {
- float x, y, z;
-};
-
-ccl_always_inline float3 make_float3(float x, float y, float z)
-{
- return {x, y, z};
-}
-ccl_always_inline float3 make_float3(float x)
-{
- return {x, x, x};
-}
-
/* math functions */
#define fabsf(x) sycl::fabs((x))
#define copysignf(x, y) sycl::copysign((x), (y))
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 9bc9f00e142..b33bad79e6c 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -129,8 +129,6 @@ set(SRC_HEADERS
types_uint4.h
types_uint4_impl.h
types_ushort4.h
- types_vector3.h
- types_vector3_impl.h
unique_ptr.h
vector.h
version.h
diff --git a/intern/cycles/util/types.h b/intern/cycles/util/types.h
index 031c2f7c4c1..26031d9e0fd 100644
--- a/intern/cycles/util/types.h
+++ b/intern/cycles/util/types.h
@@ -12,6 +12,7 @@
#if !defined(__KERNEL_GPU__)
# include <stdint.h>
+# include <stdio.h>
#endif
#include "util/defines.h"
@@ -70,6 +71,12 @@ ccl_device_inline bool is_power_of_two(size_t x)
CCL_NAMESPACE_END
+/* Most GPU APIs matching native vector types, so we only need to implement them for
+ * CPU and oneAPI. */
+#if defined(__KERNEL_GPU__) && !defined(__KERNEL_ONEAPI__)
+# define __KERNEL_NATIVE_VECTOR_TYPES__
+#endif
+
/* Vectorized types declaration. */
#include "util/types_uchar2.h"
#include "util/types_uchar3.h"
@@ -90,8 +97,6 @@ CCL_NAMESPACE_END
#include "util/types_float4.h"
#include "util/types_float8.h"
-#include "util/types_vector3.h"
-
/* Vectorized types implementation. */
#include "util/types_uchar2_impl.h"
#include "util/types_uchar3_impl.h"
@@ -110,8 +115,6 @@ CCL_NAMESPACE_END
#include "util/types_float4_impl.h"
#include "util/types_float8_impl.h"
-#include "util/types_vector3_impl.h"
-
/* SSE types. */
#ifndef __KERNEL_GPU__
# include "util/sseb.h"
diff --git a/intern/cycles/util/types_float2.h b/intern/cycles/util/types_float2.h
index 07b9ec0986b..f37aa1b4ad2 100644
--- a/intern/cycles/util/types_float2.h
+++ b/intern/cycles/util/types_float2.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_FLOAT2_H__
-#define __UTIL_TYPES_FLOAT2_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,18 +9,18 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct float2 {
float x, y;
+# ifndef __KERNEL_GPU__
__forceinline float operator[](int i) const;
__forceinline float &operator[](int i);
+# endif
};
ccl_device_inline float2 make_float2(float x, float y);
ccl_device_inline void print_float2(const char *label, const float2 &a);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT2_H__ */
diff --git a/intern/cycles/util/types_float2_impl.h b/intern/cycles/util/types_float2_impl.h
index 45fc90c52bd..9d1820fe17d 100644
--- a/intern/cycles/util/types_float2_impl.h
+++ b/intern/cycles/util/types_float2_impl.h
@@ -1,20 +1,16 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_FLOAT2_IMPL_H__
-#define __UTIL_TYPES_FLOAT2_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
#endif
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
__forceinline float float2::operator[](int i) const
{
util_assert(i >= 0);
@@ -28,6 +24,7 @@ __forceinline float &float2::operator[](int i)
util_assert(i < 2);
return *(&x + i);
}
+# endif
ccl_device_inline float2 make_float2(float x, float y)
{
@@ -39,8 +36,6 @@ ccl_device_inline void print_float2(const char *label, const float2 &a)
{
printf("%s: %.8f %.8f\n", label, (double)a.x, (double)a.y);
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT2_IMPL_H__ */
diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h
index c7900acaa69..4e43e928657 100644
--- a/intern/cycles/util/types_float3.h
+++ b/intern/cycles/util/types_float3.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_FLOAT3_H__
-#define __UTIL_TYPES_FLOAT3_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,28 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct ccl_try_align(16) float3
{
-# ifdef __KERNEL_SSE__
+# ifdef __KERNEL_GPU__
+ /* Compact structure for GPU. */
+ float x, y, z;
+# else
+ /* SIMD aligned structure for CPU. */
+# ifdef __KERNEL_SSE__
union {
__m128 m128;
struct {
float x, y, z, w;
};
};
+# else
+ float x, y, z, w;
+# endif
+# endif
+# ifdef __KERNEL_SSE__
+ /* Convenient constructors and operators for SIMD, otherwise default is enough. */
__forceinline float3();
__forceinline float3(const float3 &a);
__forceinline explicit float3(const __m128 &a);
@@ -29,18 +39,18 @@ struct ccl_try_align(16) float3
__forceinline operator __m128 &();
__forceinline float3 &operator=(const float3 &a);
-# else /* __KERNEL_SSE__ */
- float x, y, z, w;
-# endif /* __KERNEL_SSE__ */
+# endif
+# ifndef __KERNEL_GPU__
__forceinline float operator[](int i) const;
__forceinline float &operator[](int i);
+# endif
};
ccl_device_inline float3 make_float3(float f);
ccl_device_inline float3 make_float3(float x, float y, float z);
ccl_device_inline void print_float3(const char *label, const float3 &a);
-#endif /* !defined(__KERNEL_GPU__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
/* Smaller float3 for storage. For math operations this must be converted to float3, so that on the
* CPU SIMD instructions can be used. */
@@ -78,5 +88,3 @@ struct packed_float3 {
static_assert(sizeof(packed_float3) == 12, "packed_float3 expected to be exactly 12 bytes");
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT3_H__ */
diff --git a/intern/cycles/util/types_float3_impl.h b/intern/cycles/util/types_float3_impl.h
index 2e6e864c8ea..cbd3f76dae4 100644
--- a/intern/cycles/util/types_float3_impl.h
+++ b/intern/cycles/util/types_float3_impl.h
@@ -1,20 +1,15 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_FLOAT3_IMPL_H__
-#define __UTIL_TYPES_FLOAT3_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
#endif
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
# ifdef __KERNEL_SSE__
__forceinline float3::float3()
{
@@ -45,6 +40,7 @@ __forceinline float3 &float3::operator=(const float3 &a)
}
# endif /* __KERNEL_SSE__ */
+# ifndef __KERNEL_GPU__
__forceinline float float3::operator[](int i) const
{
util_assert(i >= 0);
@@ -58,23 +54,32 @@ __forceinline float &float3::operator[](int i)
util_assert(i < 3);
return *(&x + i);
}
+# endif
ccl_device_inline float3 make_float3(float f)
{
-# ifdef __KERNEL_SSE__
- float3 a(_mm_set1_ps(f));
+# ifdef __KERNEL_GPU__
+ float3 a = {f, f, f};
# else
+# ifdef __KERNEL_SSE__
+ float3 a(_mm_set1_ps(f));
+# else
float3 a = {f, f, f, f};
+# endif
# endif
return a;
}
ccl_device_inline float3 make_float3(float x, float y, float z)
{
-# ifdef __KERNEL_SSE__
- float3 a(_mm_set_ps(0.0f, z, y, x));
+# ifdef __KERNEL_GPU__
+ float3 a = {x, y, z};
# else
+# ifdef __KERNEL_SSE__
+ float3 a(_mm_set_ps(0.0f, z, y, x));
+# else
float3 a = {x, y, z, 0.0f};
+# endif
# endif
return a;
}
@@ -83,8 +88,6 @@ ccl_device_inline void print_float3(const char *label, const float3 &a)
{
printf("%s: %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z);
}
-#endif /* !defined(__KERNEL_GPU__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT3_IMPL_H__ */
diff --git a/intern/cycles/util/types_float4.h b/intern/cycles/util/types_float4.h
index 27453bf39e4..6b301c47362 100644
--- a/intern/cycles/util/types_float4.h
+++ b/intern/cycles/util/types_float4.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_FLOAT4_H__
-#define __UTIL_TYPES_FLOAT4_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,7 +9,7 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct int4;
struct ccl_try_align(16) float4
@@ -35,16 +34,16 @@ struct ccl_try_align(16) float4
float x, y, z, w;
# endif /* __KERNEL_SSE__ */
+# ifndef __KERNEL_GPU__
__forceinline float operator[](int i) const;
__forceinline float &operator[](int i);
+# endif
};
ccl_device_inline float4 make_float4(float f);
ccl_device_inline float4 make_float4(float x, float y, float z, float w);
ccl_device_inline float4 make_float4(const int4 &i);
ccl_device_inline void print_float4(const char *label, const float4 &a);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT4_H__ */
diff --git a/intern/cycles/util/types_float4_impl.h b/intern/cycles/util/types_float4_impl.h
index d7858f744e3..77b4fbff788 100644
--- a/intern/cycles/util/types_float4_impl.h
+++ b/intern/cycles/util/types_float4_impl.h
@@ -1,20 +1,15 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_FLOAT4_IMPL_H__
-#define __UTIL_TYPES_FLOAT4_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
#endif
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
# ifdef __KERNEL_SSE__
__forceinline float4::float4()
{
@@ -41,6 +36,7 @@ __forceinline float4 &float4::operator=(const float4 &a)
}
# endif /* __KERNEL_SSE__ */
+# ifndef __KERNEL_GPU__
__forceinline float float4::operator[](int i) const
{
util_assert(i >= 0);
@@ -54,6 +50,7 @@ __forceinline float &float4::operator[](int i)
util_assert(i < 4);
return *(&x + i);
}
+# endif
ccl_device_inline float4 make_float4(float f)
{
@@ -89,8 +86,6 @@ ccl_device_inline void print_float4(const char *label, const float4 &a)
{
printf("%s: %.8f %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z, (double)a.w);
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT4_IMPL_H__ */
diff --git a/intern/cycles/util/types_float8.h b/intern/cycles/util/types_float8.h
index bb9798932ac..29fd632f08e 100644
--- a/intern/cycles/util/types_float8.h
+++ b/intern/cycles/util/types_float8.h
@@ -2,8 +2,7 @@
* Original code Copyright 2017, Intel Corporation
* Modifications Copyright 2018-2022 Blender Foundation. */
-#ifndef __UTIL_TYPES_FLOAT8_H__
-#define __UTIL_TYPES_FLOAT8_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -12,7 +11,7 @@
CCL_NAMESPACE_BEGIN
/* float8 is a reserved type in Metal that has not been implemented. For
- * that reason this is named float8_t. */
+ * that reason this is named float8_t and not using native vector types. */
#ifdef __KERNEL_GPU__
struct float8_t
@@ -52,5 +51,3 @@ ccl_device_inline float8_t
make_float8_t(float a, float b, float c, float d, float e, float f, float g, float h);
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT8_H__ */
diff --git a/intern/cycles/util/types_float8_impl.h b/intern/cycles/util/types_float8_impl.h
index 2ab464a791b..e8576cdaf70 100644
--- a/intern/cycles/util/types_float8_impl.h
+++ b/intern/cycles/util/types_float8_impl.h
@@ -2,17 +2,12 @@
* Original code Copyright 2017, Intel Corporation
* Modifications Copyright 2018-2022 Blender Foundation. */
-#ifndef __UTIL_TYPES_FLOAT8_IMPL_H__
-#define __UTIL_TYPES_FLOAT8_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
#endif
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
CCL_NAMESPACE_BEGIN
#ifdef __KERNEL_AVX2__
@@ -83,5 +78,3 @@ make_float8_t(float a, float b, float c, float d, float e, float f, float g, flo
}
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_FLOAT8_IMPL_H__ */
diff --git a/intern/cycles/util/types_int2.h b/intern/cycles/util/types_int2.h
index bf69cddc653..604713dffcd 100644
--- a/intern/cycles/util/types_int2.h
+++ b/intern/cycles/util/types_int2.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_INT2_H__
-#define __UTIL_TYPES_INT2_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,17 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct int2 {
int x, y;
+# ifndef __KERNEL_GPU__
__forceinline int operator[](int i) const;
__forceinline int &operator[](int i);
+# endif
};
ccl_device_inline int2 make_int2(int x, int y);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT2_H__ */
diff --git a/intern/cycles/util/types_int2_impl.h b/intern/cycles/util/types_int2_impl.h
index 7bdc77369ee..f48c6f46729 100644
--- a/intern/cycles/util/types_int2_impl.h
+++ b/intern/cycles/util/types_int2_impl.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_INT2_IMPL_H__
-#define __UTIL_TYPES_INT2_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,7 +9,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
int int2::operator[](int i) const
{
util_assert(i >= 0);
@@ -24,14 +24,13 @@ int &int2::operator[](int i)
util_assert(i < 2);
return *(&x + i);
}
+# endif
ccl_device_inline int2 make_int2(int x, int y)
{
int2 a = {x, y};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT2_IMPL_H__ */
diff --git a/intern/cycles/util/types_int3.h b/intern/cycles/util/types_int3.h
index f88ff22ac35..3196b158ee9 100644
--- a/intern/cycles/util/types_int3.h
+++ b/intern/cycles/util/types_int3.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_INT3_H__
-#define __UTIL_TYPES_INT3_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,10 +9,15 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct ccl_try_align(16) int3
{
-# ifdef __KERNEL_SSE__
+# ifdef __KERNEL_GPU__
+ /* Compact structure on the GPU. */
+ int x, y, z;
+# else
+ /* SIMD aligned structure for CPU. */
+# ifdef __KERNEL_SSE__
union {
__m128i m128;
struct {
@@ -29,19 +33,20 @@ struct ccl_try_align(16) int3
__forceinline operator __m128i &();
__forceinline int3 &operator=(const int3 &a);
-# else /* __KERNEL_SSE__ */
+# else /* __KERNEL_SSE__ */
int x, y, z, w;
-# endif /* __KERNEL_SSE__ */
+# endif /* __KERNEL_SSE__ */
+# endif
+# ifndef __KERNEL_GPU__
__forceinline int operator[](int i) const;
__forceinline int &operator[](int i);
+# endif
};
ccl_device_inline int3 make_int3(int i);
ccl_device_inline int3 make_int3(int x, int y, int z);
ccl_device_inline void print_int3(const char *label, const int3 &a);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT3_H__ */
diff --git a/intern/cycles/util/types_int3_impl.h b/intern/cycles/util/types_int3_impl.h
index 1c49e97ad32..abc0f4e4309 100644
--- a/intern/cycles/util/types_int3_impl.h
+++ b/intern/cycles/util/types_int3_impl.h
@@ -1,20 +1,15 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_INT3_IMPL_H__
-#define __UTIL_TYPES_INT3_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
#endif
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
# ifdef __KERNEL_SSE__
__forceinline int3::int3()
{
@@ -45,6 +40,7 @@ __forceinline int3 &int3::operator=(const int3 &a)
}
# endif /* __KERNEL_SSE__ */
+# ifndef __KERNEL_GPU__
__forceinline int int3::operator[](int i) const
{
util_assert(i >= 0);
@@ -58,25 +54,33 @@ __forceinline int &int3::operator[](int i)
util_assert(i < 3);
return *(&x + i);
}
+# endif
ccl_device_inline int3 make_int3(int i)
{
-# ifdef __KERNEL_SSE__
- int3 a(_mm_set1_epi32(i));
+# ifdef __KERNEL_GPU__
+ int3 a = {i, i, i};
# else
+# ifdef __KERNEL_SSE__
+ int3 a(_mm_set1_epi32(i));
+# else
int3 a = {i, i, i, i};
+# endif
# endif
return a;
}
ccl_device_inline int3 make_int3(int x, int y, int z)
{
-# ifdef __KERNEL_SSE__
- int3 a(_mm_set_epi32(0, z, y, x));
+# ifdef __KERNEL_GPU__
+ int3 a = {x, y, z};
# else
+# ifdef __KERNEL_SSE__
+ int3 a(_mm_set_epi32(0, z, y, x));
+# else
int3 a = {x, y, z, 0};
+# endif
# endif
-
return a;
}
@@ -84,8 +88,6 @@ ccl_device_inline void print_int3(const char *label, const int3 &a)
{
printf("%s: %d %d %d\n", label, a.x, a.y, a.z);
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT3_IMPL_H__ */
diff --git a/intern/cycles/util/types_int4.h b/intern/cycles/util/types_int4.h
index 9d557c01344..0ac53ffc09c 100644
--- a/intern/cycles/util/types_int4.h
+++ b/intern/cycles/util/types_int4.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_INT4_H__
-#define __UTIL_TYPES_INT4_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,7 +9,7 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct float3;
struct float4;
@@ -37,8 +36,10 @@ struct ccl_try_align(16) int4
int x, y, z, w;
# endif /* __KERNEL_SSE__ */
+# ifndef __KERNEL_GPU__
__forceinline int operator[](int i) const;
__forceinline int &operator[](int i);
+# endif
};
ccl_device_inline int4 make_int4(int i);
@@ -46,8 +47,6 @@ ccl_device_inline int4 make_int4(int x, int y, int z, int w);
ccl_device_inline int4 make_int4(const float3 &f);
ccl_device_inline int4 make_int4(const float4 &f);
ccl_device_inline void print_int4(const char *label, const int4 &a);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT4_H__ */
diff --git a/intern/cycles/util/types_int4_impl.h b/intern/cycles/util/types_int4_impl.h
index 11e1ede6705..2aab29df941 100644
--- a/intern/cycles/util/types_int4_impl.h
+++ b/intern/cycles/util/types_int4_impl.h
@@ -1,20 +1,15 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_INT4_IMPL_H__
-#define __UTIL_TYPES_INT4_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
#endif
-#ifndef __KERNEL_GPU__
-# include <cstdio>
-#endif
-
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
# ifdef __KERNEL_SSE__
__forceinline int4::int4()
{
@@ -45,6 +40,7 @@ __forceinline int4 &int4::operator=(const int4 &a)
}
# endif /* __KERNEL_SSE__ */
+# ifndef __KERNEL_GPU__
__forceinline int int4::operator[](int i) const
{
util_assert(i >= 0);
@@ -58,6 +54,7 @@ __forceinline int &int4::operator[](int i)
util_assert(i < 4);
return *(&x + i);
}
+# endif
ccl_device_inline int4 make_int4(int i)
{
@@ -105,8 +102,6 @@ ccl_device_inline void print_int4(const char *label, const int4 &a)
{
printf("%s: %d %d %d %d\n", label, a.x, a.y, a.z, a.w);
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_INT4_IMPL_H__ */
diff --git a/intern/cycles/util/types_uchar2.h b/intern/cycles/util/types_uchar2.h
index 0b3c9bd0331..ce617248e6e 100644
--- a/intern/cycles/util/types_uchar2.h
+++ b/intern/cycles/util/types_uchar2.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UCHAR2_H__
-#define __UTIL_TYPES_UCHAR2_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,17 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct uchar2 {
uchar x, y;
+# ifndef __KERNEL_GPU__
__forceinline uchar operator[](int i) const;
__forceinline uchar &operator[](int i);
+# endif
};
ccl_device_inline uchar2 make_uchar2(uchar x, uchar y);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR2_H__ */
diff --git a/intern/cycles/util/types_uchar2_impl.h b/intern/cycles/util/types_uchar2_impl.h
index a7254d5eaf2..9f3f3a4efb9 100644
--- a/intern/cycles/util/types_uchar2_impl.h
+++ b/intern/cycles/util/types_uchar2_impl.h
@@ -10,7 +10,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
uchar uchar2::operator[](int i) const
{
util_assert(i >= 0);
@@ -24,13 +25,14 @@ uchar &uchar2::operator[](int i)
util_assert(i < 2);
return *(&x + i);
}
+# endif
ccl_device_inline uchar2 make_uchar2(uchar x, uchar y)
{
uchar2 a = {x, y};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar3.h b/intern/cycles/util/types_uchar3.h
index fc213502ada..aed04c4775e 100644
--- a/intern/cycles/util/types_uchar3.h
+++ b/intern/cycles/util/types_uchar3.h
@@ -10,16 +10,18 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct uchar3 {
uchar x, y, z;
+# ifndef __KERNEL_GPU__
__forceinline uchar operator[](int i) const;
__forceinline uchar &operator[](int i);
+# endif
};
ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar3_impl.h b/intern/cycles/util/types_uchar3_impl.h
index 0c24ffb488a..83eb3c99b3c 100644
--- a/intern/cycles/util/types_uchar3_impl.h
+++ b/intern/cycles/util/types_uchar3_impl.h
@@ -10,7 +10,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
uchar uchar3::operator[](int i) const
{
util_assert(i >= 0);
@@ -24,13 +25,14 @@ uchar &uchar3::operator[](int i)
util_assert(i < 3);
return *(&x + i);
}
+# endif
ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z)
{
uchar3 a = {x, y, z};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar4.h b/intern/cycles/util/types_uchar4.h
index a2a2c945aaa..fb13a98875e 100644
--- a/intern/cycles/util/types_uchar4.h
+++ b/intern/cycles/util/types_uchar4.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UCHAR4_H__
-#define __UTIL_TYPES_UCHAR4_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,17 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct uchar4 {
uchar x, y, z, w;
+# ifndef __KERNEL_GPU__
__forceinline uchar operator[](int i) const;
__forceinline uchar &operator[](int i);
+# endif
};
ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UCHAR4_H__ */
diff --git a/intern/cycles/util/types_uchar4_impl.h b/intern/cycles/util/types_uchar4_impl.h
index 8ec6213a37d..244bb98f883 100644
--- a/intern/cycles/util/types_uchar4_impl.h
+++ b/intern/cycles/util/types_uchar4_impl.h
@@ -10,7 +10,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
uchar uchar4::operator[](int i) const
{
util_assert(i >= 0);
@@ -24,13 +25,14 @@ uchar &uchar4::operator[](int i)
util_assert(i < 4);
return *(&x + i);
}
+# endif
ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w)
{
uchar4 a = {x, y, z, w};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint2.h b/intern/cycles/util/types_uint2.h
index faa0955f903..4d76b628088 100644
--- a/intern/cycles/util/types_uint2.h
+++ b/intern/cycles/util/types_uint2.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UINT2_H__
-#define __UTIL_TYPES_UINT2_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,17 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct uint2 {
uint x, y;
+# ifndef __KERNEL_GPU__
__forceinline uint operator[](uint i) const;
__forceinline uint &operator[](uint i);
+# endif
};
ccl_device_inline uint2 make_uint2(uint x, uint y);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT2_H__ */
diff --git a/intern/cycles/util/types_uint2_impl.h b/intern/cycles/util/types_uint2_impl.h
index cac0ba6b531..b508aaf2543 100644
--- a/intern/cycles/util/types_uint2_impl.h
+++ b/intern/cycles/util/types_uint2_impl.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UINT2_IMPL_H__
-#define __UTIL_TYPES_UINT2_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,7 +9,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
__forceinline uint uint2::operator[](uint i) const
{
util_assert(i < 2);
@@ -22,14 +22,13 @@ __forceinline uint &uint2::operator[](uint i)
util_assert(i < 2);
return *(&x + i);
}
+# endif
ccl_device_inline uint2 make_uint2(uint x, uint y)
{
uint2 a = {x, y};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT2_IMPL_H__ */
diff --git a/intern/cycles/util/types_uint3.h b/intern/cycles/util/types_uint3.h
index 3ff87bfc791..b1571716fc7 100644
--- a/intern/cycles/util/types_uint3.h
+++ b/intern/cycles/util/types_uint3.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UINT3_H__
-#define __UTIL_TYPES_UINT3_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,17 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct uint3 {
uint x, y, z;
+# ifndef __KERNEL_GPU__
__forceinline uint operator[](uint i) const;
__forceinline uint &operator[](uint i);
+# endif
};
ccl_device_inline uint3 make_uint3(uint x, uint y, uint z);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT3_H__ */
diff --git a/intern/cycles/util/types_uint3_impl.h b/intern/cycles/util/types_uint3_impl.h
index 221883a1adb..d36c9f52de9 100644
--- a/intern/cycles/util/types_uint3_impl.h
+++ b/intern/cycles/util/types_uint3_impl.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UINT3_IMPL_H__
-#define __UTIL_TYPES_UINT3_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,7 +9,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
__forceinline uint uint3::operator[](uint i) const
{
util_assert(i < 3);
@@ -22,14 +22,13 @@ __forceinline uint &uint3::operator[](uint i)
util_assert(i < 3);
return *(&x + i);
}
+# endif
ccl_device_inline uint3 make_uint3(uint x, uint y, uint z)
{
uint3 a = {x, y, z};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT3_IMPL_H__ */
diff --git a/intern/cycles/util/types_uint4.h b/intern/cycles/util/types_uint4.h
index 504095b2383..4982b30f577 100644
--- a/intern/cycles/util/types_uint4.h
+++ b/intern/cycles/util/types_uint4.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UINT4_H__
-#define __UTIL_TYPES_UINT4_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,17 +9,17 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct uint4 {
uint x, y, z, w;
+# ifndef __KERNEL_GPU__
__forceinline uint operator[](uint i) const;
__forceinline uint &operator[](uint i);
+# endif
};
ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w);
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT4_H__ */
diff --git a/intern/cycles/util/types_uint4_impl.h b/intern/cycles/util/types_uint4_impl.h
index d78db944a1f..1cfdb9e0992 100644
--- a/intern/cycles/util/types_uint4_impl.h
+++ b/intern/cycles/util/types_uint4_impl.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#ifndef __UTIL_TYPES_UINT4_IMPL_H__
-#define __UTIL_TYPES_UINT4_IMPL_H__
+#pragma once
#ifndef __UTIL_TYPES_H__
# error "Do not include this file directly, include util/types.h instead."
@@ -10,7 +9,8 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifndef __KERNEL_GPU__
__forceinline uint uint4::operator[](uint i) const
{
util_assert(i < 3);
@@ -22,14 +22,13 @@ __forceinline uint &uint4::operator[](uint i)
util_assert(i < 3);
return *(&x + i);
}
+# endif
ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w)
{
uint4 a = {x, y, z, w};
return a;
}
-#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
+#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_UINT4_IMPL_H__ */
diff --git a/intern/cycles/util/types_ushort4.h b/intern/cycles/util/types_ushort4.h
index 9a6e12095ba..aef36f63285 100644
--- a/intern/cycles/util/types_ushort4.h
+++ b/intern/cycles/util/types_ushort4.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
struct ushort4 {
uint16_t x, y, z, w;
diff --git a/intern/cycles/util/types_vector3.h b/intern/cycles/util/types_vector3.h
deleted file mode 100644
index 2e0d68e1bd0..00000000000
--- a/intern/cycles/util/types_vector3.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0
- * Copyright 2011-2022 Blender Foundation */
-
-#ifndef __UTIL_TYPES_VECTOR3_H__
-#define __UTIL_TYPES_VECTOR3_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util/types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-template<typename T> class vector3 {
- public:
- T x, y, z;
-
- __forceinline vector3();
- __forceinline vector3(const T &a);
- __forceinline vector3(const T &x, const T &y, const T &z);
-};
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_VECTOR3_H__ */
diff --git a/intern/cycles/util/types_vector3_impl.h b/intern/cycles/util/types_vector3_impl.h
deleted file mode 100644
index a765780e2d3..00000000000
--- a/intern/cycles/util/types_vector3_impl.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0
- * Copyright 2011-2022 Blender Foundation */
-
-#ifndef __UTIL_TYPES_VECTOR3_IMPL_H__
-#define __UTIL_TYPES_VECTOR3_IMPL_H__
-
-#ifndef __UTIL_TYPES_H__
-# error "Do not include this file directly, include util/types.h instead."
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef __KERNEL_GPU__
-template<typename T> ccl_always_inline vector3<T>::vector3()
-{
-}
-
-template<typename T> ccl_always_inline vector3<T>::vector3(const T &a) : x(a), y(a), z(a)
-{
-}
-
-template<typename T>
-ccl_always_inline vector3<T>::vector3(const T &x, const T &y, const T &z) : x(x), y(y), z(z)
-{
-}
-#endif /* __KERNEL_GPU__ */
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_TYPES_VECTOR3_IMPL_H__ */
diff --git a/release/datafiles/fonts/DejaVuSans.woff2 b/release/datafiles/fonts/DejaVuSans.woff2
new file mode 100644
index 00000000000..a391596a421
--- /dev/null
+++ b/release/datafiles/fonts/DejaVuSans.woff2
Binary files differ
diff --git a/release/datafiles/fonts/DejaVuSansMono.woff2 b/release/datafiles/fonts/DejaVuSansMono.woff2
new file mode 100644
index 00000000000..cf200e12fff
--- /dev/null
+++ b/release/datafiles/fonts/DejaVuSansMono.woff2
Binary files differ
diff --git a/release/datafiles/fonts/MaterialIcons-Variable.woff2 b/release/datafiles/fonts/MaterialIcons-Variable.woff2
new file mode 100644
index 00000000000..048802a6454
--- /dev/null
+++ b/release/datafiles/fonts/MaterialIcons-Variable.woff2
Binary files differ
diff --git a/release/datafiles/fonts/Noto Sans CJK Regular.woff2 b/release/datafiles/fonts/Noto Sans CJK Regular.woff2
new file mode 100644
index 00000000000..5d3854b6bf7
--- /dev/null
+++ b/release/datafiles/fonts/Noto Sans CJK Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2 b/release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2
new file mode 100644
index 00000000000..4d019787bca
--- /dev/null
+++ b/release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..8ee78b73e72
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..c6c1ed5c2cf
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..cdac12cc8e8
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansDevanagari-Regular.woff2 b/release/datafiles/fonts/NotoSansDevanagari-Regular.woff2
new file mode 100644
index 00000000000..2cb157b2c51
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansDevanagari-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansEthiopic-Regular.woff2 b/release/datafiles/fonts/NotoSansEthiopic-Regular.woff2
new file mode 100644
index 00000000000..dc272d98964
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansEthiopic-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..4ebc52f0b59
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansGujarati-Regular.woff2 b/release/datafiles/fonts/NotoSansGujarati-Regular.woff2
new file mode 100644
index 00000000000..6e66a15b1cd
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansGujarati-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..e752468775f
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..4f6033c916f
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansJavanese-Regular.woff2 b/release/datafiles/fonts/NotoSansJavanese-Regular.woff2
new file mode 100644
index 00000000000..aeb0bbe8dab
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansJavanese-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..56fbd8d8bce
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..bdbce8a0b76
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansMath-Regular.woff2 b/release/datafiles/fonts/NotoSansMath-Regular.woff2
new file mode 100644
index 00000000000..bb3baafeb7a
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansMath-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansMyanmar-Regular.woff2 b/release/datafiles/fonts/NotoSansMyanmar-Regular.woff2
new file mode 100644
index 00000000000..f18edac80ed
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansMyanmar-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2 b/release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2
new file mode 100644
index 00000000000..98f940b813e
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansSymbols2-Regular.woff2 b/release/datafiles/fonts/NotoSansSymbols2-Regular.woff2
new file mode 100644
index 00000000000..cefcc2d9c0d
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansSymbols2-Regular.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..a3541942429
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..790235d3a71
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2
new file mode 100644
index 00000000000..507255e6b5c
--- /dev/null
+++ b/release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2
Binary files differ
diff --git a/release/datafiles/fonts/bmonofont-i18n.ttf b/release/datafiles/fonts/bmonofont-i18n.ttf
deleted file mode 100644
index 08b3f723d61..00000000000
--- a/release/datafiles/fonts/bmonofont-i18n.ttf
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/fonts/droidsans.ttf b/release/datafiles/fonts/droidsans.ttf
deleted file mode 100644
index b03e47f087e..00000000000
--- a/release/datafiles/fonts/droidsans.ttf
+++ /dev/null
Binary files differ
diff --git a/release/datafiles/fonts/lastresort.woff2 b/release/datafiles/fonts/lastresort.woff2
new file mode 100644
index 00000000000..e5ad6f353f5
--- /dev/null
+++ b/release/datafiles/fonts/lastresort.woff2
Binary files differ
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index d7c9cdd3a8f..eb1250cf5a5 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index df4ca9ef170..ff9b5a06fb7 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -149,37 +149,6 @@ class NODE_OT_add_node(NodeAddOperator, Operator):
bl_options = {'REGISTER', 'UNDO'}
-# Add a node and link it to an existing socket
-class NODE_OT_add_and_link_node(NodeAddOperator, Operator):
- '''Add a node to the active tree and link to an existing socket'''
- bl_idname = "node.add_and_link_node"
- bl_label = "Add and Link Node"
- bl_options = {'REGISTER', 'UNDO'}
-
- link_socket_index: IntProperty(
- name="Link Socket Index",
- description="Index of the socket to link",
- )
-
- def execute(self, context):
- space = context.space_data
- ntree = space.edit_tree
-
- node = self.create_node(context)
- if not node:
- return {'CANCELLED'}
-
- to_socket = getattr(context, "link_to_socket", None)
- if to_socket:
- ntree.links.new(node.outputs[self.link_socket_index], to_socket)
-
- from_socket = getattr(context, "link_from_socket", None)
- if from_socket:
- ntree.links.new(from_socket, node.inputs[self.link_socket_index])
-
- return {'FINISHED'}
-
-
class NODE_OT_add_search(NodeAddOperator, Operator):
'''Add a node to the active tree'''
bl_idname = "node.add_search"
@@ -306,7 +275,6 @@ class NODE_OT_tree_path_parent(Operator):
classes = (
NodeSetting,
- NODE_OT_add_and_link_node,
NODE_OT_add_node,
NODE_OT_add_search,
NODE_OT_collapse_hide_unused_toggle,
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index e031b32247a..062476f2624 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -162,6 +162,35 @@ class RENDER_PT_eevee_motion_blur(RenderButtonsPanel, Panel):
col.prop(props, "motion_blur_steps", text="Steps")
+class RENDER_PT_eevee_next_motion_blur(RenderButtonsPanel, Panel):
+ bl_label = "Motion Blur"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE_NEXT'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_motion_blur", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_motion_blur
+ col = layout.column()
+ col.prop(props, "motion_blur_position", text="Position")
+ col.prop(props, "motion_blur_shutter")
+ col.separator()
+ col.prop(props, "motion_blur_depth_scale")
+ col.prop(props, "motion_blur_steps", text="Steps")
+
+
class RENDER_PT_eevee_depth_of_field(RenderButtonsPanel, Panel):
bl_label = "Depth of Field"
bl_options = {'DEFAULT_CLOSED'}
@@ -756,6 +785,7 @@ classes = (
RENDER_PT_eevee_film,
RENDER_PT_eevee_next_sampling,
+ RENDER_PT_eevee_next_motion_blur,
RENDER_PT_eevee_next_film,
RENDER_PT_gpencil,
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
index 01bd0adc8df..78aec096510 100644
--- a/release/scripts/startup/bl_ui/properties_view_layer.py
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -79,6 +79,7 @@ class VIEWLAYER_PT_eevee_next_layer_passes_data(ViewLayerButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
+ scene = context.scene
view_layer = context.view_layer
col = layout.column()
@@ -87,7 +88,9 @@ class VIEWLAYER_PT_eevee_next_layer_passes_data(ViewLayerButtonsPanel, Panel):
col.prop(view_layer, "use_pass_mist")
col.prop(view_layer, "use_pass_normal")
col.prop(view_layer, "use_pass_position")
- col.prop(view_layer, "use_pass_vector")
+ sub = col.column()
+ sub.active = not scene.eevee.use_motion_blur
+ sub.prop(view_layer, "use_pass_vector")
class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 83ca9158efc..75824ae056f 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -18,10 +18,10 @@ extern "C" {
#define BLF_DATAFILES_FONTS_DIR "fonts"
/* File name of the default variable-width font. */
-#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf"
+#define BLF_DEFAULT_PROPORTIONAL_FONT "DejaVuSans.woff2"
/* File name of the default fixed-pitch font. */
-#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf"
+#define BLF_DEFAULT_MONOSPACED_FONT "DejaVuSansMono.woff2"
/* enable this only if needed (unused circa 2016) */
#define BLF_BLUR_ENABLE 0
@@ -351,6 +351,8 @@ enum {
BLF_DEFAULT = 1 << 14,
/** Must only be used as last font in the stack. */
BLF_LAST_RESORT = 1 << 15,
+ /** Failure to load this font. Don't try again. */
+ BLF_BAD_FONT = 1 << 16,
};
#define BLF_DRAW_STR_DUMMY_MAX 1024
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 038e73cc928..eb974f33994 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -18,8 +18,9 @@
#include FT_FREETYPE_H
#include FT_GLYPH_H
-#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
+#include FT_TRUETYPE_IDS_H /* Codepoint coverage constants. */
+#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
#include "MEM_guardedalloc.h"
@@ -28,6 +29,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
+#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
@@ -836,7 +838,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
size_t i = 0, i_curr;
rcti gbox_px;
- if (str_len == 0) {
+ if (str_len == 0 || str[0] == 0) {
/* early output. */
return;
}
@@ -1157,7 +1159,7 @@ int blf_font_ascender(FontBLF *font)
char *blf_display_name(FontBLF *font)
{
- if (!font->face->family_name) {
+ if (!blf_ensure_face(font) || !font->face->family_name) {
return NULL;
}
return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name);
@@ -1244,14 +1246,28 @@ static void blf_font_fill(FontBLF *font)
font->glyph_cache_mutex = &blf_glyph_cache_mutex;
}
-FontBLF *blf_font_new(const char *name, const char *filepath)
+/**
+ * Create an FT_Face for this font if not already existing.
+ */
+bool blf_ensure_face(FontBLF *font)
{
- FontBLF *font;
+ if (font->face) {
+ return true;
+ }
+
+ if (font->flags & BLF_BAD_FONT) {
+ return false;
+ }
+
FT_Error err;
- char *mfile;
- font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
- err = FT_New_Face(ft_lib, filepath, 0, &font->face);
+ if (font->filepath) {
+ err = FT_New_Face(ft_lib, font->filepath, 0, &font->face);
+ }
+ if (font->mem) {
+ err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face);
+ }
+
if (err) {
if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
printf("Format of this font file is not supported\n");
@@ -1259,8 +1275,8 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
else {
printf("Error encountered while opening font file\n");
}
- MEM_freeN(font);
- return NULL;
+ font->flags |= BLF_BAD_FONT;
+ return false;
}
err = FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
@@ -1272,28 +1288,28 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
}
if (err) {
printf("Can't set a character map!\n");
- FT_Done_Face(font->face);
- MEM_freeN(font);
- return NULL;
+ font->flags |= BLF_BAD_FONT;
+ return false;
}
- mfile = blf_dir_metrics_search(filepath);
- if (mfile) {
- err = FT_Attach_File(font->face, mfile);
- if (err) {
- fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filepath, (int)err);
+ if (font->filepath) {
+ char *mfile = blf_dir_metrics_search(font->filepath);
+ if (mfile) {
+ err = FT_Attach_File(font->face, mfile);
+ if (err) {
+ fprintf(stderr,
+ "FT_Attach_File failed to load '%s' with error %d\n",
+ font->filepath,
+ (int)err);
+ }
+ MEM_freeN(mfile);
}
- MEM_freeN(mfile);
}
if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
FT_Get_MM_Var(font->face, &(font->variations));
}
- font->name = BLI_strdup(name);
- font->filepath = BLI_strdup(filepath);
- blf_font_fill(font);
-
/* Save TrueType table with bits to quickly test most unicode block coverage. */
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
if (os2_table) {
@@ -1303,17 +1319,11 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4;
}
- /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
- if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU &&
- font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) {
- font->flags |= BLF_LAST_RESORT;
- }
-
if (FT_IS_FIXED_WIDTH(font->face)) {
font->flags |= BLF_MONOSPACED;
}
- if (FT_HAS_KERNING(font->face)) {
+ if (FT_HAS_KERNING(font->face) && !font->kerning_cache) {
/* Create kerning cache table and fill with value indicating "unset". */
font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__);
for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
@@ -1323,49 +1333,114 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
}
}
- return font;
+ return true;
}
-void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
+typedef struct eFaceDetails {
+ char name[50];
+ unsigned int coverage1;
+ unsigned int coverage2;
+ unsigned int coverage3;
+ unsigned int coverage4;
+} eFaceDetails;
+
+/* Details about the fallback fonts we ship, so that we can load only when needed. */
+static const eFaceDetails static_face_details[] = {
+ {"lastresort.woff2", UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX},
+ {"Noto Sans CJK Regular.woff2", 0x30000083L, 0x2BDF3C10L, 0x16L, 0},
+ {"NotoEmoji-VariableFont_wght.woff2", 0x80000003L, 0x241E4ACL, 0x14000000L, 0x4000000L},
+ {"NotoSansArabic-VariableFont_wdth,wght.woff2", TT_UCR_ARABIC, 0, 0, 0},
+ {"NotoSansArmenian-VariableFont_wdth,wght.woff2",
+ TT_UCR_ARMENIAN,
+ TT_UCR_ALPHABETIC_PRESENTATION_FORMS,
+ 0,
+ 0},
+ {"NotoSansBengali-VariableFont_wdth,wght.woff2", TT_UCR_BENGALI, 0, 0, 0},
+ {"NotoSansDevanagari-Regular.woff2", TT_UCR_DEVANAGARI, 0, 0, 0},
+ {"NotoSansEthiopic-Regular.woff2", 0, 0, TT_UCR_ETHIOPIC, 0},
+ {"NotoSansGeorgian-VariableFont_wdth,wght.woff2", TT_UCR_GEORGIAN, 0, 0, 0},
+ {"NotoSansGujarati-Regular.woff2", TT_UCR_GUJARATI, 0, 0, 0},
+ {"NotoSansGurmukhi-VariableFont_wdth,wght.woff2", TT_UCR_GURMUKHI, 0, 0, 0},
+ {"NotoSansHebrew-VariableFont_wdth,wght.woff2", TT_UCR_HEBREW, 0, 0, 0},
+ {"NotoSansJavanese-Regular.woff2", 0x80000003L, 0x2000L, 0, 0},
+ {"NotoSansKannada-VariableFont_wdth,wght.woff2", TT_UCR_KANNADA, 0, 0, 0},
+ {"NotoSansMalayalam-VariableFont_wdth,wght.woff2", TT_UCR_MALAYALAM, 0, 0, 0},
+ {"NotoSansMath-Regular.woff2", 0, TT_UCR_MATHEMATICAL_OPERATORS, 0, 0},
+ {"NotoSansMyanmar-Regular.woff2", 0, 0, TT_UCR_MYANMAR, 0},
+ {"NotoSansSymbols-VariableFont_wght.woff2", 0x3L, 0x200E4B4L, 0, 0},
+ {"NotoSansSymbols2-Regular.woff2", 0x80000003L, 0x200E3E4L, 0x40020L, 0x580A048L},
+ {"NotoSansTamil-VariableFont_wdth,wght.woff2", TT_UCR_TAMIL, 0, 0, 0},
+ {"NotoSansTelugu-VariableFont_wdth,wght.woff2", TT_UCR_TELUGU, 0, 0, 0},
+ {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0},
+};
+
+/* Create a new font from filename OR from passed memory pointer. */
+static FontBLF *blf_font_new_ex(const char *name,
+ const char *filepath,
+ const unsigned char *mem,
+ const size_t mem_size)
{
- FT_Open_Args open;
+ FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
- open.flags = FT_OPEN_MEMORY;
- open.memory_base = (const FT_Byte *)mem;
- open.memory_size = mem_size;
- FT_Attach_Stream(font->face, &open);
-}
-
-FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size)
-{
- FontBLF *font;
- FT_Error err;
+ font->name = BLI_strdup(name);
+ font->filepath = filepath ? BLI_strdup(filepath) : NULL;
+ if (mem) {
+ font->mem = (void *)mem;
+ font->mem_size = mem_size;
+ }
+ blf_font_fill(font);
- font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem");
- err = FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face);
- if (err) {
- MEM_freeN(font);
- return NULL;
+ /* If we have static details about this font we don't need to load the Face. */
+ const eFaceDetails *static_details = NULL;
+ char filename[256];
+ for (int i = 0; i < (int)ARRAY_SIZE(static_face_details); i++) {
+ BLI_split_file_part(font->filepath, filename, sizeof(filename));
+ if (STREQ(static_face_details[i].name, filename)) {
+ static_details = &static_face_details[i];
+ font->UnicodeRanges[0] = static_details->coverage1;
+ font->UnicodeRanges[1] = static_details->coverage2;
+ font->UnicodeRanges[2] = static_details->coverage3;
+ font->UnicodeRanges[3] = static_details->coverage4;
+ break;
+ }
}
- err = FT_Select_Charmap(font->face, ft_encoding_unicode);
- if (err) {
- printf("Can't set the unicode character map!\n");
- FT_Done_Face(font->face);
- MEM_freeN(font);
- return NULL;
+ if (!static_details) {
+ if (!blf_ensure_face(font)) {
+ blf_font_free(font);
+ return NULL;
+ }
}
- if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
- FT_Get_MM_Var(font->face, &(font->variations));
+ /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
+ if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU &&
+ font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) {
+ font->flags |= BLF_LAST_RESORT;
}
- font->name = BLI_strdup(name);
- font->filepath = NULL;
- blf_font_fill(font);
return font;
}
+FontBLF *blf_font_new(const char *name, const char *filename)
+{
+ return blf_font_new_ex(name, filename, NULL, 0);
+}
+
+FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, const size_t mem_size)
+{
+ return blf_font_new_ex(name, NULL, mem, mem_size);
+}
+
+void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const size_t mem_size)
+{
+ FT_Open_Args open;
+
+ open.flags = FT_OPEN_MEMORY;
+ open.memory_base = (const FT_Byte *)mem;
+ open.memory_size = (FT_Long)mem_size;
+ FT_Attach_Stream(font->face, &open);
+}
+
void blf_font_free(FontBLF *font)
{
blf_glyph_cache_clear(font);
@@ -1378,7 +1453,9 @@ void blf_font_free(FontBLF *font)
FT_Done_MM_Var(ft_lib, font->variations);
}
- FT_Done_Face(font->face);
+ if (font->face) {
+ FT_Done_Face(font->face);
+ }
if (font->filepath) {
MEM_freeN(font->filepath);
}
@@ -1396,6 +1473,10 @@ void blf_font_free(FontBLF *font)
bool blf_font_size(FontBLF *font, float size, unsigned int dpi)
{
+ if (!blf_ensure_face(font)) {
+ return false;
+ }
+
/* FreeType uses fixed-point integers in 64ths. */
FT_F26Dot6 ft_size = lroundf(size * 64.0f);
/* Adjust our new size to be on even 64ths. */
diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c
index 1bde25b5776..63957fad003 100644
--- a/source/blender/blenfont/intern/blf_font_default.c
+++ b/source/blender/blenfont/intern/blf_font_default.c
@@ -66,8 +66,6 @@ void BLF_load_font_stack()
}
else {
BLF_enable(font_id, BLF_DEFAULT);
- /* TODO: FontBLF will later load FT_Face on demand. When this is in
- * place we can drop this face now since we have all needed data. */
}
}
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 215f79e6795..48ddbc9f920 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -584,16 +584,22 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
continue;
}
if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) {
- glyph_index = FT_Get_Char_Index(f->face, charcode);
- if (glyph_index) {
- *font = f;
- return glyph_index;
+ if (blf_ensure_face(f)) {
+ glyph_index = FT_Get_Char_Index(f->face, charcode);
+ if (glyph_index) {
+ *font = f;
+ return glyph_index;
+ }
}
}
}
+#ifdef DEBUG
+ printf("Unicode character U+%04X not found in loaded fonts. \n", charcode);
+#endif
+
/* Not found in the stack, return from Last Resort if there is one. */
- if (last_resort) {
+ if (last_resort && blf_ensure_face(last_resort)) {
glyph_index = FT_Get_Char_Index(last_resort->face, charcode);
if (glyph_index) {
*font = last_resort;
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 84037ff4bd0..6207edb0107 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -39,12 +39,14 @@ void blf_font_exit(void);
bool blf_font_id_is_valid(int fontid);
+bool blf_ensure_face(struct FontBLF *font);
+
void blf_draw_buffer__start(struct FontBLF *font);
void blf_draw_buffer__end(void);
struct FontBLF *blf_font_new(const char *name, const char *filepath);
-struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size);
-void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size);
+struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, size_t mem_size);
+void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, size_t mem_size);
/**
* Change font's output size. Returns true if successful in changing the size.
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 5b55f4af0b8..018cef4540f 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -240,9 +240,13 @@ typedef struct FontBLF {
/* # of times this font was loaded */
unsigned int reference_count;
- /** File-path or NULL. */
+ /* Full path to font file or NULL if from memory. */
char *filepath;
+ /* Pointer to in-memory font, or NULL if from file. */
+ void *mem;
+ size_t mem_size;
+
/* Copied from the SFNT OS/2 table. Bit flags for unicode blocks and ranges
* considered "functional". Cached here because face might not always exist.
* See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 2067730faca..ee9c7a964d9 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -17,15 +17,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 303
+#define BLENDER_VERSION 304
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 6
+#define BLENDER_FILE_SUBVERSION 0
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 404ce63a5df..c14da538e7c 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -7,6 +7,7 @@
*/
#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh
index 1e741cc252f..6a42ab1669f 100644
--- a/source/blender/blenkernel/BKE_idprop.hh
+++ b/source/blender/blenkernel/BKE_idprop.hh
@@ -45,6 +45,9 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, d
std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
const StringRefNull value);
+/** \brief Allocate a new IDProperty of type IDP_ID, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, ID *id);
+
/**
* \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT.
*
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 90dbec7ec52..02e3cefe6a5 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -374,6 +374,9 @@ typedef struct bNodeTreeType {
int type; /* type identifier */
char idname[64]; /* identifier name */
+ /* The ID name of group nodes for this type. */
+ char group_idname[64];
+
char ui_name[64];
char ui_description[256];
int ui_icon;
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 3922bfb6c0d..a24a3e05dab 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -291,7 +291,7 @@ enum {
/* Draw an item in the uiList */
typedef void (*uiListDrawItemFunc)(struct uiList *ui_list,
- struct bContext *C,
+ const struct bContext *C,
struct uiLayout *layout,
struct PointerRNA *dataptr,
struct PointerRNA *itemptr,
@@ -303,12 +303,12 @@ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list,
/* Draw the filtering part of an uiList */
typedef void (*uiListDrawFilterFunc)(struct uiList *ui_list,
- struct bContext *C,
+ const struct bContext *C,
struct uiLayout *layout);
/* Filter items of an uiList */
typedef void (*uiListFilterItemsFunc)(struct uiList *ui_list,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *,
const char *propname);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 3ea595cfaf0..c16d19588ed 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -53,6 +53,7 @@
#include "BIK_api.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "BLO_read_write.h"
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 861a89ea9d7..b5b00e031b2 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -43,6 +43,7 @@
#include "BLO_read_write.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "CLG_log.h"
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index eb4784bebff..19fef1ce825 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -53,6 +53,7 @@
#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "BLO_read_write.h"
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 6486be4afe0..7fb4e37f956 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -1163,6 +1163,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
}
CurvesGeometry new_curves{new_point_count, new_curve_count};
+ Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT);
+ Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE);
threading::parallel_invoke(
256 < new_point_count * new_curve_count,
@@ -1170,8 +1174,7 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
[&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); },
[&]() {
/* Copy over point attributes. */
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) {
+ for (bke::AttributeTransferData &attribute : point_attributes) {
threading::parallel_for(copy_point_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
const IndexRange src_range = copy_point_ranges[range_i];
@@ -1182,24 +1185,29 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
{copy_point_range_dst_offsets[range_i], src_range.size()});
}
});
- attribute.dst.finish();
}
-
+ },
+ [&]() {
/* Copy over curve attributes.
* In some cases points are just dissolved, so the the number of
* curves will be the same. That could be optimized in the future. */
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) {
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
if (new_curves.curves_num() == curves.curves_num()) {
attribute.dst.span.copy_from(attribute.src);
}
else {
copy_with_map(attribute.src, new_curve_orig_indices, attribute.dst.span);
}
- attribute.dst.finish();
}
});
+ for (bke::AttributeTransferData &attribute : point_attributes) {
+ attribute.dst.finish();
+ }
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
+ attribute.dst.finish();
+ }
+
return new_curves;
}
@@ -1236,6 +1244,10 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
}
CurvesGeometry new_curves{new_tot_points, new_tot_curves};
+ Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT);
+ Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE);
threading::parallel_invoke(
256 < new_tot_points * new_tot_curves,
@@ -1267,8 +1279,7 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
},
[&]() {
/* Copy over point attributes. */
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) {
+ for (bke::AttributeTransferData &attribute : point_attributes) {
threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
copy_between_buffers(attribute.src.type(),
@@ -1278,11 +1289,11 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
new_point_ranges[range_i]);
}
});
- attribute.dst.finish();
}
+ },
+ [&]() {
/* Copy over curve attributes. */
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) {
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
copy_between_buffers(attribute.src.type(),
@@ -1292,10 +1303,16 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
new_curve_ranges[range_i]);
}
});
- attribute.dst.finish();
}
});
+ for (bke::AttributeTransferData &attribute : point_attributes) {
+ attribute.dst.finish();
+ }
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
+ attribute.dst.finish();
+ }
+
return new_curves;
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 972ff377519..f5876e48241 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -37,6 +37,7 @@
#include "BLO_read_write.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "CLG_log.h"
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 5d54c5c039b..aa33bef998f 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -30,6 +30,7 @@
#include "BKE_object.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "atomic_ops.h"
diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc
index f549393fd12..a2f58baebf7 100644
--- a/source/blender/blenkernel/intern/idprop_create.cc
+++ b/source/blender/blenkernel/intern/idprop_create.cc
@@ -44,6 +44,14 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_n
return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
}
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, ID *value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.id = value;
+ IDProperty *property = IDP_New(IDP_ID, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
static std::unique_ptr<IDProperty, IDPropertyDeleter> array_create(const StringRefNull prop_name,
eIDPropertyType subtype,
size_t array_len)
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 7ef15912567..07ce4e46e9b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -46,6 +46,7 @@
#include "BKE_scene.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "BLO_read_write.h"
diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc
index 4ad8d26cd2a..6afbb9064a8 100644
--- a/source/blender/blenkernel/intern/lib_override.cc
+++ b/source/blender/blenkernel/intern/lib_override.cc
@@ -52,6 +52,7 @@
#include "PIL_time.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh
index 6fcc560d856..2b290e1ba7d 100644
--- a/source/blender/blenlib/BLI_index_range.hh
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -90,10 +90,10 @@ class IndexRange {
return *this;
}
- constexpr Iterator operator++(int) const
+ constexpr Iterator operator++(int)
{
Iterator copied_iterator = *this;
- ++copied_iterator;
+ ++(*this);
return copied_iterator;
}
diff --git a/source/blender/blenlib/BLI_listbase_wrapper.hh b/source/blender/blenlib/BLI_listbase_wrapper.hh
index 25e029a5616..2d631cb2441 100644
--- a/source/blender/blenlib/BLI_listbase_wrapper.hh
+++ b/source/blender/blenlib/BLI_listbase_wrapper.hh
@@ -50,7 +50,7 @@ template<typename T> class ListBaseWrapper {
Iterator operator++(int)
{
Iterator iterator = *this;
- ++*this;
+ ++(*this);
return iterator;
}
diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index 55233676ed8..95d1e344894 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -669,10 +669,10 @@ class Map {
return *this;
}
- BaseIterator operator++(int) const
+ BaseIterator operator++(int)
{
BaseIterator copied_iterator = *this;
- ++copied_iterator;
+ ++(*this);
return copied_iterator;
}
diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh
index 62de4b79e41..a1b6ad9754e 100644
--- a/source/blender/blenlib/BLI_set.hh
+++ b/source/blender/blenlib/BLI_set.hh
@@ -427,10 +427,10 @@ class Set {
return *this;
}
- Iterator operator++(int) const
+ Iterator operator++(int)
{
Iterator copied_iterator = *this;
- ++copied_iterator;
+ ++(*this);
return copied_iterator;
}
diff --git a/source/blender/blenlib/tests/BLI_set_test.cc b/source/blender/blenlib/tests/BLI_set_test.cc
index 5a97b2c7999..9dfa48b5822 100644
--- a/source/blender/blenlib/tests/BLI_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_set_test.cc
@@ -532,8 +532,14 @@ TEST(set, ForwardIterator)
Set<int>::iterator iter1 = set.begin();
int value1 = *iter1;
Set<int>::iterator iter2 = iter1++;
- EXPECT_EQ(*iter1, value1);
- EXPECT_EQ(*iter2, *(++iter1));
+ EXPECT_EQ(*iter2, value1);
+ EXPECT_EQ(*(++iter2), *iter1);
+ /* Interesting find: On GCC & MSVC this will succeed, as the 2nd argument is evaluated before the
+ * 1st. On Apple Clang it's the other way around, and the test fails. */
+ // EXPECT_EQ(*iter1, *(++iter1));
+ Set<int>::iterator iter3 = ++iter1;
+ /* Check that #iter1 itself changed. */
+ EXPECT_EQ(*iter3, *iter1);
}
TEST(set, GenericAlgorithms)
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index e91dab3dd6f..26f1a9e626e 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -83,7 +83,7 @@ typedef struct PathContext {
/* only to access BMO flags */
BMesh *bm_bmoflag;
- BMVert *v_a, *v_b;
+ BMVert *v_pair[2];
BLI_mempool *link_pool;
} PathContext;
@@ -593,17 +593,17 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
}
pc.bm_bmoflag = bm;
- pc.v_a = ((BMVert **)op_verts_slot->data.p)[0];
- pc.v_b = ((BMVert **)op_verts_slot->data.p)[1];
+ pc.v_pair[0] = ((BMVert **)op_verts_slot->data.p)[0];
+ pc.v_pair[1] = ((BMVert **)op_verts_slot->data.p)[1];
/* fail! */
- if (!(pc.v_a && pc.v_b)) {
+ if (!(pc.v_pair[0] && pc.v_pair[1])) {
return;
}
#ifdef DEBUG_PRINT
- printf("%s: v_a: %d\n", __func__, BM_elem_index_get(pc.v_a));
- printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b));
+ printf("%s: v_pair[0]: %d\n", __func__, BM_elem_index_get(pc.v_pair[0]));
+ printf("%s: v_pair[1]: %d\n", __func__, BM_elem_index_get(pc.v_pair[1]));
#endif
/* tag so we won't touch ever (typically hidden faces) */
@@ -618,15 +618,15 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
/* calculate matrix */
{
- bm_vert_pair_to_matrix(&pc.v_a, pc.matrix);
- pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co);
+ bm_vert_pair_to_matrix(pc.v_pair, pc.matrix);
+ pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_pair[0]->co);
}
/* add first vertex */
{
PathLinkState *state;
state = MEM_callocN(sizeof(*state), __func__);
- state_link_add(&pc, state, (BMElem *)pc.v_a, NULL);
+ state_link_add(&pc, state, (BMElem *)pc.v_pair[0], NULL);
BLI_heapsimple_insert(pc.states, state->dist, state);
}
@@ -642,7 +642,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
/* either we insert this into 'pc.states' or its freed */
bool continue_search;
- if (state->link_last->ele == (BMElem *)pc.v_b) {
+ if (state->link_last->ele == (BMElem *)pc.v_pair[1]) {
/* pass, wait until all are found */
#ifdef DEBUG_PRINT
printf("%s: state %p loop found %.4f\n", __func__, state, state->dist);
@@ -698,8 +698,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
} while ((link = link->next));
}
- BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT);
- BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT);
+ BMO_vert_flag_enable(bm, pc.v_pair[0], VERT_OUT);
+ BMO_vert_flag_enable(bm, pc.v_pair[1], VERT_OUT);
BLI_mempool_destroy(pc.link_pool);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
index 6474f853390..129e0093d11 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
@@ -15,6 +15,8 @@
#include "BKE_animsys.h"
+#include "RNA_path.h"
+
namespace blender::deg {
/* Animated property storage. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 4cbb2ce7060..be087c0b2d4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -93,6 +93,7 @@
#include "BKE_world.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 0cb0b60dfb0..7a78280f1f0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -15,6 +15,7 @@
#include "DNA_ID.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_types.h"
#include "BLI_string.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 9a047c70d01..19339fa34ea 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -23,6 +23,7 @@
#include "DNA_scene_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 9744f2e3cee..9d3b392d7b3 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -138,6 +138,7 @@ set(SRC
engines/eevee_next/eevee_film.cc
engines/eevee_next/eevee_instance.cc
engines/eevee_next/eevee_material.cc
+ engines/eevee_next/eevee_motion_blur.cc
engines/eevee_next/eevee_pipeline.cc
engines/eevee_next/eevee_renderbuffers.cc
engines/eevee_next/eevee_sampling.cc
@@ -367,7 +368,12 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
engines/eevee_next/shaders/eevee_geom_world_vert.glsl
+ engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl
+ engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl
+ engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl
+ engines/eevee_next/shaders/eevee_motion_blur_lib.glsl
engines/eevee_next/shaders/eevee_nodetree_lib.glsl
+ engines/eevee_next/shaders/eevee_sampling_lib.glsl
engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl
engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh
index 1e7979b594e..cb02689f34a 100644
--- a/source/blender/draw/engines/eevee_next/eevee_defines.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh
@@ -45,3 +45,7 @@
#define LIGHTPROBE_FILTER_VIS_GROUP_SIZE 16
#define FILM_GROUP_SIZE 16
+
+#define MOTION_BLUR_GROUP_SIZE 32
+
+#define MOTION_BLUR_DILATE_GROUP_SIZE 512
diff --git a/source/blender/draw/engines/eevee_next/eevee_film.cc b/source/blender/draw/engines/eevee_next/eevee_film.cc
index 49f43265aa8..60e5f95d803 100644
--- a/source/blender/draw/engines/eevee_next/eevee_film.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_film.cc
@@ -183,20 +183,17 @@ void Film::init(const int2 &extent, const rcti *output_rect)
* Using the render pass ensure we store the center depth. */
render_passes |= EEVEE_RENDER_PASS_Z;
}
- /* TEST */
- render_passes |= EEVEE_RENDER_PASS_VECTOR;
}
else {
/* Render Case. */
render_passes = eViewLayerEEVEEPassType(inst_.view_layer->eevee.render_passes);
- render_passes |= EEVEE_RENDER_PASS_COMBINED;
-
#define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \
SET_FLAG_FROM_TEST(render_passes, \
(inst_.view_layer->passflag & SCE_PASS_##name_legacy) != 0, \
EEVEE_RENDER_PASS_##name_eevee);
+ ENABLE_FROM_LEGACY(COMBINED, COMBINED)
ENABLE_FROM_LEGACY(Z, Z)
ENABLE_FROM_LEGACY(MIST, MIST)
ENABLE_FROM_LEGACY(NORMAL, NORMAL)
@@ -209,6 +206,7 @@ void Film::init(const int2 &extent, const rcti *output_rect)
ENABLE_FROM_LEGACY(DIFFUSE_DIRECT, DIFFUSE_LIGHT)
ENABLE_FROM_LEGACY(GLOSSY_DIRECT, SPECULAR_LIGHT)
ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT)
+ ENABLE_FROM_LEGACY(VECTOR, VECTOR)
#undef ENABLE_FROM_LEGACY
}
@@ -216,6 +214,11 @@ void Film::init(const int2 &extent, const rcti *output_rect)
/* Filter obsolete passes. */
render_passes &= ~(EEVEE_RENDER_PASS_UNUSED_8 | EEVEE_RENDER_PASS_BLOOM);
+ if (scene_eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) {
+ /* Disable motion vector pass if motion blur is enabled. */
+ render_passes &= ~EEVEE_RENDER_PASS_VECTOR;
+ }
+
/* TODO(@fclem): Can't we rely on depsgraph update notification? */
if (assign_if_different(enabled_passes_, render_passes)) {
sampling.reset();
@@ -383,7 +386,7 @@ void Film::sync()
DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*velocity.camera_steps[STEP_CURRENT]));
DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*velocity.camera_steps[step_next]));
DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &rbuffers.depth_tx);
- DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &rbuffers.combined_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &combined_final_tx_);
DRW_shgroup_uniform_texture_ref(grp, "normal_tx", &rbuffers.normal_tx);
DRW_shgroup_uniform_texture_ref(grp, "vector_tx", &rbuffers.vector_tx);
DRW_shgroup_uniform_texture_ref(grp, "diffuse_light_tx", &rbuffers.diffuse_light_tx);
@@ -458,6 +461,10 @@ float2 Film::pixel_jitter_get() const
eViewLayerEEVEEPassType Film::enabled_passes_get() const
{
+ if (inst_.is_viewport() && data_.use_reprojection) {
+ /* Enable motion vector rendering but not the accumulation buffer. */
+ return enabled_passes_ | EEVEE_RENDER_PASS_VECTOR;
+ }
return enabled_passes_;
}
@@ -538,7 +545,7 @@ void Film::update_sample_table()
}
}
-void Film::accumulate(const DRWView *view)
+void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx)
{
if (inst_.is_viewport()) {
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
@@ -554,6 +561,8 @@ void Film::accumulate(const DRWView *view)
update_sample_table();
+ combined_final_tx_ = combined_final_tx;
+
/* Need to update the static references as there could have change from a previous swap. */
weight_src_tx_ = weight_tx_.current();
weight_dst_tx_ = weight_tx_.next();
@@ -580,12 +589,14 @@ void Film::display()
BLI_assert(inst_.is_viewport());
/* Acquire dummy render buffers for correct binding. They will not be used. */
- inst_.render_buffers.acquire(int2(1), (void *)this);
+ inst_.render_buffers.acquire(int2(1));
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent));
+ combined_final_tx_ = inst_.render_buffers.combined_tx;
+
/* Need to update the static references as there could have change from a previous swap. */
weight_src_tx_ = weight_tx_.current();
weight_dst_tx_ = weight_tx_.next();
diff --git a/source/blender/draw/engines/eevee_next/eevee_film.hh b/source/blender/draw/engines/eevee_next/eevee_film.hh
index 1165b9a4c12..d47e3dfa24b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_film.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_film.hh
@@ -50,6 +50,8 @@ class Film {
/** Static reference as SwapChain does not actually move the objects when swapping. */
GPUTexture *combined_src_tx_ = nullptr;
GPUTexture *combined_dst_tx_ = nullptr;
+ /** Incomming combined buffer with post fx applied (motion blur + depth of field). */
+ GPUTexture *combined_final_tx_ = nullptr;
/** Weight buffers. Double buffered to allow updating it during accumulation. */
SwapChain<Texture, 2> weight_tx_;
/** Static reference as SwapChain does not actually move the objects when swapping. */
@@ -74,7 +76,7 @@ class Film {
void end_sync();
/** Accumulate the newly rendered sample contained in #RenderBuffers and blit to display. */
- void accumulate(const DRWView *view);
+ void accumulate(const DRWView *view, GPUTexture *combined_final_tx);
/** Blit to display. No rendered sample needed. */
void display();
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc
index 9f8cf6dc6ba..70b5cb7d98f 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc
@@ -60,6 +60,8 @@ void Instance::init(const int2 &output_res,
sampling.init(scene);
camera.init();
film.init(output_res, output_rect);
+ velocity.init();
+ motion_blur.init();
main_view.init();
}
@@ -92,15 +94,14 @@ void Instance::update_eval_members()
void Instance::begin_sync()
{
materials.begin_sync();
- velocity.begin_sync();
+ velocity.begin_sync(); /* NOTE: Also syncs camera. */
gpencil_engine_enabled = false;
- render_buffers.sync();
+ motion_blur.sync();
pipelines.sync();
main_view.sync();
world.sync();
- camera.sync();
film.sync();
}
@@ -212,22 +213,12 @@ void Instance::render_sample()
sampling.step();
main_view.render();
-}
-
-/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Interface
- * \{ */
+ motion_blur.step();
+}
-void Instance::render_frame(RenderLayer *render_layer, const char *view_name)
+void Instance::render_read_result(RenderLayer *render_layer, const char *view_name)
{
- while (!sampling.finished()) {
- this->render_sample();
- /* TODO(fclem) print progression. */
- }
-
- /* Read Results. */
eViewLayerEEVEEPassType pass_bits = film.enabled_passes_get();
for (auto i : IndexRange(EEVEE_RENDER_PASS_MAX_BIT)) {
eViewLayerEEVEEPassType pass_type = eViewLayerEEVEEPassType(pass_bits & (1 << i));
@@ -240,7 +231,6 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name)
if (rp) {
float *result = film.read_pass(pass_type);
if (result) {
- std::cout << "read " << pass_name << std::endl;
BLI_mutex_lock(&render->update_render_passes_mutex);
/* WORKAROUND: We use texture read to avoid using a framebuffer to get the render result.
* However, on some implementation, we need a buffer with a few extra bytes for the read to
@@ -252,6 +242,45 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name)
}
}
}
+
+ /* The vector pass is initialized to weird values. Set it to neutral value if not rendered. */
+ if ((pass_bits & EEVEE_RENDER_PASS_VECTOR) == 0) {
+ const char *vector_pass_name = Film::pass_to_render_pass_name(EEVEE_RENDER_PASS_VECTOR);
+ RenderPass *vector_rp = RE_pass_find_by_name(render_layer, vector_pass_name, view_name);
+ if (vector_rp) {
+ memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interface
+ * \{ */
+
+void Instance::render_frame(RenderLayer *render_layer, const char *view_name)
+{
+ while (!sampling.finished()) {
+ this->render_sample();
+
+ /* TODO(fclem) print progression. */
+#if 0
+ /* TODO(fclem): Does not currently work. But would be better to just display to 2D view like
+ * cycles does. */
+ if (G.background == false && first_read) {
+ /* Allow to preview the first sample. */
+ /* TODO(fclem): Might want to not do this during animation render to avoid too much stall. */
+ this->render_read_result(render_layer, view_name);
+ first_read = false;
+ DRW_render_context_disable(render->re);
+ /* Allow the 2D viewport to grab the ticket mutex to display the render. */
+ DRW_render_context_enable(render->re);
+ }
+#endif
+ }
+
+ this->render_read_result(render_layer, view_name);
}
void Instance::draw_viewport(DefaultFramebufferList *dfbl)
@@ -260,7 +289,10 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl)
render_sample();
velocity.step_swap();
- if (!sampling.finished_viewport()) {
+ /* Do not request redraw during viewport animation to lock the framerate to the animation
+ * playback rate. This is in order to preserve motion blur aspect and also to avoid TAA reset
+ * that can show flickering. */
+ if (!sampling.finished_viewport() && !DRW_state_is_playback()) {
DRW_viewport_request_redraw();
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh
index 1efda769648..d714111a3c6 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh
@@ -18,6 +18,7 @@
#include "eevee_camera.hh"
#include "eevee_film.hh"
#include "eevee_material.hh"
+#include "eevee_motion_blur.hh"
#include "eevee_pipeline.hh"
#include "eevee_renderbuffers.hh"
#include "eevee_sampling.hh"
@@ -34,6 +35,7 @@ namespace blender::eevee {
*/
class Instance {
friend VelocityModule;
+ friend MotionBlurModule;
public:
ShaderModule &shaders;
@@ -41,6 +43,7 @@ class Instance {
MaterialModule materials;
PipelineModule pipelines;
VelocityModule velocity;
+ MotionBlurModule motion_blur;
Sampling sampling;
Camera camera;
Film film;
@@ -76,6 +79,7 @@ class Instance {
materials(*this),
pipelines(*this),
velocity(*this),
+ motion_blur(*this),
sampling(*this),
camera(*this),
film(*this),
@@ -138,6 +142,7 @@ class Instance {
RenderEngine *engine,
Depsgraph *depsgraph);
void render_sample();
+ void render_read_result(RenderLayer *render_layer, const char *view_name);
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc
new file mode 100644
index 00000000000..660eb9f1e22
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc
@@ -0,0 +1,262 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ */
+
+// #include "BLI_map.hh"
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_instance.hh"
+#include "eevee_motion_blur.hh"
+// #include "eevee_sampling.hh"
+// #include "eevee_shader_shared.hh"
+// #include "eevee_velocity.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name MotionBlurModule
+ *
+ * \{ */
+
+void MotionBlurModule::init()
+{
+ const Scene *scene = inst_.scene;
+
+ enabled_ = (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) != 0;
+
+ if (!enabled_) {
+ motion_blur_fx_enabled_ = false;
+ return;
+ }
+
+ /* Take into account the steps needed for fx motion blur. */
+ int steps_count = max_ii(1, scene->eevee.motion_blur_steps) * 2 + 1;
+
+ time_steps_.resize(steps_count);
+
+ initial_frame_ = scene->r.cfra;
+ initial_subframe_ = scene->r.subframe;
+ frame_time_ = initial_frame_ + initial_subframe_;
+ shutter_position_ = scene->eevee.motion_blur_position;
+ shutter_time_ = scene->eevee.motion_blur_shutter;
+
+ data_.depth_scale = scene->eevee.motion_blur_depth_scale;
+ motion_blur_fx_enabled_ = true; /* TODO(fclem): UI option. */
+
+ /* Viewport stops here. We only do Post-FX motion blur. */
+ if (inst_.is_viewport()) {
+ enabled_ = false;
+ return;
+ }
+
+ /* Without this there is the possibility of the curve table not being allocated. */
+ BKE_curvemapping_changed((struct CurveMapping *)&scene->r.mblur_shutter_curve, false);
+
+ Vector<float> cdf(CM_TABLE);
+ Sampling::cdf_from_curvemapping(scene->r.mblur_shutter_curve, cdf);
+ Sampling::cdf_invert(cdf, time_steps_);
+
+ for (float &time : time_steps_) {
+ time = this->shutter_time_to_scene_time(time);
+ }
+
+ step_id_ = 1;
+
+ if (motion_blur_fx_enabled_) {
+ /* A bit weird but we have to sync the first 2 steps here because the step()
+ * function is only called after rendering a sample. */
+ inst_.velocity.step_sync(STEP_PREVIOUS, time_steps_[0]);
+ inst_.velocity.step_sync(STEP_NEXT, time_steps_[2]);
+ }
+ inst_.set_time(time_steps_[1]);
+}
+
+/* Runs after rendering a sample. */
+void MotionBlurModule::step()
+{
+ if (!enabled_) {
+ return;
+ }
+
+ if (inst_.sampling.finished()) {
+ /* Restore original frame number. This is because the render pipeline expects it. */
+ RE_engine_frame_set(inst_.render, initial_frame_, initial_subframe_);
+ }
+ else if (inst_.sampling.do_render_sync()) {
+ /* Time to change motion step. */
+ BLI_assert(time_steps_.size() > step_id_ + 2);
+ step_id_ += 2;
+
+ if (motion_blur_fx_enabled_) {
+ inst_.velocity.step_swap();
+ inst_.velocity.step_sync(eVelocityStep::STEP_NEXT, time_steps_[step_id_ + 1]);
+ }
+ inst_.set_time(time_steps_[step_id_]);
+ }
+}
+
+float MotionBlurModule::shutter_time_to_scene_time(float time)
+{
+ switch (shutter_position_) {
+ case SCE_EEVEE_MB_START:
+ /* No offset. */
+ break;
+ case SCE_EEVEE_MB_CENTER:
+ time -= 0.5f;
+ break;
+ case SCE_EEVEE_MB_END:
+ time -= 1.0;
+ break;
+ default:
+ BLI_assert(!"Invalid motion blur position enum!");
+ break;
+ }
+ time *= shutter_time_;
+ time += frame_time_;
+ return time;
+}
+
+void MotionBlurModule::sync()
+{
+ /* Disable motion blur in viewport when changing camera projection type.
+ * Avoids really high velocities. */
+ if (inst_.velocity.camera_changed_projection()) {
+ motion_blur_fx_enabled_ = false;
+ }
+
+ if (!motion_blur_fx_enabled_) {
+ return;
+ }
+
+ eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT;
+ RenderBuffers &render_buffers = inst_.render_buffers;
+
+ {
+ /* Create max velocity tiles. */
+ DRW_PASS_CREATE(tiles_flatten_ps_, DRW_STATE_NO_DRAW);
+ eShaderType shader = (inst_.is_viewport()) ? MOTION_BLUR_TILE_FLATTEN_VIEWPORT :
+ MOTION_BLUR_TILE_FLATTEN_RENDER;
+ GPUShader *sh = inst_.shaders.static_shader_get(shader);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_flatten_ps_);
+ inst_.velocity.bind_resources(grp);
+ DRW_shgroup_uniform_block(grp, "motion_blur_buf", data_);
+ DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &render_buffers.depth_tx);
+ DRW_shgroup_uniform_image_ref(grp, "velocity_img", &render_buffers.vector_tx);
+ DRW_shgroup_uniform_image_ref(grp, "out_tiles_img", &tiles_tx_);
+
+ DRW_shgroup_call_compute_ref(grp, dispatch_flatten_size_);
+ DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_TEXTURE_FETCH);
+ }
+ {
+ /* Expand max velocity tiles by spreading them in their neighborhood. */
+ DRW_PASS_CREATE(tiles_dilate_ps_, DRW_STATE_NO_DRAW);
+ GPUShader *sh = inst_.shaders.static_shader_get(MOTION_BLUR_TILE_DILATE);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_dilate_ps_);
+ DRW_shgroup_storage_block(grp, "tile_indirection_buf", tile_indirection_buf_);
+ DRW_shgroup_uniform_image_ref(grp, "in_tiles_img", &tiles_tx_);
+
+ DRW_shgroup_call_compute_ref(grp, dispatch_dilate_size_);
+ DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE);
+ }
+ {
+ /* Do the motion blur gather algorithm. */
+ DRW_PASS_CREATE(gather_ps_, DRW_STATE_NO_DRAW);
+ GPUShader *sh = inst_.shaders.static_shader_get(MOTION_BLUR_GATHER);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, gather_ps_);
+ inst_.sampling.bind_resources(grp);
+ DRW_shgroup_uniform_block(grp, "motion_blur_buf", data_);
+ DRW_shgroup_storage_block(grp, "tile_indirection_buf", tile_indirection_buf_);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, no_filter);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "velocity_tx", &render_buffers.vector_tx, no_filter);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "in_color_tx", &input_color_tx_, no_filter);
+ DRW_shgroup_uniform_image_ref(grp, "in_tiles_img", &tiles_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "out_color_img", &output_color_tx_);
+
+ DRW_shgroup_call_compute_ref(grp, dispatch_gather_size_);
+ DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH);
+ }
+}
+
+void MotionBlurModule::render(GPUTexture **input_tx, GPUTexture **output_tx)
+{
+ if (!motion_blur_fx_enabled_) {
+ return;
+ }
+
+ const Texture &depth_tx = inst_.render_buffers.depth_tx;
+
+ int2 extent = {depth_tx.width(), depth_tx.height()};
+ int2 tiles_extent = math::divide_ceil(extent, int2(MOTION_BLUR_TILE_SIZE));
+
+ if (inst_.is_viewport()) {
+ float frame_delta = fabsf(inst_.velocity.step_time_delta_get(STEP_PREVIOUS, STEP_CURRENT));
+ /* Avoid highly disturbing blurs, during navigation with high shutter time. */
+ if (frame_delta > 0.0f && !DRW_state_is_navigating()) {
+ /* Rescale motion blur intensity to be shutter time relative and avoid long streak when we
+ * have frame skipping. Always try to stick to what the render frame would look like. */
+ data_.motion_scale = float2(shutter_time_ / frame_delta);
+ }
+ else {
+ /* There is no time change. Motion only comes from viewport navigation and object transform.
+ * Apply motion blur as smoothing and only blur towards last frame. */
+ data_.motion_scale = float2(1.0f, 0.0f);
+
+ if (was_navigating_ != DRW_state_is_navigating()) {
+ /* Special case for navigation events that only last for one frame (for instance mouse
+ * scroll for zooming). For this case we have to wait for the next frame before enabling
+ * the navigation motion blur. */
+ was_navigating_ = DRW_state_is_navigating();
+ return;
+ }
+ }
+ was_navigating_ = DRW_state_is_navigating();
+
+ /* Change texture swizzling to avoid complexity in gather pass shader. */
+ GPU_texture_swizzle_set(inst_.render_buffers.vector_tx, "rgrg");
+ }
+ else {
+ data_.motion_scale = float2(1.0f);
+ }
+ /* Second motion vector is stored inverted. */
+ data_.motion_scale.y = -data_.motion_scale.y;
+ data_.target_size_inv = 1.0f / float2(extent);
+ data_.push_update();
+
+ input_color_tx_ = *input_tx;
+ output_color_tx_ = *output_tx;
+
+ dispatch_flatten_size_ = int3(tiles_extent, 1);
+ dispatch_dilate_size_ = int3(math::divide_ceil(tiles_extent, int2(MOTION_BLUR_GROUP_SIZE)), 1);
+ dispatch_gather_size_ = int3(math::divide_ceil(extent, int2(MOTION_BLUR_GROUP_SIZE)), 1);
+
+ DRW_stats_group_start("Motion Blur");
+
+ tiles_tx_.acquire(tiles_extent, GPU_RGBA16F);
+
+ GPU_storagebuf_clear_to_zero(tile_indirection_buf_);
+
+ DRW_draw_pass(tiles_flatten_ps_);
+ DRW_draw_pass(tiles_dilate_ps_);
+ DRW_draw_pass(gather_ps_);
+
+ tiles_tx_.release();
+
+ DRW_stats_group_end();
+
+ if (inst_.is_viewport()) {
+ /* Reset swizzle since this texture might be reused in other places. */
+ GPU_texture_swizzle_set(inst_.render_buffers.vector_tx, "rgba");
+ }
+
+ /* Swap buffers so that next effect has the right input. */
+ *input_tx = output_color_tx_;
+ *output_tx = input_color_tx_;
+}
+
+/** \} */
+
+} // namespace blender::eevee \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh b/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh
new file mode 100644
index 00000000000..310e94a702b
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * Motion blur is done by accumulating scene samples over shutter time.
+ * Since the number of step is discrete, quite low, and not per pixel randomized,
+ * we couple this with a post processing motion blur.
+ *
+ * The post-fx motion blur is done in two directions, from the previous step and to the next.
+ *
+ * For a scene with 3 motion steps, a flat shutter curve and shutter time of 2 frame
+ * centered on frame we have:
+ *
+ * |--------------------|--------------------|
+ * -1 0 1 Frames
+ *
+ * |-------------|-------------|-------------|
+ * 1 2 3 Motion steps
+ *
+ * |------|------|------|------|------|------|
+ * 0 1 2 4 5 6 7 Time Steps
+ *
+ * |-------------| One motion step blurs this range.
+ * -1 | +1 Objects and geometry steps are recorded here.
+ * 0 Scene is rendered here.
+ *
+ * Since motion step N and N+1 share one time step we reuse it to avoid an extra scene evaluation.
+ *
+ * Note that we have to evaluate -1 and +1 time steps before rendering so eval order is -1, +1, 0.
+ * This is because all GPUBatches from the DRWCache are being free when changing a frame.
+ *
+ * For viewport, we only have the current and previous step data to work with. So we center the
+ * blur on the current frame and extrapolate the motion.
+ *
+ * The Post-FX motion blur is based on:
+ * "A Fast and Stable Feature-Aware Motion Blur Filter"
+ * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_sampling.hh"
+#include "eevee_shader_shared.hh"
+#include "eevee_velocity.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name MotionBlur
+ *
+ * \{ */
+
+/**
+ * Manages time-steps evaluations and accumulation Motion blur.
+ * Also handles Post process motion blur.
+ */
+class MotionBlurModule {
+ private:
+ Instance &inst_;
+
+ /**
+ * Array containing all steps (in scene time) we need to evaluate (not render).
+ * Only odd steps are rendered. The even ones are evaluated for fx motion blur.
+ */
+ Vector<float> time_steps_;
+
+ /** Copy of input frame and sub-frame to restore after render. */
+ int initial_frame_;
+ float initial_subframe_;
+ /** Time of the frame we are rendering. */
+ float frame_time_;
+ /** Enum controlling when the shutter opens. See SceneEEVEE.motion_blur_position. */
+ int shutter_position_;
+ /** Time in scene frame the shutter is open. Controls the amount of blur. */
+ float shutter_time_;
+
+ /** True if motion blur is enabled as a module. */
+ bool enabled_ = false;
+ /** True if motion blur post-fx is enabled. */
+ float motion_blur_fx_enabled_ = false;
+ /** True if last viewport redraw state was already in navigation state. */
+ bool was_navigating_ = false;
+
+ int step_id_ = 0;
+
+ /** Velocity tiles used to guide and speedup the gather pass. */
+ TextureFromPool tiles_tx_;
+
+ GPUTexture *input_color_tx_ = nullptr;
+ GPUTexture *output_color_tx_ = nullptr;
+
+ DRWPass *tiles_flatten_ps_ = nullptr;
+ DRWPass *tiles_dilate_ps_ = nullptr;
+ DRWPass *gather_ps_ = nullptr;
+
+ MotionBlurTileIndirectionBuf tile_indirection_buf_;
+ MotionBlurDataBuf data_;
+ /** Dispatch size for full-screen passes. */
+ int3 dispatch_flatten_size_ = int3(0);
+ int3 dispatch_dilate_size_ = int3(0);
+ int3 dispatch_gather_size_ = int3(0);
+
+ public:
+ MotionBlurModule(Instance &inst) : inst_(inst){};
+ ~MotionBlurModule(){};
+
+ void init();
+
+ void step();
+
+ void sync();
+
+ bool postfx_enabled() const
+ {
+ return motion_blur_fx_enabled_;
+ }
+
+ void render(GPUTexture **input_tx, GPUTexture **output_tx);
+
+ private:
+ float shutter_time_to_scene_time(float time);
+};
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc
index c60054496c1..b69fde7b26c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc
@@ -24,25 +24,7 @@
namespace blender::eevee {
-void RenderBuffers::sync()
-{
- depth_tx.sync();
- combined_tx.sync();
-
- normal_tx.sync();
- vector_tx.sync();
- diffuse_light_tx.sync();
- diffuse_color_tx.sync();
- specular_light_tx.sync();
- specular_color_tx.sync();
- volume_light_tx.sync();
- emission_tx.sync();
- environment_tx.sync();
- shadow_tx.sync();
- ambient_occlusion_tx.sync();
-}
-
-void RenderBuffers::acquire(int2 extent, void *owner)
+void RenderBuffers::acquire(int2 extent)
{
auto pass_extent = [&](eViewLayerEEVEEPassType pass_bit) -> int2 {
/* Use dummy texture for disabled passes. Allows correct bindings. */
@@ -53,25 +35,26 @@ void RenderBuffers::acquire(int2 extent, void *owner)
eGPUTextureFormat float_format = GPU_R16F;
/* Depth and combined are always needed. */
- depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8, owner);
- combined_tx.acquire(extent, color_format, owner);
+ depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8);
+ combined_tx.acquire(extent, color_format);
- bool do_vector_render_pass = inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR;
+ bool do_vector_render_pass = (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR) ||
+ (inst_.motion_blur.postfx_enabled() && !inst_.is_viewport());
/* Only RG16F when only doing only reprojection or motion blur. */
eGPUTextureFormat vector_format = do_vector_render_pass ? GPU_RGBA16F : GPU_RG16F;
/* TODO(fclem): Make vector pass allocation optional if no TAA or motion blur is needed. */
- vector_tx.acquire(extent, vector_format, owner);
-
- normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format, owner);
- diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format, owner);
- diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format, owner);
- specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format, owner);
- specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format, owner);
- volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format, owner);
- emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format, owner);
- environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format, owner);
- shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format, owner);
- ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format, owner);
+ vector_tx.acquire(extent, vector_format);
+
+ normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format);
+ diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format);
+ diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format);
+ specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format);
+ specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format);
+ volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format);
+ emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format);
+ environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format);
+ shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format);
+ ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format);
const AOVsInfoData &aovs = inst_.film.aovs_info;
aov_color_tx.ensure_2d_array(
diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh
index 8c91fed2f0f..787f5604aa4 100644
--- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh
@@ -48,9 +48,8 @@ class RenderBuffers {
public:
RenderBuffers(Instance &inst) : inst_(inst){};
- void sync();
/* Acquires (also ensures) the render buffer before rendering to them. */
- void acquire(int2 extent, void *owner);
+ void acquire(int2 extent);
void release();
};
diff --git a/source/blender/draw/engines/eevee_next/eevee_sampling.cc b/source/blender/draw/engines/eevee_next/eevee_sampling.cc
index 1d320c75f16..76a0e98638b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sampling.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_sampling.cc
@@ -232,7 +232,7 @@ void Sampling::cdf_from_curvemapping(const CurveMapping &curve, Vector<float> &c
BLI_assert(cdf.size() > 1);
cdf[0] = 0.0f;
/* Actual CDF evaluation. */
- for (int u : cdf.index_range()) {
+ for (int u : IndexRange(cdf.size() - 1)) {
float x = (float)(u + 1) / (float)(cdf.size() - 1);
cdf[u + 1] = cdf[u] + BKE_curvemapping_evaluateF(&curve, 0, x);
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc
index 7db9692783a..782e73f6dd0 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -82,6 +82,14 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_film_frag";
case FILM_COMP:
return "eevee_film_comp";
+ case MOTION_BLUR_GATHER:
+ return "eevee_motion_blur_gather";
+ case MOTION_BLUR_TILE_DILATE:
+ return "eevee_motion_blur_tiles_dilate";
+ case MOTION_BLUR_TILE_FLATTEN_RENDER:
+ return "eevee_motion_blur_tiles_flatten_render";
+ case MOTION_BLUR_TILE_FLATTEN_VIEWPORT:
+ return "eevee_motion_blur_tiles_flatten_viewport";
/* To avoid compiler warning about missing case. */
case MAX_SHADER_TYPE:
return "";
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh
index 280aaab4e1c..8dc61fbae0b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh
@@ -29,6 +29,11 @@ enum eShaderType {
FILM_FRAG = 0,
FILM_COMP,
+ MOTION_BLUR_GATHER,
+ MOTION_BLUR_TILE_DILATE,
+ MOTION_BLUR_TILE_FLATTEN_RENDER,
+ MOTION_BLUR_TILE_FLATTEN_VIEWPORT,
+
MAX_SHADER_TYPE,
};
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
index 3c10f633740..70de4101bb9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -124,7 +124,7 @@ struct CameraData {
float clip_far;
eCameraType type;
- bool initialized;
+ bool1 initialized;
#ifdef __cplusplus
/* Small constructor to allow detecting new buffers. */
@@ -312,6 +312,40 @@ BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Motion Blur
+ * \{ */
+
+#define MOTION_BLUR_TILE_SIZE 32
+#define MOTION_BLUR_MAX_TILE 512 /* 16384 / MOTION_BLUR_TILE_SIZE */
+struct MotionBlurData {
+ /** As the name suggests. Used to avoid a division in the sampling. */
+ float2 target_size_inv;
+ /** Viewport motion scaling factor. Make blur relative to frame time not render time. */
+ float2 motion_scale;
+ /** Depth scaling factor. Avoid blurring background behind moving objects. */
+ float depth_scale;
+
+ float _pad0, _pad1, _pad2;
+};
+BLI_STATIC_ASSERT_ALIGN(MotionBlurData, 16)
+
+/* For some reasons some GLSL compilers do not like this struct.
+ * So we declare it as a uint array instead and do indexing ourselves. */
+#ifdef __cplusplus
+struct MotionBlurTileIndirection {
+ /**
+ * Stores indirection to the tile with the highest velocity covering each tile.
+ * This is stored using velocity in the MSB to be able to use atomicMax operations.
+ */
+ uint prev[MOTION_BLUR_MAX_TILE][MOTION_BLUR_MAX_TILE];
+ uint next[MOTION_BLUR_MAX_TILE][MOTION_BLUR_MAX_TILE];
+};
+BLI_STATIC_ASSERT_ALIGN(MotionBlurTileIndirection, 16)
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Ray-Tracing
* \{ */
@@ -375,6 +409,8 @@ using SamplingDataBuf = draw::StorageBuffer<SamplingData>;
using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>;
using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>;
using VelocityObjectBuf = draw::StorageArrayBuffer<float4x4, 16>;
+using MotionBlurDataBuf = draw::UniformBuffer<MotionBlurData>;
+using MotionBlurTileIndirectionBuf = draw::StorageBuffer<MotionBlurTileIndirection, true>;
} // namespace blender::eevee
#endif
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
index 048daf1b2db..36734f0c28c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
@@ -32,13 +32,16 @@ namespace blender::eevee {
void VelocityModule::init()
{
- if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR)) {
- /* No motion blur and the vector pass was requested. Do the step sync here. */
+ if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR) != 0) {
+ /* No motion blur and the vector pass was requested. Do the steps sync here. */
const Scene *scene = inst_.scene;
float initial_time = scene->r.cfra + scene->r.subframe;
step_sync(STEP_PREVIOUS, initial_time - 1.0f);
step_sync(STEP_NEXT, initial_time + 1.0f);
+
inst_.set_time(initial_time);
+ step_ = STEP_CURRENT;
+ /* Let the main sync loop handle the current step. */
}
}
@@ -64,10 +67,12 @@ void VelocityModule::step_camera_sync()
{
inst_.camera.sync();
*camera_steps[step_] = inst_.camera.data_get();
+ step_time[step_] = inst_.scene->r.cfra + inst_.scene->r.subframe;
/* Fix undefined camera steps when rendering is starting. */
if ((step_ == STEP_CURRENT) && (camera_steps[STEP_PREVIOUS]->initialized == false)) {
*camera_steps[STEP_PREVIOUS] = *static_cast<CameraData *>(camera_steps[step_]);
camera_steps[STEP_PREVIOUS]->initialized = true;
+ step_time[STEP_PREVIOUS] = step_time[step_];
}
}
@@ -212,6 +217,7 @@ void VelocityModule::step_swap()
SWAP(VelocityObjectBuf *, object_steps[step_a], object_steps[step_b]);
SWAP(VelocityGeometryBuf *, geometry_steps[step_a], geometry_steps[step_b]);
SWAP(CameraDataBuf *, camera_steps[step_a], camera_steps[step_b]);
+ SWAP(float, step_time[step_a], step_time[step_b]);
for (VelocityObjectData &vel : velocity_map.values()) {
vel.obj.ofs[step_a] = vel.obj.ofs[step_b];
@@ -238,10 +244,7 @@ void VelocityModule::step_swap()
void VelocityModule::begin_sync()
{
- if (inst_.is_viewport()) {
- /* Viewport always evaluate current step. */
- step_ = STEP_CURRENT;
- }
+ step_ = STEP_CURRENT;
step_camera_sync();
object_steps_usage[step_] = 0;
}
@@ -360,6 +363,21 @@ bool VelocityModule::camera_has_motion() const
*camera_steps[STEP_NEXT] != *camera_steps[STEP_CURRENT];
}
+bool VelocityModule::camera_changed_projection() const
+{
+ /* Only valid after sync. */
+ if (inst_.is_viewport()) {
+ return camera_steps[STEP_PREVIOUS]->type != camera_steps[STEP_CURRENT]->type;
+ }
+ /* Cannot happen in render mode since we set the type during the init phase. */
+ return false;
+}
+
+float VelocityModule::step_time_delta_get(eVelocityStep start, eVelocityStep end) const
+{
+ return step_time[end] - step_time[start];
+}
+
/** \} */
} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
index 826cd631a96..01b8a5fb8c1 100644
--- a/source/blender/draw/engines/eevee_next/eevee_velocity.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
@@ -56,6 +56,8 @@ class VelocityModule {
int3 object_steps_usage = int3(0);
/** Buffer of all #VelocityIndex used in this frame. Indexed by draw manager resource id. */
VelocityIndexBuf indirection_buf;
+ /** Frame time at which each steps were evaluated. */
+ float3 step_time;
/**
* Copies of camera data. One for previous and one for next time step.
@@ -78,7 +80,6 @@ class VelocityModule {
}
for (CameraDataBuf *&step_buf : camera_steps) {
step_buf = new CameraDataBuf();
- /* */
}
};
@@ -112,6 +113,10 @@ class VelocityModule {
void bind_resources(DRWShadingGroup *grp);
bool camera_has_motion() const;
+ bool camera_changed_projection() const;
+
+ /* Returns frame time difference between two steps. */
+ float step_time_delta_get(eVelocityStep start, eVelocityStep end) const;
private:
bool object_has_velocity(const Object *ob);
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc
index 55741bee4df..c7434a662a2 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_view.cc
@@ -79,14 +79,11 @@ void ShadingView::sync()
render_view_ = DRW_view_create_sub(main_view_, viewmat_p, winmat_p);
// dof_.sync(winmat_p, extent_);
- // mb_.sync(extent_);
// rt_buffer_opaque_.sync(extent_);
// rt_buffer_refract_.sync(extent_);
// inst_.hiz_back.view_sync(extent_);
// inst_.hiz_front.view_sync(extent_);
// inst_.gbuffer.view_sync(extent_);
-
- postfx_tx_.sync();
}
void ShadingView::render()
@@ -96,12 +93,8 @@ void ShadingView::render()
}
/* Query temp textures and create frame-buffers. */
- /* HACK: View name should be unique and static.
- * With this, we can reuse the same texture across views. */
- DrawEngineType *owner = (DrawEngineType *)name_;
-
RenderBuffers &rbufs = inst_.render_buffers;
- rbufs.acquire(extent_, owner);
+ rbufs.acquire(extent_);
combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx),
GPU_ATTACHMENT_TEXTURE(rbufs.combined_tx));
prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx),
@@ -138,9 +131,9 @@ void ShadingView::render()
// inst_.lights.debug_draw(view_fb_);
// inst_.shadows.debug_draw(view_fb_);
- // GPUTexture *final_radiance_tx = render_post(combined_tx_);
+ GPUTexture *combined_final_tx = render_postfx(rbufs.combined_tx);
- inst_.film.accumulate(sub_view_);
+ inst_.film.accumulate(sub_view_, combined_final_tx);
rbufs.release();
postfx_tx_.release();
@@ -148,23 +141,19 @@ void ShadingView::render()
DRW_stats_group_end();
}
-GPUTexture *ShadingView::render_post(GPUTexture *input_tx)
+GPUTexture *ShadingView::render_postfx(GPUTexture *input_tx)
{
-#if 0
- if (!dof_.postfx_enabled() && !mb_.enabled()) {
+ if (/*!dof_.postfx_enabled() &&*/ !inst_.motion_blur.postfx_enabled()) {
return input_tx;
}
- /* HACK: View name should be unique and static.
- * With this, we can reuse the same texture across views. */
- postfx_tx_.acquire(extent_, GPU_RGBA16F, (void *)name_);
+ postfx_tx_.acquire(extent_, GPU_RGBA16F);
- GPUTexture *velocity_tx = velocity_.view_vectors_get();
GPUTexture *output_tx = postfx_tx_;
/* Swapping is done internally. Actual output is set to the next input. */
- dof_.render(depth_tx_, &input_tx, &output_tx);
- mb_.render(depth_tx_, velocity_tx, &input_tx, &output_tx);
-#endif
+ // dof_.render(depth_tx_, &input_tx, &output_tx);
+ inst_.motion_blur.render(&input_tx, &output_tx);
+
return input_tx;
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index c6faebdd0e5..ac8decc7632 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -78,7 +78,7 @@ class ShadingView {
void render();
- GPUTexture *render_post(GPUTexture *input_tx);
+ GPUTexture *render_postfx(GPUTexture *input_tx);
private:
void update_view();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl
index b286836e8df..135507d956c 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl
@@ -636,6 +636,8 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
vec4 normal = texelFetch(normal_tx, film_sample.texel, 0);
float depth = texelFetch(depth_tx, film_sample.texel, 0).x;
vec4 vector = velocity_resolve(vector_tx, film_sample.texel, depth);
+ /* Transform to pixel space. */
+ vector *= vec4(film_buf.render_extent, -film_buf.render_extent);
film_store_depth(texel_film, depth, out_depth);
film_store_data(texel_film, film_buf.normal_id, normal, out_color);
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl
new file mode 100644
index 00000000000..c59b7d7f4df
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl
@@ -0,0 +1,116 @@
+
+/**
+ * Dilate motion vector tiles until we covered maximum velocity.
+ * Outputs the largest intersecting motion vector in the neighboorhod.
+ *
+ */
+
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_motion_blur_lib.glsl)
+
+#define DEBUG_BYPASS_DILATION 0
+
+struct MotionRect {
+ ivec2 bottom_left;
+ ivec2 extent;
+};
+
+MotionRect compute_motion_rect(ivec2 tile, vec2 motion)
+{
+#if DEBUG_BYPASS_DILATION
+ return MotionRect(tile, ivec2(1));
+#endif
+ /* Ceil to number of tile touched.*/
+ ivec2 point1 = tile + ivec2(sign(motion) * ceil(abs(motion) / float(MOTION_BLUR_TILE_SIZE)));
+ ivec2 point2 = tile;
+
+ ivec2 max_point = max(point1, point2);
+ ivec2 min_point = min(point1, point2);
+ /* Clamp to bounds. */
+ max_point = min(max_point, imageSize(in_tiles_img) - 1);
+ min_point = max(min_point, ivec2(0));
+
+ MotionRect rect;
+ rect.bottom_left = min_point;
+ rect.extent = 1 + max_point - min_point;
+ return rect;
+}
+
+struct MotionLine {
+ /** Origin of the line. */
+ vec2 origin;
+ /** Normal to the line direction. */
+ vec2 normal;
+};
+
+MotionLine compute_motion_line(ivec2 tile, vec2 motion)
+{
+ vec2 dir = safe_normalize(motion);
+
+ MotionLine line;
+ line.origin = vec2(tile);
+ /* Rotate 90° Counter-Clockwise. */
+ line.normal = vec2(-dir.y, dir.x);
+ return line;
+}
+
+bool is_inside_motion_line(ivec2 tile, MotionLine motion_line)
+{
+#if DEBUG_BYPASS_DILATION
+ return true;
+#endif
+ /* NOTE: Everything in is tile unit. */
+ float dist = point_line_projection_dist(vec2(tile), motion_line.origin, motion_line.normal);
+ /* In order to be conservative and for simplicity, we use the tiles bounding circles.
+ * Consider that both the tile and the line have bouding radius of M_SQRT1_2. */
+ return abs(dist) < M_SQRT2;
+}
+
+void main()
+{
+ ivec2 src_tile = ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThanEqual(src_tile, imageSize(in_tiles_img)))) {
+ return;
+ }
+
+ vec4 max_motion = imageLoad(in_tiles_img, src_tile);
+
+ MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, src_tile);
+ MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile);
+ if (true) {
+ /* Rectangular area (in tiles) where the motion vector spreads. */
+ MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy);
+ MotionLine motion_line = compute_motion_line(src_tile, max_motion.xy);
+ /* Do a conservative rasterization of the line of the motion vector line. */
+ for (int x = 0; x < motion_rect.extent.x; x++) {
+ for (int y = 0; y < motion_rect.extent.y; y++) {
+ ivec2 tile = motion_rect.bottom_left + ivec2(x, y);
+ if (is_inside_motion_line(tile, motion_line)) {
+ motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv);
+ /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in
+ * the motion next so that weighting in gather pass is better. */
+ motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt);
+ }
+ }
+ }
+ }
+
+ if (true) {
+ MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile);
+ /* Rectangular area (in tiles) where the motion vector spreads. */
+ MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw);
+ MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw);
+ /* Do a conservative rasterization of the line of the motion vector line. */
+ for (int x = 0; x < motion_rect.extent.x; x++) {
+ for (int y = 0; y < motion_rect.extent.y; y++) {
+ ivec2 tile = motion_rect.bottom_left + ivec2(x, y);
+ if (is_inside_motion_line(tile, motion_line)) {
+ motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt);
+ /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in
+ * the motion next so that weighting in gather pass is better. */
+ motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl
new file mode 100644
index 00000000000..cbbeea25d20
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl
@@ -0,0 +1,103 @@
+
+/**
+ * Shaders that down-sample velocity buffer into squared tile of MB_TILE_DIVISOR pixels wide.
+ * Outputs the largest motion vector in the tile area.
+ * Also perform velocity resolve to speedup the convolution pass.
+ *
+ * Based on:
+ * A Fast and Stable Feature-Aware Motion Blur Filter
+ * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai
+ *
+ * Adapted from G3D Innovation Engine implementation.
+ */
+
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
+
+shared uint payload_prev;
+shared uint payload_next;
+shared vec2 max_motion_prev;
+shared vec2 max_motion_next;
+
+/* Store velocity magnitude in the MSB and thread id in the LSB. */
+uint pack_payload(vec2 motion, uvec2 thread_id)
+{
+ /* NOTE: We clamp max velocity to 16k pixels. */
+ return (min(uint(ceil(length(motion))), 0xFFFFu) << 16u) | (thread_id.y << 8) | thread_id.x;
+}
+
+/* Return thread index from the payload. */
+uvec2 unpack_payload(uint payload)
+{
+ return uvec2(payload & 0xFFu, (payload >> 8) & 0xFFu);
+}
+
+void main()
+{
+ if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) {
+ payload_prev = 0u;
+ payload_next = 0u;
+ }
+ barrier();
+
+ uint local_payload_prev = 0u;
+ uint local_payload_next = 0u;
+ vec2 local_max_motion_prev;
+ vec2 local_max_motion_next;
+
+ ivec2 texel = min(ivec2(gl_GlobalInvocationID.xy), imageSize(velocity_img) - 1);
+
+ vec2 render_size = vec2(imageSize(velocity_img).xy);
+ vec2 uv = (vec2(texel) + 0.5) / render_size;
+ float depth = texelFetch(depth_tx, texel, 0).r;
+ vec4 motion = velocity_resolve(imageLoad(velocity_img, texel), uv, depth);
+#ifdef FLATTEN_VIEWPORT
+ /* imageLoad does not perform the swizzling like sampler does. Do it manually. */
+ motion = motion.xyxy;
+#endif
+
+ /* Store resolved velocity to speedup the gather pass. Out of bounds writes are ignored.
+ * Unfortunately, we cannot convert to pixel space here since it is also used by TAA and the
+ * motion blur needs to remain optional. */
+ imageStore(velocity_img, ivec2(gl_GlobalInvocationID.xy), velocity_pack(motion));
+ /* Clip velocity to viewport bounds (in NDC space). */
+ vec2 line_clip;
+ line_clip.x = line_unit_square_intersect_dist_safe(uv * 2.0 - 1.0, motion.xy * 2.0);
+ line_clip.y = line_unit_square_intersect_dist_safe(uv * 2.0 - 1.0, -motion.zw * 2.0);
+ motion *= min(line_clip, vec2(1.0)).xxyy;
+ /* Convert to pixel space. Note this is only for velocity tiles. */
+ motion *= render_size.xyxy;
+ /* Rescale to shutter relative motion for viewport. */
+ motion *= motion_blur_buf.motion_scale.xxyy;
+
+ uint sample_payload_prev = pack_payload(motion.xy, gl_LocalInvocationID.xy);
+ if (local_payload_prev < sample_payload_prev) {
+ local_payload_prev = sample_payload_prev;
+ local_max_motion_prev = motion.xy;
+ }
+
+ uint sample_payload_next = pack_payload(motion.zw, gl_LocalInvocationID.xy);
+ if (local_payload_next < sample_payload_next) {
+ local_payload_next = sample_payload_next;
+ local_max_motion_next = motion.zw;
+ }
+
+ /* Compare the local payload with the other threads. */
+ atomicMax(payload_prev, local_payload_prev);
+ atomicMax(payload_next, local_payload_next);
+ barrier();
+
+ /* Need to broadcast the result to another thread in order to issue a unique write. */
+ if (all(equal(unpack_payload(payload_prev), gl_LocalInvocationID.xy))) {
+ max_motion_prev = local_max_motion_prev;
+ }
+ if (all(equal(unpack_payload(payload_next), gl_LocalInvocationID.xy))) {
+ max_motion_next = local_max_motion_next;
+ }
+ barrier();
+
+ if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) {
+ ivec2 tile_co = ivec2(gl_WorkGroupID.xy);
+ imageStore(out_tiles_img, tile_co, vec4(max_motion_prev, max_motion_next));
+ }
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl
new file mode 100644
index 00000000000..a7329f77181
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl
@@ -0,0 +1,221 @@
+
+/**
+ * Perform two gather blur in the 2 motion blur directions
+ * Based on:
+ * A Fast and Stable Feature-Aware Motion Blur Filter
+ * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai
+ *
+ * With modification from the presentation:
+ * Next Generation Post Processing in Call of Duty Advanced Warfare
+ * by Jorge Jimenez
+ */
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_motion_blur_lib.glsl)
+
+const int gather_sample_count = 8;
+
+/* Converts uv velocity into pixel space. Assumes velocity_tx is the same resolution as the
+ * target post-fx framebuffer. */
+vec4 motion_blur_sample_velocity(sampler2D velocity_tx, vec2 uv)
+{
+ /* We can load velocity without velocity_resolve() since we resovled during the flatten pass. */
+ vec4 velocity = velocity_unpack(texture(velocity_tx, uv));
+ return velocity * vec2(textureSize(velocity_tx, 0)).xyxy * motion_blur_buf.motion_scale.xxyy;
+}
+
+vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length)
+{
+ return saturate(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0);
+}
+
+vec2 depth_compare(float center_depth, float sample_depth)
+{
+ vec2 depth_scale = vec2(-motion_blur_buf.depth_scale, motion_blur_buf.depth_scale);
+ return saturate(0.5 + depth_scale * (sample_depth - center_depth));
+}
+
+/* Kill contribution if not going the same direction. */
+float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length)
+{
+ if (sample_motion_length < 0.5) {
+ return 1.0;
+ }
+ return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0;
+}
+
+/* Return background (x) and foreground (y) weights. */
+vec2 sample_weights(float center_depth,
+ float sample_depth,
+ float center_motion_length,
+ float sample_motion_length,
+ float offset_length)
+{
+ /* Classify foreground/background. */
+ vec2 depth_weight = depth_compare(center_depth, sample_depth);
+ /* Weight if sample is overlapping or under the center pixel. */
+ vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length);
+ return depth_weight * spread_weight;
+}
+
+struct Accumulator {
+ vec4 fg;
+ vec4 bg;
+ /** x: Background, y: Foreground, z: dir. */
+ vec3 weight;
+};
+
+void gather_sample(vec2 screen_uv,
+ float center_depth,
+ float center_motion_len,
+ vec2 offset,
+ float offset_len,
+ const bool next,
+ inout Accumulator accum)
+{
+ vec2 sample_uv = screen_uv - offset * motion_blur_buf.target_size_inv;
+ vec4 sample_vectors = motion_blur_sample_velocity(velocity_tx, sample_uv);
+ vec2 sample_motion = (next) ? sample_vectors.zw : sample_vectors.xy;
+ float sample_motion_len = length(sample_motion);
+ float sample_depth = texture(depth_tx, sample_uv).r;
+ vec4 sample_color = textureLod(in_color_tx, sample_uv, 0.0);
+
+ sample_depth = get_view_z_from_depth(sample_depth);
+
+ vec3 weights;
+ weights.xy = sample_weights(
+ center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len);
+ weights.z = dir_compare(offset, sample_motion, sample_motion_len);
+ weights.xy *= weights.z;
+
+ accum.fg += sample_color * weights.y;
+ accum.bg += sample_color * weights.x;
+ accum.weight += weights;
+}
+
+void gather_blur(vec2 screen_uv,
+ vec2 center_motion,
+ float center_depth,
+ vec2 max_motion,
+ float ofs,
+ const bool next,
+ inout Accumulator accum)
+{
+ float center_motion_len = length(center_motion);
+ float max_motion_len = length(max_motion);
+
+ /* Tile boundaries randomization can fetch a tile where there is less motion than this pixel.
+ * Fix this by overriding the max_motion. */
+ if (max_motion_len < center_motion_len) {
+ max_motion_len = center_motion_len;
+ max_motion = center_motion;
+ }
+
+ if (max_motion_len < 0.5) {
+ return;
+ }
+
+ int i;
+ float t, inc = 1.0 / float(gather_sample_count);
+ for (i = 0, t = ofs * inc; i < gather_sample_count; i++, t += inc) {
+ gather_sample(screen_uv,
+ center_depth,
+ center_motion_len,
+ max_motion * t,
+ max_motion_len * t,
+ next,
+ accum);
+ }
+
+ if (center_motion_len < 0.5) {
+ return;
+ }
+
+ for (i = 0, t = ofs * inc; i < gather_sample_count; i++, t += inc) {
+ /* Also sample in center motion direction.
+ * Allow recovering motion where there is conflicting
+ * motion between foreground and background. */
+ gather_sample(screen_uv,
+ center_depth,
+ center_motion_len,
+ center_motion * t,
+ center_motion_len * t,
+ next,
+ accum);
+ }
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+ vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(depth_tx, 0).xy);
+
+ if (!in_texture_range(texel, depth_tx)) {
+ return;
+ }
+
+ /* Data of the center pixel of the gather (target). */
+ float center_depth = get_view_z_from_depth(texelFetch(depth_tx, texel, 0).r);
+ vec4 center_motion = motion_blur_sample_velocity(velocity_tx, uv);
+
+ vec4 center_color = textureLod(in_color_tx, uv, 0.0);
+
+ float noise_offset = sampling_rng_1D_get(SAMPLING_TIME);
+ /** TODO(fclem) Blue noise. */
+ vec2 rand = vec2(interlieved_gradient_noise(vec2(gl_GlobalInvocationID.xy), 0, noise_offset),
+ interlieved_gradient_noise(vec2(gl_GlobalInvocationID.xy), 1, noise_offset));
+
+ /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile.
+ * Note this randomize only in one direction but in practice it's enough. */
+ rand.x = rand.x * 2.0 - 1.0;
+ ivec2 tile = (texel + ivec2(rand.x * float(MOTION_BLUR_TILE_SIZE) * 0.25)) /
+ MOTION_BLUR_TILE_SIZE;
+ tile = clamp(tile, ivec2(0), imageSize(in_tiles_img) - 1);
+ /* NOTE: Tile velocity is already in pixel space and with correct zw sign. */
+ vec4 max_motion;
+ /* Load dilation result from the indirection table. */
+ ivec2 tile_prev;
+ motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, tile, tile_prev);
+ max_motion.xy = imageLoad(in_tiles_img, tile_prev).xy;
+ ivec2 tile_next;
+ motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, tile, tile_next);
+ max_motion.zw = imageLoad(in_tiles_img, tile_next).zw;
+
+ Accumulator accum;
+ accum.weight = vec3(0.0, 0.0, 1.0);
+ accum.bg = vec4(0.0);
+ accum.fg = vec4(0.0);
+ /* First linear gather. time = [T - delta, T] */
+ gather_blur(uv, center_motion.xy, center_depth, max_motion.xy, rand.y, false, accum);
+ /* Second linear gather. time = [T, T + delta] */
+ gather_blur(uv, center_motion.zw, center_depth, max_motion.zw, rand.y, true, accum);
+
+#if 1 /* Own addition. Not present in reference implementation. */
+ /* Avoid division by 0.0. */
+ float w = 1.0 / (50.0 * float(gather_sample_count) * 4.0);
+ accum.bg += center_color * w;
+ accum.weight.x += w;
+ /* NOTE: In Jimenez's presentation, they used center sample.
+ * We use background color as it contains more information for foreground
+ * elements that have not enough weights.
+ * Yield better blur in complex motion. */
+ center_color = accum.bg / accum.weight.x;
+#endif
+ /* Merge background. */
+ accum.fg += accum.bg;
+ accum.weight.y += accum.weight.x;
+ /* Balance accumulation for failed samples.
+ * We replace the missing foreground by the background. */
+ float blend_fac = saturate(1.0 - accum.weight.y / accum.weight.z);
+ vec4 out_color = (accum.fg / accum.weight.z) + center_color * blend_fac;
+
+#if 0 /* For debugging. */
+ out_color.rgb = out_color.ggg;
+ out_color.rg += max_motion.xy;
+#endif
+
+ imageStore(out_color_img, texel, out_color);
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl
new file mode 100644
index 00000000000..436fd01795a
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl
@@ -0,0 +1,48 @@
+
+
+/* -------------------------------------------------------------------- */
+/** \name Tile indirection packing
+ * \{ */
+
+#define MotionPayload uint
+
+/* Store velocity magnitude in the MSB to be able to use it with atomicMax operations. */
+MotionPayload motion_blur_tile_indirection_pack_payload(vec2 motion, uvec2 payload)
+{
+ /* NOTE: Clamp to 16383 pixel velocity. After that, it is tile position that determine the tile
+ * to dilate over. */
+ uint velocity = min(uint(ceil(length(motion))), 0x3FFFu);
+ /* Designed for 512x512 tiles max. */
+ return (velocity << 18u) | ((payload.x & 0x1FFu) << 9u) | (payload.y & 0x1FFu);
+}
+
+/* Return thread index. */
+ivec2 motion_blur_tile_indirection_pack_payload(uint data)
+{
+ return ivec2((data >> 9u) & 0x1FFu, data & 0x1FFu);
+}
+
+uint motion_blur_tile_indirection_index(uint motion_step, uvec2 tile)
+{
+ uint index = tile.x;
+ index += tile.y * MOTION_BLUR_MAX_TILE;
+ index += motion_step * MOTION_BLUR_MAX_TILE * MOTION_BLUR_MAX_TILE;
+ return index;
+}
+
+#define MOTION_PREV 0u
+#define MOTION_NEXT 1u
+
+#define motion_blur_tile_indirection_store(table_, step_, tile, payload_) \
+ if (true) { \
+ uint index = motion_blur_tile_indirection_index(step_, tile); \
+ atomicMax(table_[index], payload_); \
+ }
+
+#define motion_blur_tile_indirection_load(table_, step_, tile_, result_) \
+ if (true) { \
+ uint index = motion_blur_tile_indirection_index(step_, tile_); \
+ result_ = motion_blur_tile_indirection_pack_payload(table_[index]); \
+ }
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl
new file mode 100644
index 00000000000..0c7bbaa9dc2
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl
@@ -0,0 +1,104 @@
+
+/**
+ * Sampling data accessors and random number generators.
+ * Also contains some sample mapping functions.
+ **/
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling data.
+ *
+ * Return a random values from Low Discrepency Sequence in [0..1) range.
+ * This value is uniform (constant) for the whole scene sample.
+ * You might want to couple it with a noise function.
+ * \{ */
+
+#ifdef EEVEE_SAMPLING_DATA
+
+float sampling_rng_1D_get(const eSamplingDimension dimension)
+{
+ return sampling_buf.dimensions[dimension];
+}
+
+vec2 sampling_rng_2D_get(const eSamplingDimension dimension)
+{
+ return vec2(sampling_buf.dimensions[dimension], sampling_buf.dimensions[dimension + 1u]);
+}
+
+vec3 sampling_rng_3D_get(const eSamplingDimension dimension)
+{
+ return vec3(sampling_buf.dimensions[dimension],
+ sampling_buf.dimensions[dimension + 1u],
+ sampling_buf.dimensions[dimension + 2u]);
+}
+
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Random Number Generators.
+ * \{ */
+
+/* Interlieved gradient noise by Jorge Jimenez
+ * http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+ * Seeding found by Epic Game. */
+float interlieved_gradient_noise(vec2 pixel, float seed, float offset)
+{
+ pixel += seed * (vec2(47, 17) * 0.695);
+ return fract(offset + 52.9829189 * fract(0.06711056 * pixel.x + 0.00583715 * pixel.y));
+}
+
+/* From: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
+float van_der_corput_radical_inverse(uint bits)
+{
+#if 0 /* Reference */
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+#else
+ bits = bitfieldReverse(bits);
+#endif
+ /* Same as dividing by 0x100000000. */
+ return float(bits) * 2.3283064365386963e-10;
+}
+
+vec2 hammersley_2d(float i, float sample_count)
+{
+ vec2 rand;
+ rand.x = i / sample_count;
+ rand.y = van_der_corput_radical_inverse(uint(i));
+ return rand;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Distribution mapping.
+ *
+ * Functions mapping input random numbers to sampling shapes (i.e: hemisphere).
+ * \{ */
+
+/* Given 2 random number in [0..1] range, return a random unit disk sample. */
+vec2 sample_disk(vec2 noise)
+{
+ float angle = noise.x * M_2PI;
+ return vec2(cos(angle), sin(angle)) * sqrt(noise.y);
+}
+
+/* This transform a 2d random sample (in [0..1] range) to a sample located on a cylinder of the
+ * same range. This is because the sampling functions expect such a random sample which is
+ * normally precomputed. */
+vec3 sample_cylinder(vec2 rand)
+{
+ float theta = rand.x;
+ float phi = (rand.y - 0.5) * M_2PI;
+ float cos_phi = cos(phi);
+ float sin_phi = sqrt(1.0 - sqr(cos_phi)) * sign(phi);
+ return vec3(theta, cos_phi, sin_phi);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
index 34ea288852a..bd32215ddc2 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
@@ -73,7 +73,7 @@ void main()
nodetree_surface();
- // float noise_offset = sampling_rng_1D_get(sampling_buf, SAMPLING_TRANSPARENCY);
+ // float noise_offset = sampling_rng_1D_get(SAMPLING_TRANSPARENCY);
float noise_offset = 0.5;
float random_threshold = hashed_alpha_threshold(1.0, noise_offset, g_data.P);
@@ -84,7 +84,7 @@ void main()
#endif
#ifdef MAT_VELOCITY
- out_velocity = velocity_surface(interp.P + motion.prev, interp.P, interp.P - motion.next);
+ out_velocity = velocity_surface(interp.P + motion.prev, interp.P, interp.P + motion.next);
out_velocity = velocity_pack(out_velocity);
#endif
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
index c21456b7a5c..c0a5b976810 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
@@ -2,8 +2,6 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_camera_lib.glsl)
-#ifdef VELOCITY_CAMERA
-
vec4 velocity_pack(vec4 data)
{
return data * 0.01;
@@ -14,6 +12,8 @@ vec4 velocity_unpack(vec4 data)
return data * 100.0;
}
+#ifdef VELOCITY_CAMERA
+
/**
* Given a triple of position, compute the previous and next motion vectors.
* Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy).
@@ -24,7 +24,15 @@ vec4 velocity_surface(vec3 P_prv, vec3 P, vec3 P_nxt)
vec2 prev_uv = project_point(camera_prev.persmat, P_prv).xy;
vec2 curr_uv = project_point(camera_curr.persmat, P).xy;
vec2 next_uv = project_point(camera_next.persmat, P_nxt).xy;
-
+ /* Fix issue with perspective division. */
+ if (any(isnan(prev_uv))) {
+ prev_uv = curr_uv;
+ }
+ if (any(isnan(next_uv))) {
+ next_uv = curr_uv;
+ }
+ /* NOTE: We output both vectors in the same direction so we can reuse the same vector
+ * with rgrg swizzle in viewport. */
vec4 motion = vec4(prev_uv - curr_uv, curr_uv - next_uv);
/* Convert NDC velocity to UV velocity */
motion *= 0.5;
@@ -45,7 +53,8 @@ vec4 velocity_background(vec3 vV)
vec2 prev_uv = project_point(camera_prev.winmat, V).xy;
vec2 curr_uv = project_point(camera_curr.winmat, V).xy;
vec2 next_uv = project_point(camera_next.winmat, V).xy;
-
+ /* NOTE: We output both vectors in the same direction so we can reuse the same vector
+ * with rgrg swizzle in viewport. */
vec4 motion = vec4(prev_uv - curr_uv, curr_uv - next_uv);
/* Convert NDC velocity to UV velocity */
motion *= 0.5;
@@ -53,15 +62,8 @@ vec4 velocity_background(vec3 vV)
return motion;
}
-/**
- * Load and resolve correct velocity as some pixels might still not have correct
- * motion data for performance reasons.
- */
-vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth)
+vec4 velocity_resolve(vec4 vector, vec2 uv, float depth)
{
- vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(vector_tx, 0).xy);
- vec4 vector = texelFetch(vector_tx, texel, 0);
-
if (vector.x == VELOCITY_INVALID) {
bool is_background = (depth == 1.0);
if (is_background) {
@@ -78,6 +80,18 @@ vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth)
return velocity_unpack(vector);
}
+/**
+ * Load and resolve correct velocity as some pixels might still not have correct
+ * motion data for performance reasons.
+ * Returns motion vector in render UV space.
+ */
+vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth)
+{
+ vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(vector_tx, 0).xy);
+ vec4 vector = texelFetch(vector_tx, texel, 0);
+ return velocity_resolve(vector, uv, depth);
+}
+
#endif
#ifdef MAT_VELOCITY
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index 2368061402c..db3cfc4a7a2 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -12,8 +12,9 @@ GPU_SHADER_CREATE_INFO(eevee_shared)
.typedef_source("eevee_shader_shared.hh");
GPU_SHADER_CREATE_INFO(eevee_sampling_data)
+ .define("EEVEE_SAMPLING_DATA")
.additional_info("eevee_shared")
- .uniform_buf(14, "SamplingData", "sampling_buf");
+ .storage_buf(14, Qualifier::READ, "SamplingData", "sampling_buf");
/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh
new file mode 100644
index 00000000000..b01d1521c5e
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh
@@ -0,0 +1,44 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten)
+ .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE)
+ .additional_info("eevee_shared", "draw_view", "eevee_velocity_camera")
+ .uniform_buf(4, "MotionBlurData", "motion_blur_buf")
+ .sampler(0, ImageType::DEPTH_2D, "depth_tx")
+ .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_img")
+ .compute_source("eevee_motion_blur_flatten_comp.glsl");
+
+GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten_viewport)
+ .do_static_compilation(true)
+ .define("FLATTEN_VIEWPORT")
+ .image(0, GPU_RG16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_img")
+ .additional_info("eevee_motion_blur_tiles_flatten");
+
+GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten_render)
+ .do_static_compilation(true)
+ .image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_img")
+ .additional_info("eevee_motion_blur_tiles_flatten");
+
+GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_dilate)
+ .do_static_compilation(true)
+ .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE)
+ .additional_info("eevee_shared")
+ /* NOTE: See MotionBlurTileIndirection. */
+ .storage_buf(0, Qualifier::READ_WRITE, "uint", "tile_indirection_buf[]")
+ .image(1, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_img")
+ .compute_source("eevee_motion_blur_dilate_comp.glsl");
+
+GPU_SHADER_CREATE_INFO(eevee_motion_blur_gather)
+ .do_static_compilation(true)
+ .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE)
+ .additional_info("eevee_shared", "draw_view", "eevee_sampling_data")
+ .uniform_buf(4, "MotionBlurData", "motion_blur_buf")
+ .sampler(0, ImageType::DEPTH_2D, "depth_tx")
+ .sampler(1, ImageType::FLOAT_2D, "velocity_tx")
+ .sampler(2, ImageType::FLOAT_2D, "in_color_tx")
+ /* NOTE: See MotionBlurTileIndirection. */
+ .storage_buf(0, Qualifier::READ, "uint", "tile_indirection_buf[]")
+ .image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_img")
+ .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img")
+ .compute_source("eevee_motion_blur_gather_comp.glsl");
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index 8e61c25be71..954d8c49f4c 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -57,6 +57,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_manager.h"
#include "draw_texture_pool.h"
#include "BLI_math_vec_types.hh"
@@ -772,50 +773,26 @@ class Texture : NonCopyable {
};
class TextureFromPool : public Texture, NonMovable {
- private:
- GPUTexture *tx_tmp_saved_ = nullptr;
-
public:
TextureFromPool(const char *name = "gpu::Texture") : Texture(name){};
- /* Always use `release()` after rendering and `sync()` in sync phase. */
- void acquire(int2 extent, eGPUTextureFormat format, void *owner_)
+ /* Always use `release()` after rendering. */
+ void acquire(int2 extent, eGPUTextureFormat format)
{
BLI_assert(this->tx_ == nullptr);
- if (this->tx_ != nullptr) {
- return;
- }
- if (tx_tmp_saved_ != nullptr) {
- if (GPU_texture_width(tx_tmp_saved_) != extent.x ||
- GPU_texture_height(tx_tmp_saved_) != extent.y ||
- GPU_texture_format(tx_tmp_saved_) != format) {
- this->tx_tmp_saved_ = nullptr;
- }
- else {
- this->tx_ = tx_tmp_saved_;
- return;
- }
- }
- DrawEngineType *owner = (DrawEngineType *)owner_;
- this->tx_ = DRW_texture_pool_query_2d(UNPACK2(extent), format, owner);
+
+ this->tx_ = DRW_texture_pool_texture_acquire(
+ DST.vmempool->texture_pool, UNPACK2(extent), format);
}
void release(void)
{
/* Allows multiple release. */
- if (this->tx_ != nullptr) {
- tx_tmp_saved_ = this->tx_;
- this->tx_ = nullptr;
+ if (this->tx_ == nullptr) {
+ return;
}
- }
-
- /**
- * Clears any reference. Workaround for pool texture not being able to release on demand.
- * Needs to be called at during the sync phase.
- */
- void sync(void)
- {
- tx_tmp_saved_ = nullptr;
+ DRW_texture_pool_texture_release(DST.vmempool->texture_pool, this->tx_);
+ this->tx_ = nullptr;
}
/** Remove methods that are forbidden with this type of textures. */
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 0e4e67f3320..88cc71fa0dd 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -27,6 +27,7 @@
#include "BKE_duplilist.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "BLI_bitmap.h"
#include "BLI_memblock.h"
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index e8944442607..266db22a84f 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef GPU_SHADER
+# pragma once
+
# include "GPU_shader.h"
# include "GPU_shader_shared_utils.h"
diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h
index 1c30ea88552..7396b55d53a 100644
--- a/source/blender/draw/intern/draw_texture_pool.h
+++ b/source/blender/draw/intern/draw_texture_pool.h
@@ -26,6 +26,7 @@ void DRW_texture_pool_free(DRWTexturePool *pool);
/**
* Try to find a texture corresponding to params into the texture pool.
* If no texture was found, create one and add it to the pool.
+ * DEPRECATED: Use DRW_texture_pool_texture_acquire instead and do it just before rendering.
*/
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user);
diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
index ae82277d9a6..cb2da9d35bf 100644
--- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
@@ -10,6 +10,11 @@ float point_plane_projection_dist(vec3 line_origin, vec3 plane_origin, vec3 plan
return dot(plane_normal, plane_origin - line_origin);
}
+float point_line_projection_dist(vec2 point, vec2 line_origin, vec2 line_normal)
+{
+ return dot(line_normal, line_origin - point);
+}
+
float line_plane_intersect_dist(vec3 line_origin,
vec3 line_direction,
vec3 plane_origin,
@@ -104,6 +109,25 @@ float line_unit_box_intersect_dist_safe(vec3 line_origin, vec3 line_direction)
}
/**
+ * Same as line_unit_box_intersect_dist but for 2D case.
+ */
+float line_unit_square_intersect_dist(vec2 line_origin, vec2 line_direction)
+{
+ vec2 first_plane = (vec2(1.0) - line_origin) / line_direction;
+ vec2 second_plane = (vec2(-1.0) - line_origin) / line_direction;
+ vec2 farthest_plane = max(first_plane, second_plane);
+
+ return min_v2(farthest_plane);
+}
+
+float line_unit_square_intersect_dist_safe(vec2 line_origin, vec2 line_direction)
+{
+ vec2 safe_line_direction = max(vec2(1e-8), abs(line_direction)) *
+ select(vec2(1.0), -vec2(1.0), lessThan(line_direction, vec2(0.0)));
+ return line_unit_square_intersect_dist(line_origin, safe_line_direction);
+}
+
+/**
* Returns clipping distance (intersection with the nearest plane) with the given axis-aligned
* bound box along \a line_direction.
* Safe even if \a line_direction is degenerate.
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 729e8533d50..f665ec27b07 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -43,6 +43,7 @@
#include "DNA_world_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "BKE_anim_data.h"
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index ff53ad42e84..22c14983569 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -32,6 +32,7 @@
#include "DEG_depsgraph.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "SEQ_sequencer.h"
#include "SEQ_utils.h"
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index d9dcbf1d57e..e352b4e26fe 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -35,6 +35,7 @@
#include "ED_keyframes_keylist.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index f01b3522547..93d83ff5f8e 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -22,6 +22,7 @@
#include "DNA_anim_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "ED_anim_api.h"
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index effedd4307d..63794caf5a7 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -39,6 +39,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "anim_intern.h"
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 7723c221a40..40f0ac59b01 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -29,6 +29,7 @@
#include "RNA_access.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 9084b9bb214..12f83343299 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "anim_intern.h"
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 97b81277008..967a324ef95 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -39,6 +39,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "anim_intern.h"
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 38c99c2ef60..3e36a0d233a 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -53,6 +53,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 032e0ec077c..ea038362532 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -26,6 +26,7 @@
#include "DEG_depsgraph.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
index 2dc67fc4d37..b54f81004f2 100644
--- a/source/blender/editors/asset/ED_asset_list.h
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -24,7 +24,7 @@ struct wmNotifier;
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
- struct bContext *C);
+ const struct bContext *C);
void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
/**
diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
index 67e253a4fcd..773838a54cd 100644
--- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc
+++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
@@ -97,10 +97,8 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
RNA_enum_item_add_separator(&item, &totitem);
}
- int i = 0;
- for (bUserAssetLibrary *user_library = (bUserAssetLibrary *)U.asset_libraries.first;
- user_library;
- user_library = user_library->next, i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bUserAssetLibrary *, user_library, &U.asset_libraries, i) {
/* Note that the path itself isn't checked for validity here. If an invalid library path is
* used, the Asset Browser can give a nice hint on what's wrong. */
const bool is_valid = (user_library->name[0] && user_library->path[0]);
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index 55167c1ed2d..b0ff5c86520 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -110,7 +110,7 @@ class AssetList : NonCopyable {
void setup();
void fetch(const bContext &C);
- void ensurePreviewsJob(bContext *C);
+ void ensurePreviewsJob(const bContext *C);
void clear(bContext *C);
bool needsRefetch() const;
@@ -212,7 +212,7 @@ void AssetList::iterate(AssetListIterFn fn) const
}
}
-void AssetList::ensurePreviewsJob(bContext *C)
+void AssetList::ensurePreviewsJob(const bContext *C)
{
FileList *files = filelist_;
int numfiles = filelist_files_ensure(files);
@@ -422,7 +422,8 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference,
AssetListStorage::fetch_library(*library_reference, *C);
}
-void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, bContext *C)
+void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference,
+ const bContext *C)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a8d25b75036..afef516b245 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2482,7 +2482,7 @@ enum uiTemplateListFlags {
ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST);
void uiTemplateList(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
@@ -2496,7 +2496,7 @@ void uiTemplateList(uiLayout *layout,
int columns,
enum uiTemplateListFlags flags);
struct uiList *uiTemplateList_ex(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
@@ -2566,7 +2566,7 @@ enum {
UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY = (1 << 2),
};
void uiTemplateAssetView(struct uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
const char *list_id,
struct PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_driver.c b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
index a9314df44a5..0f3062c3f61 100644
--- a/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
@@ -24,6 +24,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 0e69b4bb358..d7d1d3ce260 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -35,6 +35,7 @@
#include "UI_interface.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index ddd805f6010..4a5919864c7 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -40,6 +40,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc
index 09902dd6c35..8572e938b30 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.cc
+++ b/source/blender/editors/interface/interface_region_menu_pie.cc
@@ -27,6 +27,7 @@
#include "WM_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 88fe866f717..f460a159a5f 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -39,6 +39,7 @@
#include "WM_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 8588c7cabc0..3147deb5ad1 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -66,7 +66,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
}
static void asset_view_draw_item(uiList *ui_list,
- bContext *UNUSED(C),
+ const bContext *UNUSED(C),
uiLayout *layout,
PointerRNA *UNUSED(dataptr),
PointerRNA *itemptr,
@@ -183,7 +183,7 @@ static void asset_view_template_refresh_asset_collection(
}
void uiTemplateAssetView(uiLayout *layout,
- bContext *C,
+ const bContext *C,
const char *list_id,
PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index e0b6bbb34c4..f0c91588f98 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -83,7 +83,7 @@ struct TemplateListVisualInfo {
};
static void uilist_draw_item_default(struct uiList *ui_list,
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct uiLayout *layout,
struct PointerRNA *UNUSED(dataptr),
struct PointerRNA *itemptr,
@@ -114,7 +114,7 @@ static void uilist_draw_item_default(struct uiList *ui_list,
}
static void uilist_draw_filter_default(struct uiList *ui_list,
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct uiLayout *layout)
{
PointerRNA listptr;
@@ -160,7 +160,7 @@ static int cmpstringp(const void *p1, const void *p2)
}
static void uilist_filter_items_default(struct uiList *ui_list,
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct PointerRNA *dataptr,
const char *propname)
{
@@ -434,7 +434,7 @@ static void ui_template_list_collect_items(PointerRNA *list_ptr,
/**
* Create the UI-list representation of the list items, sorted and filtered if needed.
*/
-static void ui_template_list_collect_display_items(bContext *C,
+static void ui_template_list_collect_display_items(const bContext *C,
uiList *ui_list,
TemplateListInputData *input_data,
const uiListFilterItemsFunc filter_items_fn,
@@ -601,7 +601,7 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha
/**
* \note that \a layout_type may be null.
*/
-static uiList *ui_list_ensure(bContext *C,
+static uiList *ui_list_ensure(const bContext *C,
uiListType *ui_list_type,
const char *list_id,
int layout_type,
@@ -656,7 +656,7 @@ static uiList *ui_list_ensure(bContext *C,
return ui_list;
}
-static void ui_template_list_layout_draw(bContext *C,
+static void ui_template_list_layout_draw(const bContext *C,
uiList *ui_list,
uiLayout *layout,
TemplateListInputData *input_data,
@@ -1156,7 +1156,7 @@ static void ui_template_list_layout_draw(bContext *C,
}
uiList *uiTemplateList_ex(uiLayout *layout,
- bContext *C,
+ const bContext *C,
const char *listtype_name,
const char *list_id,
PointerRNA *dataptr,
@@ -1227,7 +1227,7 @@ uiList *uiTemplateList_ex(uiLayout *layout,
}
void uiTemplateList(uiLayout *layout,
- bContext *C,
+ const bContext *C,
const char *listtype_name,
const char *list_id,
PointerRNA *dataptr,
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 14da5a7cd62..a9de095a2a8 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -6674,7 +6674,7 @@ void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
}
static void cache_file_layer_item(uiList *UNUSED(ui_list),
- bContext *UNUSED(C),
+ const bContext *UNUSED(C),
uiLayout *layout,
PointerRNA *UNUSED(dataptr),
PointerRNA *itemptr,
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index bf3b71178e8..abf286afa0c 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -50,6 +50,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "ED_keyframing.h"
diff --git a/source/blender/editors/render/render_update.cc b/source/blender/editors/render/render_update.cc
index 3d26e764211..7cefcf9815e 100644
--- a/source/blender/editors/render/render_update.cc
+++ b/source/blender/editors/render/render_update.cc
@@ -95,20 +95,20 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
CTX_free(C);
}
- else {
- RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
- if (updated) {
- DRWUpdateContext drw_context = {nullptr};
- drw_context.bmain = bmain;
- drw_context.depsgraph = depsgraph;
- drw_context.scene = scene;
- drw_context.view_layer = view_layer;
- drw_context.region = region;
- drw_context.v3d = v3d;
- drw_context.engine_type = engine_type;
- DRW_notify_view_update(&drw_context);
- }
+
+ if (!updated) {
+ continue;
}
+
+ DRWUpdateContext drw_context = {nullptr};
+ drw_context.bmain = bmain;
+ drw_context.depsgraph = depsgraph;
+ drw_context.scene = scene;
+ drw_context.view_layer = view_layer;
+ drw_context.region = region;
+ drw_context.v3d = v3d;
+ drw_context.engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ DRW_notify_view_update(&drw_context);
}
}
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 9d66debda6f..01c208bf48d 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -34,6 +34,7 @@
#include "UI_resources.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
index 5bfc8ccc667..a955a074df2 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
@@ -67,10 +67,11 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.curves_num());
}
+ const Span<float> point_selection_span = selection.get_internal_span();
return index_mask_ops::find_indices_based_on_predicate(
curves.curves_range(), 512, r_indices, [&](const int curve_i) {
for (const int i : curves.points_for_curve(curve_i)) {
- if (selection[i] > 0.0f) {
+ if (point_selection_span[i] > 0.0f) {
return true;
}
}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index c69b73e377d..90b3cec437c 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -20,6 +20,7 @@
#include "ED_space_api.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 3b8c6cbd1d0..d41904d9790 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -41,6 +41,7 @@
#include "WM_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "ED_anim_api.h"
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index 160a379d3c6..bb520c0537e 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -36,6 +36,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
@@ -44,7 +45,12 @@
#include "UI_resources.h"
#include "NOD_common.h"
+#include "NOD_composite.h"
+#include "NOD_geometry.h"
+#include "NOD_shader.h"
#include "NOD_socket.h"
+#include "NOD_texture.h"
+
#include "node_intern.hh" /* own include */
namespace blender::ed::space_node {
@@ -99,16 +105,16 @@ const char *node_group_idname(bContext *C)
SpaceNode *snode = CTX_wm_space_node(C);
if (ED_node_is_shader(snode)) {
- return "ShaderNodeGroup";
+ return ntreeType_Shader->group_idname;
}
if (ED_node_is_compositor(snode)) {
- return "CompositorNodeGroup";
+ return ntreeType_Composite->group_idname;
}
if (ED_node_is_texture(snode)) {
- return "TextureNodeGroup";
+ return ntreeType_Texture->group_idname;
}
if (ED_node_is_geometry(snode)) {
- return "GeometryNodeGroup";
+ return ntreeType_Geometry->group_idname;
}
return "";
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index 32860bc2cff..16da4f7b1dd 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -55,6 +55,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "GPU_material.h"
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index ea35a8c0fa7..1b4acda9bcf 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -30,6 +30,7 @@
#include "UI_view2d.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "text_format.h"
#include "text_intern.h" /* own include */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index 41015c429fe..aa9c654aa7e 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -270,7 +270,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
}
static void segment_list_item(struct uiList *UNUSED(ui_list),
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct uiLayout *layout,
struct PointerRNA *UNUSED(idataptr),
struct PointerRNA *itemptr,
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 5e97909a2b8..2de0f4e470a 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -456,6 +456,7 @@ set(SRC_SHADER_CREATE_INFOS
../draw/engines/basic/shaders/infos/basic_depth_info.hh
../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh
../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+ ../draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh
../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 3ca465fa57a..12a7cf49f9d 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -121,6 +121,7 @@ typedef struct GPUCodegenOutput {
char *surface;
char *volume;
char *thickness;
+ char *composite;
char *material_functions;
GPUShaderCreateInfo *create_info;
@@ -178,6 +179,8 @@ void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash);
+void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link);
+
/**
* Wrap a part of the material graph into a function. You need then need to call the function by
* using something like #GPU_differentiate_float_function.
@@ -218,6 +221,7 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
void *thunk);
void GPU_material_compile(GPUMaterial *mat);
+void GPU_material_free_single(GPUMaterial *material);
void GPU_material_free(struct ListBase *gpumaterial);
void GPU_material_acquire(GPUMaterial *mat);
@@ -319,6 +323,16 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info);
void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, GPUUniformAttrList *src);
void GPU_uniform_attr_list_free(GPUUniformAttrList *set);
+/* A callback passed to GPU_material_from_callbacks to construct the material graph by adding and
+ * linking the necessary GPU material nodes. */
+typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material);
+
+/* Construct a GPU material from a set of callbacks. See the callback types for more information.
+ * The given thunk will be passed as the first parameter of each callback. */
+GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb,
+ GPUCodegenCallbackFn generate_code_function_cb,
+ void *thunk);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 3460d33fe68..c154f1adc8b 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -177,7 +177,9 @@ void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, fl
void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]);
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]);
void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]);
+void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]);
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]);
+void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]);
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]);
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]);
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index 82441c3c89c..4a45a3e63ed 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -280,6 +280,7 @@ class GPUCodegen {
void node_serialize(std::stringstream &eval_ss, const GPUNode *node);
char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link);
+ char *graph_serialize(eGPUNodeTag tree_tag);
static char *extract_c_str(std::stringstream &stream)
{
@@ -500,6 +501,19 @@ char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link
return eval_c_str;
}
+char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag)
+{
+ std::stringstream eval_ss;
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ if (node->tag & tree_tag) {
+ node_serialize(eval_ss, node);
+ }
+ }
+ char *eval_c_str = extract_c_str(eval_ss);
+ BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size());
+ return eval_c_str;
+}
+
void GPUCodegen::generate_uniform_buffer()
{
/* Extract uniform inputs. */
@@ -539,6 +553,9 @@ void GPUCodegen::generate_graphs()
output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume);
output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement);
output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness);
+ if (!BLI_listbase_is_empty(&graph.outlink_compositor)) {
+ output.composite = graph_serialize(GPU_NODE_TAG_COMPOSITOR);
+ }
if (!BLI_listbase_is_empty(&graph.material_functions)) {
std::stringstream eval_ss;
@@ -569,9 +586,10 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
GPUCodegenCallbackFn finalize_source_cb,
void *thunk)
{
- /* Prune the unused nodes and extract attributes before compiling so the
- * generated VBOs are ready to accept the future shader. */
gpu_node_graph_prune_unused(graph);
+
+ /* Extract attributes before compiling so the generated VBOs are ready to accept the future
+ * shader. */
gpu_node_graph_finalize_uniform_attrs(graph);
GPUCodegen codegen(material, graph);
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 4d3ea3e0c99..a4842ef0e43 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -141,7 +141,7 @@ static void gpu_material_ramp_texture_build(GPUMaterial *mat)
mat->coba_builder = NULL;
}
-static void gpu_material_free_single(GPUMaterial *material)
+void GPU_material_free_single(GPUMaterial *material)
{
bool do_free = atomic_sub_and_fetch_uint32(&material->refcount, 1) == 0;
if (!do_free) {
@@ -173,7 +173,7 @@ void GPU_material_free(ListBase *gpumaterial)
LISTBASE_FOREACH (LinkData *, link, gpumaterial) {
GPUMaterial *material = link->data;
DRW_deferred_shader_remove(material);
- gpu_material_free_single(material);
+ GPU_material_free_single(material);
}
BLI_freelistN(gpumaterial);
}
@@ -538,6 +538,13 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link,
BLI_addtail(&material->graph.outlink_aovs, aov_link);
}
+void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link)
+{
+ GPUNodeGraphOutputLink *compositor_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__);
+ compositor_link->outlink = link;
+ BLI_addtail(&material->graph.outlink_compositor, compositor_link);
+}
+
char *GPU_material_split_sub_function(GPUMaterial *material,
eGPUType return_type,
GPUNodeLink **link)
@@ -721,7 +728,7 @@ void GPU_material_acquire(GPUMaterial *mat)
void GPU_material_release(GPUMaterial *mat)
{
- gpu_material_free_single(mat);
+ GPU_material_free_single(mat);
}
void GPU_material_compile(GPUMaterial *mat)
@@ -772,3 +779,42 @@ void GPU_materials_free(Main *bmain)
// BKE_world_defaults_free_gpu();
BKE_material_defaults_free_gpu();
}
+
+GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb,
+ GPUCodegenCallbackFn generate_code_function_cb,
+ void *thunk)
+{
+ /* Allocate a new material and its material graph, and initialize its reference count. */
+ GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
+ material->graph.used_libraries = BLI_gset_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
+ material->refcount = 1;
+
+ /* Construct the material graph by adding and linking the necessary GPU material nodes. */
+ construct_function_cb(thunk, material);
+
+ /* Create and initialize the texture storing color bands used by Ramp and Curve nodes. */
+ gpu_material_ramp_texture_build(material);
+
+ /* Lookup an existing pass in the cache or generate a new one. */
+ material->pass = GPU_generate_pass(material, &material->graph, generate_code_function_cb, thunk);
+
+ /* The pass already exists in the pass cache but its shader already failed to compile. */
+ if (material->pass == NULL) {
+ material->status = GPU_MAT_FAILED;
+ gpu_node_graph_free(&material->graph);
+ return material;
+ }
+
+ /* The pass already exists in the pass cache and its shader is already compiled. */
+ GPUShader *shader = GPU_pass_shader_get(material->pass);
+ if (shader != NULL) {
+ material->status = GPU_MAT_SUCCESS;
+ gpu_node_graph_free_nodes(&material->graph);
+ return material;
+ }
+
+ /* The material was created successfully but still needs to be compiled. */
+ material->status = GPU_MAT_CREATED;
+ return material;
+}
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 684070dbdc0..c7b2fde492f 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -75,9 +75,26 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
if (STR_ELEM(name, "set_value", "set_rgb", "set_rgba") && (input->type == type)) {
input = MEM_dupallocN(outnode->inputs.first);
+
+ switch (input->source) {
+ case GPU_SOURCE_ATTR:
+ input->attr->users++;
+ break;
+ case GPU_SOURCE_UNIFORM_ATTR:
+ input->uniform_attr->users++;
+ break;
+ case GPU_SOURCE_TEX:
+ case GPU_SOURCE_TEX_TILED_MAPPING:
+ input->texture->users++;
+ break;
+ default:
+ break;
+ }
+
if (input->link) {
input->link->users++;
}
+
BLI_addtail(&node->inputs, input);
return;
}
@@ -179,35 +196,21 @@ static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat,
BLI_assert(socket != NULL);
BLI_assert(socket->in_out == in_out);
- if ((socket->flag & SOCK_HIDE_VALUE) == 0) {
- GPUNodeLink *link;
- switch (socket->type) {
- case SOCK_FLOAT: {
- bNodeSocketValueFloat *socket_data = socket->default_value;
- link = GPU_uniform(&socket_data->value);
- break;
- }
- case SOCK_VECTOR: {
- bNodeSocketValueVector *socket_data = socket->default_value;
- link = GPU_uniform(socket_data->value);
- break;
- }
- case SOCK_RGBA: {
- bNodeSocketValueRGBA *socket_data = socket->default_value;
- link = GPU_uniform(socket_data->value);
- break;
- }
- default:
- return NULL;
- break;
- }
+ if (socket->flag & SOCK_HIDE_VALUE) {
+ return NULL;
+ }
- if (in_out == SOCK_IN) {
- GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link);
- }
- return link;
+ if (!ELEM(socket->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA)) {
+ return NULL;
+ }
+
+ GPUNodeLink *link = GPU_uniform(stack->vec);
+
+ if (in_out == SOCK_IN) {
+ GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link);
}
- return NULL;
+
+ return link;
}
static void gpu_node_input_socket(
@@ -803,6 +806,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
BLI_freelistN(&graph->material_functions);
+ BLI_freelistN(&graph->outlink_compositor);
gpu_node_graph_free_nodes(graph);
BLI_freelistN(&graph->textures);
@@ -855,6 +859,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) {
gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION);
}
+ LISTBASE_FOREACH (GPUNodeGraphOutputLink *, compositor_link, &graph->outlink_compositor) {
+ gpu_nodes_tag(compositor_link->outlink, GPU_NODE_TAG_COMPOSITOR);
+ }
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
next = node->next;
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index ae472d5b7aa..08ff8bbef58 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -59,6 +59,7 @@ typedef enum {
GPU_NODE_TAG_THICKNESS = (1 << 3),
GPU_NODE_TAG_AOV = (1 << 4),
GPU_NODE_TAG_FUNCTION = (1 << 5),
+ GPU_NODE_TAG_COMPOSITOR = (1 << 6),
} eGPUNodeTag;
ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION)
@@ -158,6 +159,8 @@ typedef struct GPUNodeGraph {
ListBase outlink_aovs;
/* List of GPUNodeGraphFunctionLink */
ListBase material_functions;
+ /* List of GPUNodeGraphOutputLink */
+ ListBase outlink_compositor;
/* Requested attributes and textures. */
ListBase attributes;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index fe9aacb95f9..8a630d9e3ca 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -7,6 +7,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_matrix.h"
#include "BLI_string_utils.h"
#include "GPU_capabilities.h"
@@ -382,6 +383,8 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
sources.append(resources.c_str());
sources.append(layout.c_str());
sources.extend(code);
+ sources.extend(info.dependencies_generated);
+ sources.append(info.compute_source_generated.c_str());
shader->compute_shader_from_glsl(sources);
}
@@ -702,12 +705,25 @@ void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]
GPU_shader_uniform_vector(sh, loc, 4, 1, data);
}
+void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
+{
+ const int loc = GPU_shader_get_uniform(sh, name);
+ GPU_shader_uniform_vector_int(sh, loc, 2, 1, data);
+}
+
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
{
const int loc = GPU_shader_get_uniform(sh, name);
GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data);
}
+void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
+{
+ float matrix[4][4];
+ copy_m4_m3(matrix, data);
+ GPU_shader_uniform_mat4(sh, name, matrix);
+}
+
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2])
{
const int loc = GPU_shader_get_uniform(sh, name);
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index 8e05412d0ee..fb8efbb209a 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -298,6 +298,7 @@ struct ShaderCreateInfo {
/** Manually set generated code. */
std::string vertex_source_generated = "";
std::string fragment_source_generated = "";
+ std::string compute_source_generated = "";
std::string geometry_source_generated = "";
std::string typedef_source_generated = "";
/** Manually set generated dependencies. */
@@ -818,6 +819,7 @@ struct ShaderCreateInfo {
TEST_EQUAL(*this, b, builtins_);
TEST_EQUAL(*this, b, vertex_source_generated);
TEST_EQUAL(*this, b, fragment_source_generated);
+ TEST_EQUAL(*this, b, compute_source_generated);
TEST_EQUAL(*this, b, typedef_source_generated);
TEST_VECTOR_EQUAL(*this, b, vertex_inputs_);
TEST_EQUAL(*this, b, geometry_layout_);
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index d91e15243f3..aff7df9ac33 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -593,7 +593,8 @@ struct GPUSource {
bool is_from_material_library() const
{
return (filename.startswith("gpu_shader_material_") ||
- filename.startswith("gpu_shader_common_")) &&
+ filename.startswith("gpu_shader_common_") ||
+ filename.startswith("gpu_shader_compositor_")) &&
filename.endswith(".glsl");
}
};
diff --git a/source/blender/io/collada/BCAnimationCurve.cpp b/source/blender/io/collada/BCAnimationCurve.cpp
index 04a7a81c0a6..fe90dc5d5fa 100644
--- a/source/blender/io/collada/BCAnimationCurve.cpp
+++ b/source/blender/io/collada/BCAnimationCurve.cpp
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2008 Blender Foundation. All rights reserved. */
+#include "RNA_path.h"
+
#include "BCAnimationCurve.h"
BCAnimationCurve::BCAnimationCurve()
diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h
index d49d0906aa7..29795519719 100644
--- a/source/blender/makesdna/DNA_asset_types.h
+++ b/source/blender/makesdna/DNA_asset_types.h
@@ -96,7 +96,7 @@ typedef enum eAssetLibraryType {
} eAssetLibraryType;
/**
- * Information to identify a asset library. May be either one of the predefined types (current
+ * Information to identify an asset library. May be either one of the predefined types (current
* 'Main', builtin library, project library), or a custom type as defined in the Preferences.
*
* If the type is set to #ASSET_LIBRARY_CUSTOM, `custom_library_index` must be set to identify the
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 0af50b2bd4f..345fa141514 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -37,7 +37,7 @@ typedef enum eViewLayerEEVEEPassType {
EEVEE_RENDER_PASS_CRYPTOMATTE = (1 << 16),
EEVEE_RENDER_PASS_VECTOR = (1 << 17),
} eViewLayerEEVEEPassType;
-#define EEVEE_RENDER_PASS_MAX_BIT 17
+#define EEVEE_RENDER_PASS_MAX_BIT 18
/* #ViewLayerAOV.type */
typedef enum eViewLayerAOVType {
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 005228bea72..de9fa60aa5d 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -475,247 +475,6 @@ bool RNA_property_copy(
bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index);
bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop);
-/* Path
- *
- * Experimental method to refer to structs and properties with a string,
- * using a syntax like: scenes[0].objects["Cube"].data.verts[7].co
- *
- * This provides a way to refer to RNA data while being detached from any
- * particular pointers, which is useful in a number of applications, like
- * UI code or Actions, though efficiency is a concern. */
-
-char *RNA_path_append(
- const char *path, const PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey);
-#if 0 /* UNUSED. */
-char *RNA_path_back(const char *path);
-#endif
-
-/**
- * Search for the start of the 'rna array index' part of the given `rna_path`.
- *
- * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first
- * character in `rna_path` that is part of the array index for the given property. Return NULL if
- * none can be found, e.g. because the property is not an RNA array.
- *
- * \param array_prop: if not NULL, the #PropertyRNA assumed to be the last one from the RNA path.
- * Only used to ensure it is a valid array property.
- */
-const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop);
-
-/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
-
-/**
- * Resolve the given RNA Path to find the pointer and/or property
- * indicated by fully resolving the path.
- *
- * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
- * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
- * and a NULL \a r_prop...
- *
- * \note Assumes all pointers provided are valid
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
-bool RNA_path_resolve(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop);
-
-/**
- * Resolve the given RNA Path to find the pointer and/or property + array index
- * indicated by fully resolving the path.
- *
- * \note Assumes all pointers provided are valid.
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
-bool RNA_path_resolve_full(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index);
-/**
- * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
- *
- * \note While it's correct to ignore the value of #PointerRNA.data
- * most callers need to know if the resulting pointer was found and not null.
- */
-bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index);
-
-/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
-
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
-bool RNA_path_resolve_property(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop);
-
-/**
- * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
-bool RNA_path_resolve_property_full(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index);
-
-/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
- * and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
-
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path, and get the value of the Pointer property
- * (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
-bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- PointerRNA *r_item_ptr);
-
-/**
- * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
- * indicated by fully resolving the path,
- * and get the value of the Pointer property (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve_full and
- * \a RNA_path_resolve_property_full in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
-bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index,
- PointerRNA *r_item_ptr);
-
-typedef struct PropertyElemRNA PropertyElemRNA;
-struct PropertyElemRNA {
- PropertyElemRNA *next, *prev;
- PointerRNA ptr;
- PropertyRNA *prop;
- int index;
-};
-/**
- * Resolve the given RNA Path into a linked list of #PropertyElemRNA's.
- *
- * To be used when complex operations over path are needed, like e.g. get relative paths,
- * to avoid too much string operations.
- *
- * \return True if there was no error while resolving the path
- * \note Assumes all pointers provided are valid
- */
-bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
-
-/**
- * Find the path from the structure referenced by the pointer to the runtime RNA-defined
- * #IDProperty object.
- *
- * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
- *
- * \param ptr: Reference to the object owning the custom property storage.
- * \param needle: Custom property object to find.
- * \return Relative path or NULL.
- */
-char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle);
-
-/**
- * Find the actual ID pointer and path from it to the given ID.
- *
- * \param id: ID reference to search the global owner for.
- * \param[out] r_path: Path from the real ID to the initial ID.
- * \return The ID pointer, or NULL in case of failure.
- */
-struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
-
-char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
-
-char *RNA_path_from_real_ID_to_struct(struct Main *bmain,
- const PointerRNA *ptr,
- struct ID **r_real);
-
-char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop);
-/**
- * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
- * \param index: The *flattened* index to use when \a `index_dim > 0`,
- * this is expanded when used with multi-dimensional arrays.
- */
-char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
- PropertyRNA *prop,
- int index_dim,
- int index);
-
-char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
- const PointerRNA *ptr,
- PropertyRNA *prop,
- int index_dim,
- int index,
- struct ID **r_real_id);
-
-/**
- * \return the path to given ptr/prop from the closest ancestor of given type,
- * if any (else return NULL).
- */
-char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
- PropertyRNA *prop,
- const struct StructRNA *type);
-
-/**
- * Get the ID as a python representation, eg:
- * bpy.data.foo["bar"]
- */
-char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
-/**
- * Get the ID.struct as a python representation, eg:
- * bpy.data.foo["bar"].some_struct
- */
-char *RNA_path_full_struct_py(struct Main *bmain, const PointerRNA *ptr);
-/**
- * Get the ID.struct.property as a python representation, eg:
- * bpy.data.foo["bar"].some_struct.some_prop[10]
- */
-char *RNA_path_full_property_py_ex(
- struct Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
-char *RNA_path_full_property_py(struct Main *bmain,
- const PointerRNA *ptr,
- PropertyRNA *prop,
- int index);
-/**
- * Get the struct.property as a python representation, eg:
- * some_struct.some_prop[10]
- */
-char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index);
-/**
- * Get the struct.property as a python representation, eg:
- * some_prop[10]
- */
-char *RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index);
-
/* Quick name based property access
*
* These are just an easier way to access property values without having to
diff --git a/source/blender/makesrna/RNA_path.h b/source/blender/makesrna/RNA_path.h
new file mode 100644
index 00000000000..7ab8c6fa313
--- /dev/null
+++ b/source/blender/makesrna/RNA_path.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup RNA
+ *
+ * RNA paths are a way to refer to pointers and properties with a string,
+ * using a syntax like: scenes[0].objects["Cube"].data.verts[7].co
+ *
+ * This provides a way to refer to RNA data while being detached from any
+ * particular pointers, which is useful in a number of applications, like
+ * UI code or Actions, though efficiency is a concern.
+ */
+
+#include "RNA_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+struct IDProperty;
+
+char *RNA_path_append(
+ const char *path, const PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey);
+#if 0 /* UNUSED. */
+char *RNA_path_back(const char *path);
+#endif
+
+/**
+ * Search for the start of the 'rna array index' part of the given `rna_path`.
+ *
+ * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first
+ * character in `rna_path` that is part of the array index for the given property. Return NULL if
+ * none can be found, e.g. because the property is not an RNA array.
+ *
+ * \param array_prop: if not NULL, the #PropertyRNA assumed to be the last one from the RNA path.
+ * Only used to ensure it is a valid array property.
+ */
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop);
+
+/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
+
+/**
+ * Resolve the given RNA Path to find the pointer and/or property
+ * indicated by fully resolving the path.
+ *
+ * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
+ * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
+ * and a NULL \a r_prop...
+ *
+ * \note Assumes all pointers provided are valid
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
+bool RNA_path_resolve(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop);
+
+/**
+ * Resolve the given RNA Path to find the pointer and/or property + array index
+ * indicated by fully resolving the path.
+ *
+ * \note Assumes all pointers provided are valid.
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
+bool RNA_path_resolve_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
+/**
+ * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
+ *
+ * \note While it's correct to ignore the value of #PointerRNA.data
+ * most callers need to know if the resulting pointer was found and not null.
+ */
+bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
+
+/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop);
+
+/**
+ * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index);
+
+/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
+ * and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path, and get the value of the Pointer property
+ * (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ PointerRNA *r_item_ptr);
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path,
+ * and get the value of the Pointer property (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve_full and
+ * \a RNA_path_resolve_property_full in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index,
+ PointerRNA *r_item_ptr);
+
+typedef struct PropertyElemRNA PropertyElemRNA;
+struct PropertyElemRNA {
+ PropertyElemRNA *next, *prev;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+};
+/**
+ * Resolve the given RNA Path into a linked list of #PropertyElemRNA's.
+ *
+ * To be used when complex operations over path are needed, like e.g. get relative paths,
+ * to avoid too much string operations.
+ *
+ * \return True if there was no error while resolving the path
+ * \note Assumes all pointers provided are valid
+ */
+bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+
+/**
+ * Find the path from the structure referenced by the pointer to the runtime RNA-defined
+ * #IDProperty object.
+ *
+ * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
+ *
+ * \param ptr: Reference to the object owning the custom property storage.
+ * \param needle: Custom property object to find.
+ * \return Relative path or NULL.
+ */
+char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle);
+
+/**
+ * Find the actual ID pointer and path from it to the given ID.
+ *
+ * \param id: ID reference to search the global owner for.
+ * \param[out] r_path: Path from the real ID to the initial ID.
+ * \return The ID pointer, or NULL in case of failure.
+ */
+struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
+
+char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
+
+char *RNA_path_from_real_ID_to_struct(struct Main *bmain,
+ const PointerRNA *ptr,
+ struct ID **r_real);
+
+char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a `index_dim > 0`,
+ * this is expanded when used with multi-dimensional arrays.
+ */
+char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index);
+
+char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index,
+ struct ID **r_real_id);
+
+/**
+ * \return the path to given ptr/prop from the closest ancestor of given type,
+ * if any (else return NULL).
+ */
+char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
+ PropertyRNA *prop,
+ const struct StructRNA *type);
+
+/**
+ * Get the ID as a python representation, eg:
+ * bpy.data.foo["bar"]
+ */
+char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
+/**
+ * Get the ID.struct as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct
+ */
+char *RNA_path_full_struct_py(struct Main *bmain, const PointerRNA *ptr);
+/**
+ * Get the ID.struct.property as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct.some_prop[10]
+ */
+char *RNA_path_full_property_py_ex(
+ struct Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
+char *RNA_path_full_property_py(struct Main *bmain,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_struct.some_prop[10]
+ */
+char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_prop[10]
+ */
+char *RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index aaadd36341f..8124804de2b 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -159,6 +159,7 @@ set(SRC_RNA_INC
../RNA_documentation.h
../RNA_enum_items.h
../RNA_enum_types.h
+ ../RNA_path.h
../RNA_types.h
)
@@ -416,6 +417,7 @@ add_custom_command(
set(SRC
rna_access.c
rna_access_compare_override.c
+ rna_path.cc
${GENSRC}
${SRC_RNA_INC}
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index cf4182243b9..04707c01d6b 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -46,6 +46,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -738,7 +739,7 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
}
/* Find the property which uses the given nested struct */
-static PropertyRNA *RNA_struct_find_nested(PointerRNA *ptr, StructRNA *srna)
+PropertyRNA *rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna)
{
PropertyRNA *prop = NULL;
@@ -1422,7 +1423,7 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
return cprop->item_type;
}
}
- /* ignore other types, RNA_struct_find_nested calls with unchecked props */
+ /* ignore other types, rna_struct_find_nested calls with unchecked props */
return &RNA_UnknownType;
}
@@ -4821,1337 +4822,6 @@ PointerRNA rna_array_lookup_int(
return rna_pointer_inherit_refine(ptr, type, ((char *)data) + index * itemsize);
}
-/* RNA Path - Experiment */
-
-/**
- * Extract the first token from `path`.
- *
- * \param path: Extract the token from path, step the pointer to the beginning of the next token
- * \return The nil terminated token.
- */
-static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen)
-{
- int len = 0;
-
- /* Get data until `.` or `[`. */
- const char *p = *path;
- while (*p && !ELEM(*p, '.', '[')) {
- len++;
- p++;
- }
-
- /* Empty, return. */
- if (UNLIKELY(len == 0)) {
- return NULL;
- }
-
- /* Try to use fixed buffer if possible. */
- char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__);
- memcpy(buf, *path, sizeof(char) * len);
- buf[len] = '\0';
-
- if (*p == '.') {
- p++;
- }
- *path = p;
-
- return buf;
-}
-
-/**
- * Extract the first token in brackets from `path` (with quoted text support).
- *
- * - `[0]` -> `0`
- * - `["Some\"Quote"]` -> `Some"Quote`
- *
- * \param path: Extract the token from path, step the pointer to the beginning of the next token
- * (past quoted text and brackets).
- * \return The nil terminated token.
- */
-static char *rna_path_token_in_brackets(const char **path,
- char *fixedbuf,
- int fixedlen,
- bool *r_quoted)
-{
- int len = 0;
- bool quoted = false;
-
- BLI_assert(r_quoted != NULL);
-
- /* Get data between `[]`, check escaping quotes and back-slashes with #BLI_str_unescape. */
- if (UNLIKELY(**path != '[')) {
- return NULL;
- }
-
- (*path)++;
- const char *p = *path;
-
- /* 2 kinds of look-ups now, quoted or unquoted. */
- if (*p == '"') {
- /* Find the matching quote. */
- (*path)++;
- p = *path;
- const char *p_end = BLI_str_escape_find_quote(p);
- if (p_end == NULL) {
- /* No Matching quote. */
- return NULL;
- }
- /* Exclude the last quote from the length. */
- len += (p_end - p);
-
- /* Skip the last quoted char to get the `]`. */
- p_end += 1;
- p = p_end;
- quoted = true;
- }
- else {
- /* Find the matching bracket. */
- while (*p && (*p != ']')) {
- len++;
- p++;
- }
- }
-
- if (UNLIKELY(*p != ']')) {
- return NULL;
- }
-
- /* Empty, return. */
- if (UNLIKELY(len == 0)) {
- return NULL;
- }
-
- /* Try to use fixed buffer if possible. */
- char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__);
-
- /* Copy string, taking into account escaped ']' */
- if (quoted) {
- BLI_str_unescape(buf, *path, len);
- /* +1 to step over the last quote. */
- BLI_assert((*path)[len] == '"');
- p = (*path) + len + 1;
- }
- else {
- memcpy(buf, *path, sizeof(char) * len);
- buf[len] = '\0';
- }
- /* Set path to start of next token. */
- if (*p == ']') {
- p++;
- }
- if (*p == '.') {
- p++;
- }
- *path = p;
-
- *r_quoted = quoted;
-
- return buf;
-}
-
-/**
- * \return true when the key in the path is correctly parsed and found in the collection
- * or when the path is empty.
- */
-static bool rna_path_parse_collection_key(const char **path,
- PointerRNA *ptr,
- PropertyRNA *prop,
- PointerRNA *r_nextptr)
-{
- char fixedbuf[256];
- int intkey;
-
- *r_nextptr = *ptr;
-
- /* end of path, ok */
- if (!(**path)) {
- return true;
- }
-
- bool found = false;
- if (**path == '[') {
- bool quoted;
- char *token;
-
- /* resolve the lookup with [] brackets */
- token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), &quoted);
-
- if (!token) {
- return false;
- }
-
- /* check for "" to see if it is a string */
- if (quoted) {
- if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) {
- found = true;
- }
- else {
- r_nextptr->data = NULL;
- }
- }
- else {
- /* otherwise do int lookup */
- intkey = atoi(token);
- if (intkey == 0 && (token[0] != '0' || token[1] != '\0')) {
- return false; /* we can be sure the fixedbuf was used in this case */
- }
- if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) {
- found = true;
- }
- else {
- r_nextptr->data = NULL;
- }
- }
-
- if (token != fixedbuf) {
- MEM_freeN(token);
- }
- }
- else {
- if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) {
- found = true;
- }
- else {
- /* ensure we quit on invalid values */
- r_nextptr->data = NULL;
- }
- }
-
- return found;
-}
-
-static bool rna_path_parse_array_index(const char **path,
- PointerRNA *ptr,
- PropertyRNA *prop,
- int *r_index)
-{
- char fixedbuf[256];
- int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0};
- int len[RNA_MAX_ARRAY_DIMENSION];
- const int dim = RNA_property_array_dimension(ptr, prop, len);
- int i;
-
- *r_index = -1;
-
- /* end of path, ok */
- if (!(**path)) {
- return true;
- }
-
- for (i = 0; i < dim; i++) {
- int temp_index = -1;
- char *token;
-
- /* multi index resolve */
- if (**path == '[') {
- bool quoted;
- token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), &quoted);
-
- if (token == NULL) {
- /* invalid syntax blah[] */
- return false;
- }
- /* check for "" to see if it is a string */
- if (quoted) {
- temp_index = RNA_property_array_item_index(prop, *token);
- }
- else {
- /* otherwise do int lookup */
- temp_index = atoi(token);
-
- if (temp_index == 0 && (token[0] != '0' || token[1] != '\0')) {
- if (token != fixedbuf) {
- MEM_freeN(token);
- }
-
- return false;
- }
- }
- }
- else if (dim == 1) {
- /* location.x || scale.X, single dimension arrays only */
- token = rna_path_token(path, fixedbuf, sizeof(fixedbuf));
- if (token == NULL) {
- /* invalid syntax blah. */
- return false;
- }
- temp_index = RNA_property_array_item_index(prop, *token);
- }
- else {
- /* just to avoid uninitialized pointer use */
- token = fixedbuf;
- }
-
- if (token != fixedbuf) {
- MEM_freeN(token);
- }
-
- /* out of range */
- if (temp_index < 0 || temp_index >= len[i]) {
- return false;
- }
-
- index_arr[i] = temp_index;
- /* end multi index resolve */
- }
-
- /* arrays always contain numbers so further values are not valid */
- if (**path) {
- return false;
- }
-
- /* flatten index over all dimensions */
- {
- int totdim = 1;
- int flat_index = 0;
-
- for (i = dim - 1; i >= 0; i--) {
- flat_index += index_arr[i] * totdim;
- totdim *= len[i];
- }
-
- *r_index = flat_index;
- }
- return true;
-}
-
-/**
- * Generic rna path parser.
- *
- * \note All parameters besides \a ptr and \a path are optional.
- *
- * \param ptr: The root of given RNA path.
- * \param path: The RNA path.
- * \param r_ptr: The final RNA data holding the last property in \a path.
- * \param r_prop: The final property of \a r_ptr, from \a path.
- * \param r_index: The final index in the \a r_prop, if defined by \a path.
- * \param r_item_ptr: Only valid for Pointer and Collection, return the actual value of the
- * pointer, or of the collection item.
- * Mutually exclusive with \a eval_pointer option.
- * \param r_elements: A list of \a PropertyElemRNA items(pairs of \a PointerRNA, \a PropertyRNA
- * that represent the whole given \a path).
- * \param eval_pointer: If \a true, and \a path leads to a Pointer property, or an item in a
- * Collection property, \a r_ptr will be set to the value of that property,
- * and \a r_prop will be NULL.
- * Mutually exclusive with \a r_item_ptr.
- *
- * \return \a true on success, \a false if the path is somehow invalid.
- */
-static bool rna_path_parse(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index,
- PointerRNA *r_item_ptr,
- ListBase *r_elements,
- const bool eval_pointer)
-{
- BLI_assert(r_item_ptr == NULL || !eval_pointer);
- PropertyRNA *prop;
- PointerRNA curptr, nextptr;
- PropertyElemRNA *prop_elem = NULL;
- int index = -1;
- char fixedbuf[256];
- int type;
- const bool do_item_ptr = r_item_ptr != NULL && !eval_pointer;
-
- if (do_item_ptr) {
- RNA_POINTER_INVALIDATE(&nextptr);
- }
-
- prop = NULL;
- curptr = *ptr;
-
- if (path == NULL || *path == '\0') {
- return false;
- }
-
- while (*path) {
- if (do_item_ptr) {
- RNA_POINTER_INVALIDATE(&nextptr);
- }
-
- const bool use_id_prop = (*path == '[');
- /* custom property lookup ?
- * C.object["someprop"]
- */
-
- if (!curptr.data) {
- return false;
- }
-
- /* look up property name in current struct */
- bool quoted = false;
- char *token = use_id_prop ?
- rna_path_token_in_brackets(&path, fixedbuf, sizeof(fixedbuf), &quoted) :
- rna_path_token(&path, fixedbuf, sizeof(fixedbuf));
- if (!token) {
- return false;
- }
-
- prop = NULL;
- if (use_id_prop) { /* look up property name in current struct */
- IDProperty *group = RNA_struct_idprops(&curptr, 0);
- if (group && quoted) {
- prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, token);
- }
- }
- else {
- prop = RNA_struct_find_property(&curptr, token);
- }
-
- if (token != fixedbuf) {
- MEM_freeN(token);
- }
-
- if (!prop) {
- return false;
- }
-
- if (r_elements) {
- prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
- prop_elem->ptr = curptr;
- prop_elem->prop = prop;
- prop_elem->index = -1; /* index will be added later, if needed. */
- BLI_addtail(r_elements, prop_elem);
- }
-
- type = RNA_property_type(prop);
-
- /* now look up the value of this property if it is a pointer or
- * collection, otherwise return the property rna so that the
- * caller can read the value of the property itself */
- switch (type) {
- case PROP_POINTER: {
- /* resolve pointer if further path elements follow
- * or explicitly requested
- */
- if (do_item_ptr || eval_pointer || *path != '\0') {
- nextptr = RNA_property_pointer_get(&curptr, prop);
- }
-
- if (eval_pointer || *path != '\0') {
- curptr = nextptr;
- prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
- index = -1;
- }
- break;
- }
- case PROP_COLLECTION: {
- /* Resolve pointer if further path elements follow.
- * Note that if path is empty, rna_path_parse_collection_key will do nothing anyway,
- * so do_item_ptr is of no use in that case.
- */
- if (*path) {
- if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) {
- return false;
- }
-
- if (eval_pointer || *path != '\0') {
- curptr = nextptr;
- prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
- index = -1;
- }
- }
- break;
- }
- default:
- if (r_index || prop_elem) {
- if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) {
- return false;
- }
-
- if (prop_elem) {
- prop_elem->index = index;
- }
- }
- break;
- }
- }
-
- if (r_ptr) {
- *r_ptr = curptr;
- }
- if (r_prop) {
- *r_prop = prop;
- }
- if (r_index) {
- *r_index = index;
- }
- if (r_item_ptr && do_item_ptr) {
- *r_item_ptr = nextptr;
- }
-
- if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop ||
- prop_elem->index != index)) {
- prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
- prop_elem->ptr = curptr;
- prop_elem->prop = prop;
- prop_elem->index = index;
- BLI_addtail(r_elements, prop_elem);
- }
-
- return true;
-}
-
-bool RNA_path_resolve(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop)
-{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
- return false;
- }
-
- return r_ptr->data != NULL;
-}
-
-bool RNA_path_resolve_full(
- const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
-{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) {
- return false;
- }
-
- return r_ptr->data != NULL;
-}
-
-bool RNA_path_resolve_full_maybe_null(
- const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
-{
- return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
-}
-
-bool RNA_path_resolve_property(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop)
-{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, false)) {
- return false;
- }
-
- return r_ptr->data != NULL && *r_prop != NULL;
-}
-
-bool RNA_path_resolve_property_full(
- const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
-{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) {
- return false;
- }
-
- return r_ptr->data != NULL && *r_prop != NULL;
-}
-
-bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- PointerRNA *r_item_ptr)
-{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, r_item_ptr, NULL, false)) {
- return false;
- }
-
- return r_ptr->data != NULL && *r_prop != NULL;
-}
-
-bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
- const char *path,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index,
- PointerRNA *r_item_ptr)
-{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, NULL, false)) {
- return false;
- }
-
- return r_ptr->data != NULL && *r_prop != NULL;
-}
-bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
-{
- return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
-}
-
-char *RNA_path_append(const char *path,
- const PointerRNA *UNUSED(ptr),
- PropertyRNA *prop,
- int intkey,
- const char *strkey)
-{
- DynStr *dynstr;
- char *result;
-
- dynstr = BLI_dynstr_new();
-
- /* add .identifier */
- if (path) {
- BLI_dynstr_append(dynstr, path);
- if (*path) {
- BLI_dynstr_append(dynstr, ".");
- }
- }
-
- BLI_dynstr_append(dynstr, RNA_property_identifier(prop));
-
- if (RNA_property_type(prop) == PROP_COLLECTION) {
- /* add ["strkey"] or [intkey] */
- BLI_dynstr_append(dynstr, "[");
-
- if (strkey) {
- const int strkey_esc_max_size = (strlen(strkey) * 2) + 1;
- char *strkey_esc = BLI_array_alloca(strkey_esc, strkey_esc_max_size);
- BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size);
- BLI_dynstr_append(dynstr, "\"");
- BLI_dynstr_append(dynstr, strkey_esc);
- BLI_dynstr_append(dynstr, "\"");
- }
- else {
- char appendstr[128];
- BLI_snprintf(appendstr, sizeof(appendstr), "%d", intkey);
- BLI_dynstr_append(dynstr, appendstr);
- }
-
- BLI_dynstr_append(dynstr, "]");
- }
-
- result = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
-
- return result;
-}
-
-/* Having both path append & back seems like it could be useful,
- * this function isn't used at the moment. */
-static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path)
-{
- char fixedbuf[256];
- const char *previous, *current;
- char *result;
- int i;
-
- if (!path) {
- return NULL;
- }
-
- previous = NULL;
- current = path;
-
- /* parse token by token until the end, then we back up to the previous
- * position and strip of the next token to get the path one step back */
- while (*current) {
- char *token;
-
- token = rna_path_token(&current, fixedbuf, sizeof(fixedbuf));
-
- if (!token) {
- return NULL;
- }
- if (token != fixedbuf) {
- MEM_freeN(token);
- }
-
- /* in case of collection we also need to strip off [] */
- bool quoted;
- token = rna_path_token_in_brackets(&current, fixedbuf, sizeof(fixedbuf), &quoted);
- if (token && token != fixedbuf) {
- MEM_freeN(token);
- }
-
- if (!*current) {
- break;
- }
-
- previous = current;
- }
-
- if (!previous) {
- return NULL;
- }
-
- /* copy and strip off last token */
- i = previous - path;
- result = BLI_strdup(path);
-
- if (i > 0 && result[i - 1] == '.') {
- i--;
- }
- result[i] = 0;
-
- return result;
-}
-
-const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
-{
- if (array_prop != NULL) {
- if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- BLI_assert(array_prop->arraydimension == 0);
- return NULL;
- }
- if (array_prop->arraydimension == 0) {
- return NULL;
- }
- }
-
- /* Valid 'array part' of a rna path can only have '[', ']' and digit characters.
- * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */
- off_t rna_path_len = (off_t)strlen(rna_path);
- if (rna_path[rna_path_len] != ']') {
- return NULL;
- }
- const char *last_valid_index_token_start = NULL;
- for (rna_path_len--; rna_path_len >= 0; rna_path_len--) {
- switch (rna_path[rna_path_len]) {
- case '[':
- if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') {
- return &rna_path[rna_path_len];
- }
- last_valid_index_token_start = &rna_path[rna_path_len];
- rna_path_len--;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- break;
- default:
- return last_valid_index_token_start;
- }
- }
- return last_valid_index_token_start;
-}
-
-/* generic path search func
- * if its needed this could also reference the IDProperty direct */
-typedef struct IDP_Chain {
- struct IDP_Chain *up; /* parent member, reverse and set to child for path conversion. */
-
- const char *name;
- int index;
-
-} IDP_Chain;
-
-static char *rna_idp_path_create(IDP_Chain *child_link)
-{
- DynStr *dynstr = BLI_dynstr_new();
- char *path;
- bool is_first = true;
-
- int tot = 0;
- IDP_Chain *link = child_link;
-
- /* reverse the list */
- IDP_Chain *link_prev;
- link_prev = NULL;
- while (link) {
- IDP_Chain *link_next = link->up;
- link->up = link_prev;
- link_prev = link;
- link = link_next;
- tot++;
- }
-
- for (link = link_prev; link; link = link->up) {
- /* pass */
- if (link->index >= 0) {
- BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index);
- }
- else {
- BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name);
- }
-
- is_first = false;
- }
-
- path = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
-
- if (*path == '\0') {
- MEM_freeN(path);
- path = NULL;
- }
-
- return path;
-}
-
-static char *rna_idp_path(PointerRNA *ptr,
- IDProperty *haystack,
- IDProperty *needle,
- IDP_Chain *parent_link)
-{
- char *path = NULL;
- IDP_Chain link;
-
- IDProperty *iter;
- int i;
-
- BLI_assert(haystack->type == IDP_GROUP);
-
- link.up = parent_link;
- /* Always set both name and index, else a stale value might get used. */
- link.name = NULL;
- link.index = -1;
-
- for (i = 0, iter = haystack->data.group.first; iter; iter = iter->next, i++) {
- if (needle == iter) { /* found! */
- link.name = iter->name;
- link.index = -1;
- path = rna_idp_path_create(&link);
- break;
- }
-
- /* Early out in case the IDProperty type cannot contain RNA properties. */
- if (!ELEM(iter->type, IDP_GROUP, IDP_IDPARRAY)) {
- continue;
- }
-
- /* Ensure this is RNA. */
- /* NOTE: `iter` might be a fully user-defined IDProperty (a.k.a. custom data), which name
- * collides with an actual fully static RNA property of the same struct (which would then not
- * be flagged with `PROP_IDPROPERTY`).
- *
- * That case must be ignored here, we only want to deal with runtime RNA properties stored in
- * IDProps.
- *
- * See T84091. */
- PropertyRNA *prop = RNA_struct_find_property(ptr, iter->name);
- if (prop == NULL || (prop->flag & PROP_IDPROPERTY) == 0) {
- continue;
- }
-
- if (iter->type == IDP_GROUP) {
- if (prop->type == PROP_POINTER) {
- PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop);
- if (RNA_pointer_is_null(&child_ptr)) {
- /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL
- * value is perfectly valid. Just means it won't match the searched needle. */
- continue;
- }
-
- link.name = iter->name;
- link.index = -1;
- if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) {
- break;
- }
- }
- }
- else if (iter->type == IDP_IDPARRAY) {
- if (prop->type == PROP_COLLECTION) {
- IDProperty *array = IDP_IDPArray(iter);
- if (needle >= array && needle < (iter->len + array)) { /* found! */
- link.name = iter->name;
- link.index = (int)(needle - array);
- path = rna_idp_path_create(&link);
- break;
- }
- int j;
- link.name = iter->name;
- for (j = 0; j < iter->len; j++, array++) {
- PointerRNA child_ptr;
- if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) {
- if (RNA_pointer_is_null(&child_ptr)) {
- /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case
- * a NULL value is perfectly valid. Just means it won't match the searched needle. */
- continue;
- }
- link.index = j;
- if ((path = rna_idp_path(&child_ptr, array, needle, &link))) {
- break;
- }
- }
- }
- if (path) {
- break;
- }
- }
- }
- }
-
- return path;
-}
-
-char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
-{
- IDProperty *haystack = RNA_struct_idprops(ptr, false);
-
- if (haystack) { /* can fail when called on bones */
- return rna_idp_path(ptr, haystack, needle, NULL);
- }
- return NULL;
-}
-
-static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
-{
- PointerRNA id_ptr;
-
- BLI_assert(ptr->owner_id != NULL);
-
- /* TODO: Support Bones/PoseBones. no pointers stored to the bones from here, only the ID.
- * See example in T25746.
- * Unless this is added only way to find this is to also search
- * all bones and pose bones of an armature or object.
- */
- RNA_id_pointer_create(ptr->owner_id, &id_ptr);
-
- return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data);
-}
-
-ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
-{
- if (r_path) {
- *r_path = "";
- }
-
- if ((id == NULL) || (id->flag & LIB_EMBEDDED_DATA) == 0) {
- return id;
- }
-
- const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
- if (r_path) {
- switch (GS(id->name)) {
- case ID_NT:
- *r_path = "node_tree";
- break;
- case ID_GR:
- *r_path = "collection";
- break;
- default:
- BLI_assert_msg(0, "Missing handling of embedded id type.");
- }
- }
-
- if (id_type->owner_get == NULL) {
- BLI_assert_msg(0, "Missing handling of embedded id type.");
- return id;
- }
- return id_type->owner_get(bmain, id);
-}
-
-static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id)
-{
- if (r_real_id != NULL) {
- *r_real_id = NULL;
- }
-
- const char *prefix;
- ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix);
-
- if (r_real_id != NULL) {
- *r_real_id = real_id;
- }
-
- if (path != NULL) {
- char *new_path = NULL;
-
- if (real_id) {
- if (prefix[0]) {
- new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path);
- }
- else {
- return path;
- }
- }
-
- MEM_freeN(path);
- return new_path;
- }
- return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL;
-}
-
-char *RNA_path_from_ID_to_struct(const PointerRNA *ptr)
-{
- char *ptrpath = NULL;
-
- if (!ptr->owner_id || !ptr->data) {
- return NULL;
- }
-
- if (!RNA_struct_is_ID(ptr->type)) {
- if (ptr->type->path) {
- /* if type has a path to some ID, use it */
- ptrpath = ptr->type->path((PointerRNA *)ptr);
- }
- else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) {
- PointerRNA parentptr;
- PropertyRNA *userprop;
-
- /* find the property in the struct we're nested in that references this struct, and
- * use its identifier as the first part of the path used...
- */
- RNA_id_pointer_create(ptr->owner_id, &parentptr);
- userprop = RNA_struct_find_nested(&parentptr, ptr->type);
-
- if (userprop) {
- ptrpath = BLI_strdup(RNA_property_identifier(userprop));
- }
- else {
- return NULL; /* can't do anything about this case yet... */
- }
- }
- else if (RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
- /* special case, easier to deal with here than in ptr->type->path() */
- return rna_path_from_ID_to_idpgroup(ptr);
- }
- else {
- return NULL;
- }
- }
-
- return ptrpath;
-}
-
-char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real)
-{
- char *path = RNA_path_from_ID_to_struct(ptr);
-
- /* NULL path is valid in that case, when given struct is an ID one... */
- return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real);
-}
-
-static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH],
- const int totdims,
- const int index_dim,
- int index,
- int r_index_multi[RNA_MAX_ARRAY_LENGTH])
-{
- int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1];
- int i = totdims - 1;
- dimsize_step[i + 1] = 1;
- dimsize_step[i] = dimsize[i];
- while (--i != -1) {
- dimsize_step[i] = dimsize[i] * dimsize_step[i + 1];
- }
- while (++i != index_dim) {
- int index_round = index / dimsize_step[i + 1];
- r_index_multi[i] = index_round;
- index -= (index_round * dimsize_step[i + 1]);
- }
- BLI_assert(index == 0);
-}
-
-static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr,
- PropertyRNA *prop,
- int index_dim,
- int index,
- char *index_str,
- int index_str_len)
-{
- int dimsize[RNA_MAX_ARRAY_LENGTH];
- int totdims = RNA_property_array_dimension(ptr, prop, dimsize);
- int index_multi[RNA_MAX_ARRAY_LENGTH];
-
- rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi);
-
- for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) {
- offset += BLI_snprintf_rlen(
- &index_str[offset], index_str_len - offset, "[%d]", index_multi[i]);
- }
-}
-
-char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
- PropertyRNA *prop,
- int index_dim,
- int index)
-{
- const bool is_rna = (prop->magic == RNA_MAGIC);
- const char *propname;
- char *ptrpath, *path;
-
- if (!ptr->owner_id || !ptr->data) {
- return NULL;
- }
-
- /* path from ID to the struct holding this property */
- ptrpath = RNA_path_from_ID_to_struct(ptr);
-
- propname = RNA_property_identifier(prop);
-
- /* support indexing w/ multi-dimensional arrays */
- char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1];
- if (index_dim == 0) {
- index_str[0] = '\0';
- }
- else {
- rna_path_array_multi_string_from_flat_index(
- ptr, prop, index_dim, index, index_str, sizeof(index_str));
- }
-
- if (ptrpath) {
- if (is_rna) {
- path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str);
- }
- else {
- char propname_esc[MAX_IDPROP_NAME * 2];
- BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str);
- }
- MEM_freeN(ptrpath);
- }
- else if (RNA_struct_is_ID(ptr->type)) {
- if (is_rna) {
- path = BLI_sprintfN("%s%s", propname, index_str);
- }
- else {
- char propname_esc[MAX_IDPROP_NAME * 2];
- BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str);
- }
- }
- else {
- path = NULL;
- }
-
- return path;
-}
-
-char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
-{
- return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
-}
-
-char *RNA_path_from_real_ID_to_property_index(Main *bmain,
- const PointerRNA *ptr,
- PropertyRNA *prop,
- int index_dim,
- int index,
- ID **r_real_id)
-{
- char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index);
-
- /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part
- * of the path either. */
- return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
-}
-
-char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
- PropertyRNA *prop,
- const StructRNA *type)
-{
- /* Try to recursively find an "type"'d ancestor,
- * to handle situations where path from ID is not enough. */
- PointerRNA idptr;
- ListBase path_elems = {NULL};
- char *path = NULL;
- char *full_path = RNA_path_from_ID_to_property(ptr, prop);
-
- if (full_path == NULL) {
- return NULL;
- }
-
- RNA_id_pointer_create(ptr->owner_id, &idptr);
-
- if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) {
- PropertyElemRNA *prop_elem;
-
- for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) {
- if (RNA_struct_is_a(prop_elem->ptr.type, type)) {
- char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr);
- if (ref_path) {
- path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */
- MEM_freeN(ref_path);
- }
- break;
- }
- }
-
- BLI_freelistN(&path_elems);
- }
-
- MEM_freeN(full_path);
- return path;
-}
-
-char *RNA_path_full_ID_py(Main *bmain, ID *id)
-{
- const char *path;
- ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path);
-
- if (id_real) {
- id = id_real;
- }
- else {
- path = "";
- }
-
- char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4];
- if (ID_IS_LINKED(id)) {
- int ofs = 0;
- memcpy(lib_filepath_esc, ", \"", 3);
- ofs += 3;
- ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc));
- memcpy(lib_filepath_esc + ofs, "\"", 2);
- }
- else {
- lib_filepath_esc[0] = '\0';
- }
-
- char id_esc[(sizeof(id->name) - 2) * 2];
- BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc));
-
- return BLI_sprintfN("bpy.data.%s[\"%s\"%s]%s%s",
- BKE_idtype_idcode_to_name_plural(GS(id->name)),
- id_esc,
- lib_filepath_esc,
- path[0] ? "." : "",
- path);
-}
-
-char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr)
-{
- char *id_path;
- char *data_path;
-
- char *ret;
-
- if (!ptr->owner_id) {
- return NULL;
- }
-
- /* never fails */
- id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
-
- data_path = RNA_path_from_ID_to_struct(ptr);
-
- /* XXX data_path may be NULL (see T36788),
- * do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */
- ret = BLI_sprintfN("%s.%s", id_path, data_path);
-
- if (data_path) {
- MEM_freeN(data_path);
- }
- MEM_freeN(id_path);
-
- return ret;
-}
-
-char *RNA_path_full_property_py_ex(
- Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
-{
- char *id_path;
- const char *data_delim;
- const char *data_path;
- bool data_path_free;
-
- char *ret;
-
- if (!ptr->owner_id) {
- return NULL;
- }
-
- /* never fails */
- id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
-
- data_path = RNA_path_from_ID_to_property(ptr, prop);
- if (data_path) {
- data_delim = (data_path[0] == '[') ? "" : ".";
- data_path_free = true;
- }
- else {
- if (use_fallback) {
- /* Fuzzy fallback. Be explicit in our ignorance. */
- data_path = RNA_property_identifier(prop);
- data_delim = " ... ";
- }
- else {
- data_delim = ".";
- }
- data_path_free = false;
- }
-
- if ((index == -1) || (RNA_property_array_check(prop) == false)) {
- ret = BLI_sprintfN("%s%s%s", id_path, data_delim, data_path);
- }
- else {
- ret = BLI_sprintfN("%s%s%s[%d]", id_path, data_delim, data_path, index);
- }
- MEM_freeN(id_path);
- if (data_path_free) {
- MEM_freeN((void *)data_path);
- }
-
- return ret;
-}
-
-char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index)
-{
- return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
-}
-
-char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
-{
- char *data_path;
-
- char *ret;
-
- if (!ptr->owner_id) {
- return NULL;
- }
-
- data_path = RNA_path_from_ID_to_property(ptr, prop);
-
- if (data_path == NULL) {
- /* This may not be an ID at all, check for simple when pointer owns property.
- * TODO: more complex nested case. */
- if (!RNA_struct_is_ID(ptr->type)) {
- const char *prop_identifier = RNA_property_identifier(prop);
- if (RNA_struct_find_property(ptr, prop_identifier) == prop) {
- data_path = BLI_strdup(prop_identifier);
- }
- }
- }
-
- if ((index == -1) || (RNA_property_array_check(prop) == false)) {
- ret = BLI_strdup(data_path);
- }
- else {
- ret = BLI_sprintfN("%s[%d]", data_path, index);
- }
-
- if (data_path) {
- MEM_freeN(data_path);
- }
-
- return ret;
-}
-
-char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index)
-{
- const bool is_rna = (prop->magic == RNA_MAGIC);
- const char *propname = RNA_property_identifier(prop);
- char *ret;
-
- if ((index == -1) || (RNA_property_array_check(prop) == false)) {
- if (is_rna) {
- ret = BLI_strdup(propname);
- }
- else {
- char propname_esc[MAX_IDPROP_NAME * 2];
- BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
- ret = BLI_sprintfN("[\"%s\"]", propname_esc);
- }
- }
- else {
- if (is_rna) {
- ret = BLI_sprintfN("%s[%d]", propname, index);
- }
- else {
- char propname_esc[MAX_IDPROP_NAME * 2];
- BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
- ret = BLI_sprintfN("[\"%s\"][%d]", propname_esc, index);
- }
- }
-
- return ret;
-}
-
/* Quick name based property access */
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 17c00923efa..d1df54df3cd 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -38,6 +38,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "rna_access_internal.h"
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
index a7dd35af670..384ff417fc9 100644
--- a/source/blender/makesrna/intern/rna_access_internal.h
+++ b/source/blender/makesrna/intern/rna_access_internal.h
@@ -10,6 +10,10 @@
#include "rna_internal_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct IDProperty;
struct PropertyRNAOrID;
@@ -26,3 +30,9 @@ void rna_property_rna_or_id_get(PropertyRNA *prop,
void rna_idproperty_touch(struct IDProperty *idprop);
struct IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name);
+
+PropertyRNA *rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 92cdcc6d781..2a85da42483 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -23,6 +23,7 @@
#ifdef RNA_RUNTIME
# include "RNA_access.h"
+# include "RNA_path.h"
# include "DNA_image_types.h"
# include "DNA_material_types.h"
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 833060e40f8..370455302b6 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -14,6 +14,10 @@
#include "UI_resources.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define RNA_MAGIC ((int)~0)
struct AssetLibraryReference;
@@ -691,3 +695,7 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
: -FLT_MAX, double \
: -DBL_MAX)
#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesrna/intern/rna_path.cc b/source/blender/makesrna/intern/rna_path.cc
new file mode 100644
index 00000000000..3e0fc9add80
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_path.cc
@@ -0,0 +1,1360 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#include <cstdlib>
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_idprop.h"
+#include "BKE_idtype.h"
+
+#include "DNA_ID.h" /* For ID properties. */
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_path.h"
+#include "RNA_prototypes.h"
+
+#include "rna_access_internal.h"
+#include "rna_internal.h"
+
+/**
+ * Extract the first token from `path`.
+ *
+ * \param path: Extract the token from path, step the pointer to the beginning of the next token
+ * \return The nil terminated token.
+ */
+static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen)
+{
+ int len = 0;
+
+ /* Get data until `.` or `[`. */
+ const char *p = *path;
+ while (*p && !ELEM(*p, '.', '[')) {
+ len++;
+ p++;
+ }
+
+ /* Empty, return. */
+ if (UNLIKELY(len == 0)) {
+ return NULL;
+ }
+
+ /* Try to use fixed buffer if possible. */
+ char *buf = (len + 1 < fixedlen) ? fixedbuf :
+ (char *)MEM_mallocN(sizeof(char) * (len + 1), __func__);
+ memcpy(buf, *path, sizeof(char) * len);
+ buf[len] = '\0';
+
+ if (*p == '.') {
+ p++;
+ }
+ *path = p;
+
+ return buf;
+}
+
+/**
+ * Extract the first token in brackets from `path` (with quoted text support).
+ *
+ * - `[0]` -> `0`
+ * - `["Some\"Quote"]` -> `Some"Quote`
+ *
+ * \param path: Extract the token from path, step the pointer to the beginning of the next token
+ * (past quoted text and brackets).
+ * \return The nil terminated token.
+ */
+static char *rna_path_token_in_brackets(const char **path,
+ char *fixedbuf,
+ int fixedlen,
+ bool *r_quoted)
+{
+ int len = 0;
+ bool quoted = false;
+
+ BLI_assert(r_quoted != NULL);
+
+ /* Get data between `[]`, check escaping quotes and back-slashes with #BLI_str_unescape. */
+ if (UNLIKELY(**path != '[')) {
+ return NULL;
+ }
+
+ (*path)++;
+ const char *p = *path;
+
+ /* 2 kinds of look-ups now, quoted or unquoted. */
+ if (*p == '"') {
+ /* Find the matching quote. */
+ (*path)++;
+ p = *path;
+ const char *p_end = BLI_str_escape_find_quote(p);
+ if (p_end == NULL) {
+ /* No Matching quote. */
+ return NULL;
+ }
+ /* Exclude the last quote from the length. */
+ len += (p_end - p);
+
+ /* Skip the last quoted char to get the `]`. */
+ p_end += 1;
+ p = p_end;
+ quoted = true;
+ }
+ else {
+ /* Find the matching bracket. */
+ while (*p && (*p != ']')) {
+ len++;
+ p++;
+ }
+ }
+
+ if (UNLIKELY(*p != ']')) {
+ return NULL;
+ }
+
+ /* Empty, return. */
+ if (UNLIKELY(len == 0)) {
+ return NULL;
+ }
+
+ /* Try to use fixed buffer if possible. */
+ char *buf = (len + 1 < fixedlen) ? fixedbuf :
+ (char *)MEM_mallocN(sizeof(char) * (len + 1), __func__);
+
+ /* Copy string, taking into account escaped ']' */
+ if (quoted) {
+ BLI_str_unescape(buf, *path, len);
+ /* +1 to step over the last quote. */
+ BLI_assert((*path)[len] == '"');
+ p = (*path) + len + 1;
+ }
+ else {
+ memcpy(buf, *path, sizeof(char) * len);
+ buf[len] = '\0';
+ }
+ /* Set path to start of next token. */
+ if (*p == ']') {
+ p++;
+ }
+ if (*p == '.') {
+ p++;
+ }
+ *path = p;
+
+ *r_quoted = quoted;
+
+ return buf;
+}
+
+/**
+ * \return true when the key in the path is correctly parsed and found in the collection
+ * or when the path is empty.
+ */
+static bool rna_path_parse_collection_key(const char **path,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ PointerRNA *r_nextptr)
+{
+ char fixedbuf[256];
+ int intkey;
+
+ *r_nextptr = *ptr;
+
+ /* end of path, ok */
+ if (!(**path)) {
+ return true;
+ }
+
+ bool found = false;
+ if (**path == '[') {
+ bool quoted;
+ char *token;
+
+ /* resolve the lookup with [] brackets */
+ token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), &quoted);
+
+ if (!token) {
+ return false;
+ }
+
+ /* check for "" to see if it is a string */
+ if (quoted) {
+ if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) {
+ found = true;
+ }
+ else {
+ r_nextptr->data = NULL;
+ }
+ }
+ else {
+ /* otherwise do int lookup */
+ intkey = atoi(token);
+ if (intkey == 0 && (token[0] != '0' || token[1] != '\0')) {
+ return false; /* we can be sure the fixedbuf was used in this case */
+ }
+ if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) {
+ found = true;
+ }
+ else {
+ r_nextptr->data = NULL;
+ }
+ }
+
+ if (token != fixedbuf) {
+ MEM_freeN(token);
+ }
+ }
+ else {
+ if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) {
+ found = true;
+ }
+ else {
+ /* ensure we quit on invalid values */
+ r_nextptr->data = NULL;
+ }
+ }
+
+ return found;
+}
+
+static bool rna_path_parse_array_index(const char **path,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int *r_index)
+{
+ char fixedbuf[256];
+ int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0};
+ int len[RNA_MAX_ARRAY_DIMENSION];
+ const int dim = RNA_property_array_dimension(ptr, prop, len);
+ int i;
+
+ *r_index = -1;
+
+ /* end of path, ok */
+ if (!(**path)) {
+ return true;
+ }
+
+ for (i = 0; i < dim; i++) {
+ int temp_index = -1;
+ char *token;
+
+ /* multi index resolve */
+ if (**path == '[') {
+ bool quoted;
+ token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), &quoted);
+
+ if (token == NULL) {
+ /* invalid syntax blah[] */
+ return false;
+ }
+ /* check for "" to see if it is a string */
+ if (quoted) {
+ temp_index = RNA_property_array_item_index(prop, *token);
+ }
+ else {
+ /* otherwise do int lookup */
+ temp_index = atoi(token);
+
+ if (temp_index == 0 && (token[0] != '0' || token[1] != '\0')) {
+ if (token != fixedbuf) {
+ MEM_freeN(token);
+ }
+
+ return false;
+ }
+ }
+ }
+ else if (dim == 1) {
+ /* location.x || scale.X, single dimension arrays only */
+ token = rna_path_token(path, fixedbuf, sizeof(fixedbuf));
+ if (token == NULL) {
+ /* invalid syntax blah. */
+ return false;
+ }
+ temp_index = RNA_property_array_item_index(prop, *token);
+ }
+ else {
+ /* just to avoid uninitialized pointer use */
+ token = fixedbuf;
+ }
+
+ if (token != fixedbuf) {
+ MEM_freeN(token);
+ }
+
+ /* out of range */
+ if (temp_index < 0 || temp_index >= len[i]) {
+ return false;
+ }
+
+ index_arr[i] = temp_index;
+ /* end multi index resolve */
+ }
+
+ /* arrays always contain numbers so further values are not valid */
+ if (**path) {
+ return false;
+ }
+
+ /* flatten index over all dimensions */
+ {
+ int totdim = 1;
+ int flat_index = 0;
+
+ for (i = dim - 1; i >= 0; i--) {
+ flat_index += index_arr[i] * totdim;
+ totdim *= len[i];
+ }
+
+ *r_index = flat_index;
+ }
+ return true;
+}
+
+/**
+ * Generic rna path parser.
+ *
+ * \note All parameters besides \a ptr and \a path are optional.
+ *
+ * \param ptr: The root of given RNA path.
+ * \param path: The RNA path.
+ * \param r_ptr: The final RNA data holding the last property in \a path.
+ * \param r_prop: The final property of \a r_ptr, from \a path.
+ * \param r_index: The final index in the \a r_prop, if defined by \a path.
+ * \param r_item_ptr: Only valid for Pointer and Collection, return the actual value of the
+ * pointer, or of the collection item.
+ * Mutually exclusive with \a eval_pointer option.
+ * \param r_elements: A list of \a PropertyElemRNA items(pairs of \a PointerRNA, \a PropertyRNA
+ * that represent the whole given \a path).
+ * \param eval_pointer: If \a true, and \a path leads to a Pointer property, or an item in a
+ * Collection property, \a r_ptr will be set to the value of that property,
+ * and \a r_prop will be NULL.
+ * Mutually exclusive with \a r_item_ptr.
+ *
+ * \return \a true on success, \a false if the path is somehow invalid.
+ */
+static bool rna_path_parse(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index,
+ PointerRNA *r_item_ptr,
+ ListBase *r_elements,
+ const bool eval_pointer)
+{
+ BLI_assert(r_item_ptr == NULL || !eval_pointer);
+ PropertyRNA *prop;
+ PointerRNA curptr, nextptr;
+ PropertyElemRNA *prop_elem = NULL;
+ int index = -1;
+ char fixedbuf[256];
+ int type;
+ const bool do_item_ptr = r_item_ptr != NULL && !eval_pointer;
+
+ if (do_item_ptr) {
+ RNA_POINTER_INVALIDATE(&nextptr);
+ }
+
+ prop = NULL;
+ curptr = *ptr;
+
+ if (path == NULL || *path == '\0') {
+ return false;
+ }
+
+ while (*path) {
+ if (do_item_ptr) {
+ RNA_POINTER_INVALIDATE(&nextptr);
+ }
+
+ const bool use_id_prop = (*path == '[');
+ /* custom property lookup ?
+ * C.object["someprop"]
+ */
+
+ if (!curptr.data) {
+ return false;
+ }
+
+ /* look up property name in current struct */
+ bool quoted = false;
+ char *token = use_id_prop ?
+ rna_path_token_in_brackets(&path, fixedbuf, sizeof(fixedbuf), &quoted) :
+ rna_path_token(&path, fixedbuf, sizeof(fixedbuf));
+ if (!token) {
+ return false;
+ }
+
+ prop = NULL;
+ if (use_id_prop) { /* look up property name in current struct */
+ IDProperty *group = RNA_struct_idprops(&curptr, 0);
+ if (group && quoted) {
+ prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, token);
+ }
+ }
+ else {
+ prop = RNA_struct_find_property(&curptr, token);
+ }
+
+ if (token != fixedbuf) {
+ MEM_freeN(token);
+ }
+
+ if (!prop) {
+ return false;
+ }
+
+ if (r_elements) {
+ prop_elem = MEM_cnew<PropertyElemRNA>(__func__);
+ prop_elem->ptr = curptr;
+ prop_elem->prop = prop;
+ prop_elem->index = -1; /* index will be added later, if needed. */
+ BLI_addtail(r_elements, prop_elem);
+ }
+
+ type = RNA_property_type(prop);
+
+ /* now look up the value of this property if it is a pointer or
+ * collection, otherwise return the property rna so that the
+ * caller can read the value of the property itself */
+ switch (type) {
+ case PROP_POINTER: {
+ /* resolve pointer if further path elements follow
+ * or explicitly requested
+ */
+ if (do_item_ptr || eval_pointer || *path != '\0') {
+ nextptr = RNA_property_pointer_get(&curptr, prop);
+ }
+
+ if (eval_pointer || *path != '\0') {
+ curptr = nextptr;
+ prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
+ index = -1;
+ }
+ break;
+ }
+ case PROP_COLLECTION: {
+ /* Resolve pointer if further path elements follow.
+ * Note that if path is empty, rna_path_parse_collection_key will do nothing anyway,
+ * so do_item_ptr is of no use in that case.
+ */
+ if (*path) {
+ if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) {
+ return false;
+ }
+
+ if (eval_pointer || *path != '\0') {
+ curptr = nextptr;
+ prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
+ index = -1;
+ }
+ }
+ break;
+ }
+ default:
+ if (r_index || prop_elem) {
+ if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) {
+ return false;
+ }
+
+ if (prop_elem) {
+ prop_elem->index = index;
+ }
+ }
+ break;
+ }
+ }
+
+ if (r_ptr) {
+ *r_ptr = curptr;
+ }
+ if (r_prop) {
+ *r_prop = prop;
+ }
+ if (r_index) {
+ *r_index = index;
+ }
+ if (r_item_ptr && do_item_ptr) {
+ *r_item_ptr = nextptr;
+ }
+
+ if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop ||
+ prop_elem->index != index)) {
+ prop_elem = MEM_cnew<PropertyElemRNA>(__func__);
+ prop_elem->ptr = curptr;
+ prop_elem->prop = prop;
+ prop_elem->index = index;
+ BLI_addtail(r_elements, prop_elem);
+ }
+
+ return true;
+}
+
+bool RNA_path_resolve(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
+ return false;
+ }
+
+ return r_ptr->data != NULL;
+}
+
+bool RNA_path_resolve_full(
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) {
+ return false;
+ }
+
+ return r_ptr->data != NULL;
+}
+
+bool RNA_path_resolve_full_maybe_null(
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+ return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
+}
+
+bool RNA_path_resolve_property(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, false)) {
+ return false;
+ }
+
+ return r_ptr->data != NULL && *r_prop != NULL;
+}
+
+bool RNA_path_resolve_property_full(
+ const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) {
+ return false;
+ }
+
+ return r_ptr->data != NULL && *r_prop != NULL;
+}
+
+bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ PointerRNA *r_item_ptr)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, r_item_ptr, NULL, false)) {
+ return false;
+ }
+
+ return r_ptr->data != NULL && *r_prop != NULL;
+}
+
+bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr,
+ const char *path,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index,
+ PointerRNA *r_item_ptr)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, NULL, false)) {
+ return false;
+ }
+
+ return r_ptr->data != NULL && *r_prop != NULL;
+}
+bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
+{
+ return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
+}
+
+char *RNA_path_append(const char *path,
+ const PointerRNA *UNUSED(ptr),
+ PropertyRNA *prop,
+ int intkey,
+ const char *strkey)
+{
+ DynStr *dynstr;
+ char *result;
+
+ dynstr = BLI_dynstr_new();
+
+ /* add .identifier */
+ if (path) {
+ BLI_dynstr_append(dynstr, path);
+ if (*path) {
+ BLI_dynstr_append(dynstr, ".");
+ }
+ }
+
+ BLI_dynstr_append(dynstr, RNA_property_identifier(prop));
+
+ if (RNA_property_type(prop) == PROP_COLLECTION) {
+ /* add ["strkey"] or [intkey] */
+ BLI_dynstr_append(dynstr, "[");
+
+ if (strkey) {
+ const int strkey_esc_max_size = (strlen(strkey) * 2) + 1;
+ char *strkey_esc = BLI_array_alloca(strkey_esc, strkey_esc_max_size);
+ BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size);
+ BLI_dynstr_append(dynstr, "\"");
+ BLI_dynstr_append(dynstr, strkey_esc);
+ BLI_dynstr_append(dynstr, "\"");
+ }
+ else {
+ char appendstr[128];
+ BLI_snprintf(appendstr, sizeof(appendstr), "%d", intkey);
+ BLI_dynstr_append(dynstr, appendstr);
+ }
+
+ BLI_dynstr_append(dynstr, "]");
+ }
+
+ result = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+
+ return result;
+}
+
+/* Having both path append & back seems like it could be useful,
+ * this function isn't used at the moment. */
+static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path)
+{
+ char fixedbuf[256];
+ const char *previous, *current;
+ char *result;
+ int i;
+
+ if (!path) {
+ return NULL;
+ }
+
+ previous = NULL;
+ current = path;
+
+ /* parse token by token until the end, then we back up to the previous
+ * position and strip of the next token to get the path one step back */
+ while (*current) {
+ char *token;
+
+ token = rna_path_token(&current, fixedbuf, sizeof(fixedbuf));
+
+ if (!token) {
+ return NULL;
+ }
+ if (token != fixedbuf) {
+ MEM_freeN(token);
+ }
+
+ /* in case of collection we also need to strip off [] */
+ bool quoted;
+ token = rna_path_token_in_brackets(&current, fixedbuf, sizeof(fixedbuf), &quoted);
+ if (token && token != fixedbuf) {
+ MEM_freeN(token);
+ }
+
+ if (!*current) {
+ break;
+ }
+
+ previous = current;
+ }
+
+ if (!previous) {
+ return NULL;
+ }
+
+ /* copy and strip off last token */
+ i = previous - path;
+ result = BLI_strdup(path);
+
+ if (i > 0 && result[i - 1] == '.') {
+ i--;
+ }
+ result[i] = 0;
+
+ return result;
+}
+
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
+{
+ if (array_prop != NULL) {
+ if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ BLI_assert(array_prop->arraydimension == 0);
+ return NULL;
+ }
+ if (array_prop->arraydimension == 0) {
+ return NULL;
+ }
+ }
+
+ /* Valid 'array part' of a rna path can only have '[', ']' and digit characters.
+ * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */
+ off_t rna_path_len = (off_t)strlen(rna_path);
+ if (rna_path[rna_path_len] != ']') {
+ return NULL;
+ }
+ const char *last_valid_index_token_start = NULL;
+ for (rna_path_len--; rna_path_len >= 0; rna_path_len--) {
+ switch (rna_path[rna_path_len]) {
+ case '[':
+ if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') {
+ return &rna_path[rna_path_len];
+ }
+ last_valid_index_token_start = &rna_path[rna_path_len];
+ rna_path_len--;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ return last_valid_index_token_start;
+ }
+ }
+ return last_valid_index_token_start;
+}
+
+/* generic path search func
+ * if its needed this could also reference the IDProperty direct */
+typedef struct IDP_Chain {
+ struct IDP_Chain *up; /* parent member, reverse and set to child for path conversion. */
+
+ const char *name;
+ int index;
+
+} IDP_Chain;
+
+static char *rna_idp_path_create(IDP_Chain *child_link)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *path;
+ bool is_first = true;
+
+ int tot = 0;
+ IDP_Chain *link = child_link;
+
+ /* reverse the list */
+ IDP_Chain *link_prev;
+ link_prev = NULL;
+ while (link) {
+ IDP_Chain *link_next = link->up;
+ link->up = link_prev;
+ link_prev = link;
+ link = link_next;
+ tot++;
+ }
+
+ for (link = link_prev; link; link = link->up) {
+ /* pass */
+ if (link->index >= 0) {
+ BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index);
+ }
+ else {
+ BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name);
+ }
+
+ is_first = false;
+ }
+
+ path = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+
+ if (*path == '\0') {
+ MEM_freeN(path);
+ path = NULL;
+ }
+
+ return path;
+}
+
+static char *rna_idp_path(PointerRNA *ptr,
+ IDProperty *haystack,
+ IDProperty *needle,
+ IDP_Chain *parent_link)
+{
+ char *path = NULL;
+ IDP_Chain link;
+
+ IDProperty *iter;
+ int i;
+
+ BLI_assert(haystack->type == IDP_GROUP);
+
+ link.up = parent_link;
+ /* Always set both name and index, else a stale value might get used. */
+ link.name = NULL;
+ link.index = -1;
+
+ for (i = 0, iter = reinterpret_cast<IDProperty *>(haystack->data.group.first); iter;
+ iter = iter->next, i++) {
+ if (needle == iter) { /* found! */
+ link.name = iter->name;
+ link.index = -1;
+ path = rna_idp_path_create(&link);
+ break;
+ }
+
+ /* Early out in case the IDProperty type cannot contain RNA properties. */
+ if (!ELEM(iter->type, IDP_GROUP, IDP_IDPARRAY)) {
+ continue;
+ }
+
+ /* Ensure this is RNA. */
+ /* NOTE: `iter` might be a fully user-defined IDProperty (a.k.a. custom data), which name
+ * collides with an actual fully static RNA property of the same struct (which would then not
+ * be flagged with `PROP_IDPROPERTY`).
+ *
+ * That case must be ignored here, we only want to deal with runtime RNA properties stored in
+ * IDProps.
+ *
+ * See T84091. */
+ PropertyRNA *prop = RNA_struct_find_property(ptr, iter->name);
+ if (prop == NULL || (prop->flag & PROP_IDPROPERTY) == 0) {
+ continue;
+ }
+
+ if (iter->type == IDP_GROUP) {
+ if (prop->type == PROP_POINTER) {
+ PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop);
+ if (RNA_pointer_is_null(&child_ptr)) {
+ /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL
+ * value is perfectly valid. Just means it won't match the searched needle. */
+ continue;
+ }
+
+ link.name = iter->name;
+ link.index = -1;
+ if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) {
+ break;
+ }
+ }
+ }
+ else if (iter->type == IDP_IDPARRAY) {
+ if (prop->type == PROP_COLLECTION) {
+ IDProperty *array = IDP_IDPArray(iter);
+ if (needle >= array && needle < (iter->len + array)) { /* found! */
+ link.name = iter->name;
+ link.index = (int)(needle - array);
+ path = rna_idp_path_create(&link);
+ break;
+ }
+ int j;
+ link.name = iter->name;
+ for (j = 0; j < iter->len; j++, array++) {
+ PointerRNA child_ptr;
+ if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) {
+ if (RNA_pointer_is_null(&child_ptr)) {
+ /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case
+ * a NULL value is perfectly valid. Just means it won't match the searched needle. */
+ continue;
+ }
+ link.index = j;
+ if ((path = rna_idp_path(&child_ptr, array, needle, &link))) {
+ break;
+ }
+ }
+ }
+ if (path) {
+ break;
+ }
+ }
+ }
+ }
+
+ return path;
+}
+
+char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
+{
+ IDProperty *haystack = RNA_struct_idprops(ptr, false);
+
+ if (haystack) { /* can fail when called on bones */
+ return rna_idp_path(ptr, haystack, needle, NULL);
+ }
+ return NULL;
+}
+
+static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
+{
+ PointerRNA id_ptr;
+
+ BLI_assert(ptr->owner_id != NULL);
+
+ /* TODO: Support Bones/PoseBones. no pointers stored to the bones from here, only the ID.
+ * See example in T25746.
+ * Unless this is added only way to find this is to also search
+ * all bones and pose bones of an armature or object.
+ */
+ RNA_id_pointer_create(ptr->owner_id, &id_ptr);
+
+ return RNA_path_from_struct_to_idproperty(&id_ptr, reinterpret_cast<IDProperty *>(ptr->data));
+}
+
+ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
+{
+ if (r_path) {
+ *r_path = "";
+ }
+
+ if ((id == NULL) || (id->flag & LIB_EMBEDDED_DATA) == 0) {
+ return id;
+ }
+
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+ if (r_path) {
+ switch (GS(id->name)) {
+ case ID_NT:
+ *r_path = "node_tree";
+ break;
+ case ID_GR:
+ *r_path = "collection";
+ break;
+ default:
+ BLI_assert_msg(0, "Missing handling of embedded id type.");
+ }
+ }
+
+ if (id_type->owner_get == NULL) {
+ BLI_assert_msg(0, "Missing handling of embedded id type.");
+ return id;
+ }
+ return id_type->owner_get(bmain, id);
+}
+
+static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id)
+{
+ if (r_real_id != NULL) {
+ *r_real_id = NULL;
+ }
+
+ const char *prefix;
+ ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix);
+
+ if (r_real_id != NULL) {
+ *r_real_id = real_id;
+ }
+
+ if (path != NULL) {
+ char *new_path = NULL;
+
+ if (real_id) {
+ if (prefix[0]) {
+ new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path);
+ }
+ else {
+ return path;
+ }
+ }
+
+ MEM_freeN(path);
+ return new_path;
+ }
+ return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL;
+}
+
+char *RNA_path_from_ID_to_struct(const PointerRNA *ptr)
+{
+ char *ptrpath = NULL;
+
+ if (!ptr->owner_id || !ptr->data) {
+ return NULL;
+ }
+
+ if (!RNA_struct_is_ID(ptr->type)) {
+ if (ptr->type->path) {
+ /* if type has a path to some ID, use it */
+ ptrpath = ptr->type->path((PointerRNA *)ptr);
+ }
+ else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) {
+ PointerRNA parentptr;
+ PropertyRNA *userprop;
+
+ /* find the property in the struct we're nested in that references this struct, and
+ * use its identifier as the first part of the path used...
+ */
+ RNA_id_pointer_create(ptr->owner_id, &parentptr);
+ userprop = rna_struct_find_nested(&parentptr, ptr->type);
+
+ if (userprop) {
+ ptrpath = BLI_strdup(RNA_property_identifier(userprop));
+ }
+ else {
+ return NULL; /* can't do anything about this case yet... */
+ }
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
+ /* special case, easier to deal with here than in ptr->type->path() */
+ return rna_path_from_ID_to_idpgroup(ptr);
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ return ptrpath;
+}
+
+char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real)
+{
+ char *path = RNA_path_from_ID_to_struct(ptr);
+
+ /* NULL path is valid in that case, when given struct is an ID one... */
+ return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real);
+}
+
+static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH],
+ const int totdims,
+ const int index_dim,
+ int index,
+ int r_index_multi[RNA_MAX_ARRAY_LENGTH])
+{
+ int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1];
+ int i = totdims - 1;
+ dimsize_step[i + 1] = 1;
+ dimsize_step[i] = dimsize[i];
+ while (--i != -1) {
+ dimsize_step[i] = dimsize[i] * dimsize_step[i + 1];
+ }
+ while (++i != index_dim) {
+ int index_round = index / dimsize_step[i + 1];
+ r_index_multi[i] = index_round;
+ index -= (index_round * dimsize_step[i + 1]);
+ }
+ BLI_assert(index == 0);
+}
+
+static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index,
+ char *index_str,
+ int index_str_len)
+{
+ int dimsize[RNA_MAX_ARRAY_LENGTH];
+ int totdims = RNA_property_array_dimension(ptr, prop, dimsize);
+ int index_multi[RNA_MAX_ARRAY_LENGTH];
+
+ rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi);
+
+ for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) {
+ offset += BLI_snprintf_rlen(
+ &index_str[offset], index_str_len - offset, "[%d]", index_multi[i]);
+ }
+}
+
+char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index)
+{
+ const bool is_rna = (prop->magic == RNA_MAGIC);
+ const char *propname;
+ char *ptrpath, *path;
+
+ if (!ptr->owner_id || !ptr->data) {
+ return NULL;
+ }
+
+ /* path from ID to the struct holding this property */
+ ptrpath = RNA_path_from_ID_to_struct(ptr);
+
+ propname = RNA_property_identifier(prop);
+
+ /* support indexing w/ multi-dimensional arrays */
+ char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1];
+ if (index_dim == 0) {
+ index_str[0] = '\0';
+ }
+ else {
+ rna_path_array_multi_string_from_flat_index(
+ ptr, prop, index_dim, index, index_str, sizeof(index_str));
+ }
+
+ if (ptrpath) {
+ if (is_rna) {
+ path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str);
+ }
+ else {
+ char propname_esc[MAX_IDPROP_NAME * 2];
+ BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
+ path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str);
+ }
+ MEM_freeN(ptrpath);
+ }
+ else if (RNA_struct_is_ID(ptr->type)) {
+ if (is_rna) {
+ path = BLI_sprintfN("%s%s", propname, index_str);
+ }
+ else {
+ char propname_esc[MAX_IDPROP_NAME * 2];
+ BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
+ path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str);
+ }
+ }
+ else {
+ path = NULL;
+ }
+
+ return path;
+}
+
+char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
+{
+ return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
+}
+
+char *RNA_path_from_real_ID_to_property_index(Main *bmain,
+ const PointerRNA *ptr,
+ PropertyRNA *prop,
+ int index_dim,
+ int index,
+ ID **r_real_id)
+{
+ char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index);
+
+ /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part
+ * of the path either. */
+ return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
+}
+
+char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr,
+ PropertyRNA *prop,
+ const StructRNA *type)
+{
+ /* Try to recursively find an "type"'d ancestor,
+ * to handle situations where path from ID is not enough. */
+ PointerRNA idptr;
+ ListBase path_elems = {NULL};
+ char *path = NULL;
+ char *full_path = RNA_path_from_ID_to_property(ptr, prop);
+
+ if (full_path == NULL) {
+ return NULL;
+ }
+
+ RNA_id_pointer_create(ptr->owner_id, &idptr);
+
+ if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) {
+ LISTBASE_FOREACH_BACKWARD (PropertyElemRNA *, prop_elem, &path_elems) {
+ if (RNA_struct_is_a(prop_elem->ptr.type, type)) {
+ char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr);
+ if (ref_path) {
+ path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */
+ MEM_freeN(ref_path);
+ }
+ break;
+ }
+ }
+
+ BLI_freelistN(&path_elems);
+ }
+
+ MEM_freeN(full_path);
+ return path;
+}
+
+char *RNA_path_full_ID_py(Main *bmain, ID *id)
+{
+ const char *path;
+ ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path);
+
+ if (id_real) {
+ id = id_real;
+ }
+ else {
+ path = "";
+ }
+
+ char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4];
+ if (ID_IS_LINKED(id)) {
+ int ofs = 0;
+ memcpy(lib_filepath_esc, ", \"", 3);
+ ofs += 3;
+ ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc));
+ memcpy(lib_filepath_esc + ofs, "\"", 2);
+ }
+ else {
+ lib_filepath_esc[0] = '\0';
+ }
+
+ char id_esc[(sizeof(id->name) - 2) * 2];
+ BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc));
+
+ return BLI_sprintfN("bpy.data.%s[\"%s\"%s]%s%s",
+ BKE_idtype_idcode_to_name_plural(GS(id->name)),
+ id_esc,
+ lib_filepath_esc,
+ path[0] ? "." : "",
+ path);
+}
+
+char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr)
+{
+ char *id_path;
+ char *data_path;
+
+ char *ret;
+
+ if (!ptr->owner_id) {
+ return NULL;
+ }
+
+ /* never fails */
+ id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
+
+ data_path = RNA_path_from_ID_to_struct(ptr);
+
+ /* XXX data_path may be NULL (see T36788),
+ * do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */
+ ret = BLI_sprintfN("%s.%s", id_path, data_path);
+
+ if (data_path) {
+ MEM_freeN(data_path);
+ }
+ MEM_freeN(id_path);
+
+ return ret;
+}
+
+char *RNA_path_full_property_py_ex(
+ Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
+{
+ char *id_path;
+ const char *data_delim;
+ const char *data_path;
+ bool data_path_free;
+
+ char *ret;
+
+ if (!ptr->owner_id) {
+ return NULL;
+ }
+
+ /* never fails */
+ id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
+
+ data_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (data_path) {
+ data_delim = (data_path[0] == '[') ? "" : ".";
+ data_path_free = true;
+ }
+ else {
+ if (use_fallback) {
+ /* Fuzzy fallback. Be explicit in our ignorance. */
+ data_path = RNA_property_identifier(prop);
+ data_delim = " ... ";
+ }
+ else {
+ data_delim = ".";
+ }
+ data_path_free = false;
+ }
+
+ if ((index == -1) || (RNA_property_array_check(prop) == false)) {
+ ret = BLI_sprintfN("%s%s%s", id_path, data_delim, data_path);
+ }
+ else {
+ ret = BLI_sprintfN("%s%s%s[%d]", id_path, data_delim, data_path, index);
+ }
+ MEM_freeN(id_path);
+ if (data_path_free) {
+ MEM_freeN((void *)data_path);
+ }
+
+ return ret;
+}
+
+char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
+}
+
+char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ char *data_path;
+
+ char *ret;
+
+ if (!ptr->owner_id) {
+ return NULL;
+ }
+
+ data_path = RNA_path_from_ID_to_property(ptr, prop);
+
+ if (data_path == NULL) {
+ /* This may not be an ID at all, check for simple when pointer owns property.
+ * TODO: more complex nested case. */
+ if (!RNA_struct_is_ID(ptr->type)) {
+ const char *prop_identifier = RNA_property_identifier(prop);
+ if (RNA_struct_find_property(ptr, prop_identifier) == prop) {
+ data_path = BLI_strdup(prop_identifier);
+ }
+ }
+ }
+
+ if ((index == -1) || (RNA_property_array_check(prop) == false)) {
+ ret = BLI_strdup(data_path);
+ }
+ else {
+ ret = BLI_sprintfN("%s[%d]", data_path, index);
+ }
+
+ if (data_path) {
+ MEM_freeN(data_path);
+ }
+
+ return ret;
+}
+
+char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index)
+{
+ const bool is_rna = (prop->magic == RNA_MAGIC);
+ const char *propname = RNA_property_identifier(prop);
+ char *ret;
+
+ if ((index == -1) || (RNA_property_array_check(prop) == false)) {
+ if (is_rna) {
+ ret = BLI_strdup(propname);
+ }
+ else {
+ char propname_esc[MAX_IDPROP_NAME * 2];
+ BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
+ ret = BLI_sprintfN("[\"%s\"]", propname_esc);
+ }
+ }
+ else {
+ if (is_rna) {
+ ret = BLI_sprintfN("%s[%d]", propname, index);
+ }
+ else {
+ char propname_esc[MAX_IDPROP_NAME * 2];
+ BLI_str_escape(propname_esc, propname, sizeof(propname_esc));
+ ret = BLI_sprintfN("[\"%s\"][%d]", propname_esc, index);
+ }
+ }
+
+ return ret;
+}
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index dabb89bcd5e..adb959944b5 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -473,7 +473,7 @@ static int rna_UIList_list_id_length(PointerRNA *ptr)
}
static void uilist_draw_item(uiList *ui_list,
- bContext *C,
+ const bContext *C,
uiLayout *layout,
PointerRNA *dataptr,
PointerRNA *itemptr,
@@ -507,7 +507,7 @@ static void uilist_draw_item(uiList *ui_list,
RNA_parameter_list_free(&list);
}
-static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout)
+static void uilist_draw_filter(uiList *ui_list, const bContext *C, uiLayout *layout)
{
extern FunctionRNA rna_UIList_draw_filter_func;
@@ -527,7 +527,7 @@ static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout)
}
static void uilist_filter_items(uiList *ui_list,
- bContext *C,
+ const bContext *C,
PointerRNA *dataptr,
const char *propname)
{
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 223e4b757b7..72978d6410a 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -40,7 +40,7 @@
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_global.h"
-#include "BKE_idprop.h"
+#include "BKE_idprop.hh"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -416,15 +416,16 @@ static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int soc
return field_interface.inputs[socket_index] != InputSocketFieldType::None;
}
-static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
+static std::unique_ptr<IDProperty, blender::bke::idprop::IDPropertyDeleter>
+id_property_create_from_socket(const bNodeSocket &socket)
{
+ using namespace blender;
switch (socket.type) {
case SOCK_FLOAT: {
- bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.f = value->value;
- IDProperty *property = IDP_New(IDP_FLOAT, &idprop, socket.identifier);
- IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property);
+ const bNodeSocketValueFloat *value = static_cast<const bNodeSocketValueFloat *>(
+ socket.default_value);
+ auto property = bke::idprop::create(socket.identifier, value->value);
+ IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
ui_data->base.rna_subtype = value->subtype;
ui_data->min = ui_data->soft_min = (double)value->min;
ui_data->max = ui_data->soft_max = (double)value->max;
@@ -432,11 +433,10 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
return property;
}
case SOCK_INT: {
- bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.i = value->value;
- IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier);
- IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property);
+ const bNodeSocketValueInt *value = static_cast<const bNodeSocketValueInt *>(
+ socket.default_value);
+ auto property = bke::idprop::create(socket.identifier, value->value);
+ IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get());
ui_data->base.rna_subtype = value->subtype;
ui_data->min = ui_data->soft_min = value->min;
ui_data->max = ui_data->soft_max = value->max;
@@ -444,13 +444,11 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
return property;
}
case SOCK_VECTOR: {
- bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.array.len = 3;
- idprop.array.type = IDP_FLOAT;
- IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier);
- copy_v3_v3((float *)IDP_Array(property), value->value);
- IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property);
+ const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>(
+ socket.default_value);
+ auto property = bke::idprop::create(
+ socket.identifier, Span<float>{value->value[0], value->value[1], value->value[2]});
+ IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
ui_data->base.rna_subtype = value->subtype;
ui_data->min = ui_data->soft_min = (double)value->min;
ui_data->max = ui_data->soft_max = (double)value->max;
@@ -462,13 +460,12 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
return property;
}
case SOCK_RGBA: {
- bNodeSocketValueRGBA *value = (bNodeSocketValueRGBA *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.array.len = 4;
- idprop.array.type = IDP_FLOAT;
- IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier);
- copy_v4_v4((float *)IDP_Array(property), value->value);
- IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property);
+ const bNodeSocketValueRGBA *value = static_cast<const bNodeSocketValueRGBA *>(
+ socket.default_value);
+ auto property = bke::idprop::create(
+ socket.identifier,
+ Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]});
+ IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
ui_data->base.rna_subtype = PROP_COLOR;
ui_data->default_array = (double *)MEM_mallocN(sizeof(double[4]), __func__);
ui_data->default_array_len = 4;
@@ -482,53 +479,48 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
return property;
}
case SOCK_BOOLEAN: {
- bNodeSocketValueBoolean *value = (bNodeSocketValueBoolean *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.i = value->value != 0;
- IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier);
- IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property);
+ const bNodeSocketValueBoolean *value = static_cast<const bNodeSocketValueBoolean *>(
+ socket.default_value);
+ auto property = bke::idprop::create(socket.identifier, int(value->value));
+ IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get());
ui_data->min = ui_data->soft_min = 0;
ui_data->max = ui_data->soft_max = 1;
ui_data->default_value = value->value != 0;
return property;
}
case SOCK_STRING: {
- bNodeSocketValueString *value = (bNodeSocketValueString *)socket.default_value;
- IDProperty *property = IDP_NewString(
- value->value, socket.identifier, BLI_strnlen(value->value, sizeof(value->value)) + 1);
- IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure(property);
+ const bNodeSocketValueString *value = static_cast<const bNodeSocketValueString *>(
+ socket.default_value);
+ auto property = bke::idprop::create(socket.identifier, value->value);
+ IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure(
+ property.get());
ui_data->default_value = BLI_strdup(value->value);
return property;
}
case SOCK_OBJECT: {
- bNodeSocketValueObject *value = (bNodeSocketValueObject *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.id = (ID *)value->value;
- return IDP_New(IDP_ID, &idprop, socket.identifier);
+ const bNodeSocketValueObject *value = static_cast<const bNodeSocketValueObject *>(
+ socket.default_value);
+ return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
}
case SOCK_COLLECTION: {
- bNodeSocketValueCollection *value = (bNodeSocketValueCollection *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.id = (ID *)value->value;
- return IDP_New(IDP_ID, &idprop, socket.identifier);
+ const bNodeSocketValueCollection *value = static_cast<const bNodeSocketValueCollection *>(
+ socket.default_value);
+ return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
}
case SOCK_TEXTURE: {
- bNodeSocketValueTexture *value = (bNodeSocketValueTexture *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.id = (ID *)value->value;
- return IDP_New(IDP_ID, &idprop, socket.identifier);
+ const bNodeSocketValueTexture *value = static_cast<const bNodeSocketValueTexture *>(
+ socket.default_value);
+ return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
}
case SOCK_IMAGE: {
- bNodeSocketValueImage *value = (bNodeSocketValueImage *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.id = (ID *)value->value;
- return IDP_New(IDP_ID, &idprop, socket.identifier);
+ const bNodeSocketValueImage *value = static_cast<const bNodeSocketValueImage *>(
+ socket.default_value);
+ return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
}
case SOCK_MATERIAL: {
- bNodeSocketValueMaterial *value = (bNodeSocketValueMaterial *)socket.default_value;
- IDPropertyTemplate idprop = {0};
- idprop.id = (ID *)value->value;
- return IDP_New(IDP_ID, &idprop, socket.identifier);
+ const bNodeSocketValueMaterial *value = static_cast<const bNodeSocketValueMaterial *>(
+ socket.default_value);
+ return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
}
}
return nullptr;
@@ -658,7 +650,7 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
int socket_index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
- IDProperty *new_prop = id_property_create_from_socket(*socket);
+ IDProperty *new_prop = id_property_create_from_socket(*socket).release();
if (new_prop == nullptr) {
/* Out of the set of supported input sockets, only
* geometry sockets aren't added to the modifier. */
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index e43d2b4ad85..5cf4e21ea68 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -1863,6 +1863,7 @@ bool NodeParamsProvider::lazy_require_input(StringRef identifier)
void NodeParamsProvider::set_input_unused(StringRef identifier)
{
+ BLI_assert(node_supports_laziness(this->dnode));
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 32b5d98a556..6efe6f231f5 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -183,6 +183,7 @@ void register_node_tree_type_cmp()
tt->type = NTREE_COMPOSIT;
strcpy(tt->idname, "CompositorNodeTree");
+ strcpy(tt->group_idname, "CompositorNodeGroup");
strcpy(tt->ui_name, N_("Compositor"));
tt->ui_icon = ICON_NODE_COMPOSITING;
strcpy(tt->ui_description, N_("Compositing nodes"));
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 38e914b9a9f..e3998322741 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -109,6 +109,7 @@ void register_node_tree_type_geo()
MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type"));
tt->type = NTREE_GEOMETRY;
strcpy(tt->idname, "GeometryNodeTree");
+ strcpy(tt->group_idname, "GeometryNodeGroup");
strcpy(tt->ui_name, N_("Geometry Node Editor"));
tt->ui_icon = ICON_GEOMETRY_NODES;
strcpy(tt->ui_description, N_("Geometry nodes"));
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index 43dbf5060bd..02ac54f4b2b 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -166,6 +166,7 @@ void register_node_tree_type_sh()
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
+ strcpy(tt->group_idname, "ShaderNodeGroup");
strcpy(tt->ui_name, N_("Shader Editor"));
tt->ui_icon = ICON_NODE_MATERIAL;
strcpy(tt->ui_description, N_("Shader nodes"));
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 03dc61af9a2..ac105b5bcb9 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -140,6 +140,7 @@ void register_node_tree_type_tex(void)
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
+ strcpy(tt->group_idname, "TextureNodeGroup");
strcpy(tt->ui_name, N_("Texture Node Editor"));
tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Texture nodes"));
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 14be9ceda94..d9c004fb6fa 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -15,6 +15,7 @@
#include <float.h> /* FLT_MIN/MAX */
#include <stddef.h>
+#include "RNA_path.h"
#include "RNA_types.h"
#include "BLI_bitmap.h"
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index f25e9d0bbbc..d4a164d9482 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -32,6 +32,7 @@
#include "RNA_access.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 315e4c994ad..1dc2307ba14 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -81,6 +81,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "UI_interface.h"
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
index be153195cee..5c745c32d2c 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -20,6 +20,7 @@
#include "message_bus/intern/wm_message_bus_intern.h"
#include "RNA_access.h"
+#include "RNA_path.h"
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 6c95ee3e490..e7a803d383f 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -41,7 +41,6 @@
#include "BKE_global.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"