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/CMakeLists.txt2
-rw-r--r--build_files/build_environment/cmake/boost.cmake9
-rw-r--r--build_files/build_environment/cmake/embree.cmake2
-rw-r--r--build_files/build_environment/cmake/gmp.cmake26
-rw-r--r--build_files/build_environment/cmake/harvest.cmake6
-rw-r--r--build_files/build_environment/cmake/llvm.cmake2
-rw-r--r--build_files/build_environment/cmake/opencolorio.cmake2
-rw-r--r--build_files/build_environment/cmake/options.cmake8
-rw-r--r--build_files/build_environment/cmake/png.cmake4
-rw-r--r--build_files/build_environment/cmake/sse2neon.cmake22
-rw-r--r--build_files/build_environment/cmake/ssl.cmake4
-rw-r--r--build_files/build_environment/cmake/ssl.conf5
-rw-r--r--build_files/build_environment/cmake/tbb.cmake4
-rw-r--r--build_files/build_environment/cmake/versions.cmake23
-rw-r--r--build_files/build_environment/cmake/x264.cmake18
-rwxr-xr-xbuild_files/build_environment/install_deps.sh23
-rw-r--r--build_files/build_environment/patches/cmakelists_tbb.txt636
-rw-r--r--build_files/build_environment/patches/tbb.diff13
-rw-r--r--build_files/build_environment/patches/theora.diff4
-rw-r--r--build_files/build_environment/patches/usd.diff144
-rw-r--r--build_files/buildbot/buildbot_utils.py4
-rw-r--r--build_files/cmake/Modules/FindEmbree.cmake2
-rw-r--r--build_files/cmake/macros.cmake4
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--doc/python_api/rst/info_gotcha.rst3
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/bvh/bvh.h98
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h19
-rw-r--r--intern/cycles/kernel/bvh/bvh_util.h162
-rw-r--r--intern/cycles/kernel/kernel_path.h17
-rw-r--r--intern/cycles/kernel/kernel_types.h2
-rw-r--r--intern/cycles/render/shader.cpp2
-rw-r--r--intern/cycles/util/util_simd.h8
-rw-r--r--intern/cycles/util/util_sseb.h12
-rw-r--r--intern/cycles/util/util_ssef.h4
-rw-r--r--intern/cycles/util/util_ssei.h13
-rw-r--r--intern/cycles/util/util_system.cpp25
-rw-r--r--release/datafiles/splash.pngbin858406 -> 737984 bytes
-rw-r--r--release/scripts/modules/keyingsets_utils.py34
-rw-r--r--release/scripts/startup/bl_operators/userpref.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py6
-rw-r--r--release/scripts/startup/bl_ui/space_info.py13
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py2
-rw-r--r--release/scripts/startup/keyingsets_builtins.py125
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh312
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh32
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_context.h19
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh243
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh55
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc744
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh230
-rw-r--r--source/blender/blenkernel/intern/blender.c2
-rw-r--r--source/blender/blenkernel/intern/context.c51
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc398
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc59
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc18
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c26
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc158
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/volume.cc74
-rw-r--r--source/blender/blenlib/BLI_compiler_attrs.h7
-rw-r--r--source/blender/blenlib/BLI_map.hh80
-rw-r--r--source/blender/blenlib/BLI_map_slots.hh12
-rw-r--r--source/blender/blenlib/BLI_span.hh14
-rw-r--r--source/blender/blenlib/BLI_stack.hh5
-rw-r--r--source/blender/blenlib/BLI_vector.hh37
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh384
-rw-r--r--source/blender/blenlib/tests/BLI_map_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_stack_cxx_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc133
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/intern/readfile.c2
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c13
-rw-r--r--source/blender/blenloader/intern/versioning_300.c80
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c9
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c90
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c48
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c156
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c26
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c1
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h5
-rw-r--r--source/blender/editors/include/ED_keyframing.h1
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h17
-rw-r--r--source/blender/editors/include/UI_interface.h16
-rw-r--r--source/blender/editors/interface/interface_handlers.c7
-rw-r--r--source/blender/editors/interface/interface_intern.h15
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c8
-rw-r--r--source/blender/editors/io/io_alembic.c23
-rw-r--r--source/blender/editors/io/io_collada.c16
-rw-r--r--source/blender/editors/io/io_gpencil_export.c18
-rw-r--r--source/blender/editors/io/io_gpencil_import.c8
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c49
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c34
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c31
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
-rw-r--r--source/blender/editors/object/object_add.c21
-rw-r--r--source/blender/editors/screen/screen_draw.c303
-rw-r--r--source/blender/editors/screen/screen_edit.c190
-rw-r--r--source/blender/editors/screen/screen_intern.h7
-rw-r--r--source/blender/editors/screen/screen_ops.c215
-rw-r--r--source/blender/editors/screen/screendump.c6
-rw-r--r--source/blender/editors/space_image/image_ops.c66
-rw-r--r--source/blender/editors/space_info/info_stats.c3
-rw-r--r--source/blender/editors/space_info/space_info.c9
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c72
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc43
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.h46
-rw-r--r--source/blender/editors/transform/transform_convert.c177
-rw-r--r--source/blender/editors/transform/transform_convert.h7
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c26
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c6
-rw-r--r--source/blender/editors/transform/transform_convert_mball.c20
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c193
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c28
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/editors/transform/transform_mode.c2
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c1
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c1
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c1
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c1
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c3
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c1
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c1
-rw-r--r--source/blender/editors/transform/transform_snap.c6
-rw-r--r--source/blender/editors/transform/transform_snap_object.c667
-rw-r--r--source/blender/functions/FN_generic_span.hh20
-rw-r--r--source/blender/functions/FN_generic_vector_array.hh6
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh683
-rw-r--r--source/blender/functions/FN_generic_virtual_vector_array.hh16
-rw-r--r--source/blender/functions/FN_multi_function_params.hh10
-rw-r--r--source/blender/functions/intern/generic_vector_array.cc6
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc216
-rw-r--r--source/blender/functions/intern/generic_virtual_vector_array.cc26
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc28
-rw-r--r--source/blender/functions/tests/FN_multi_function_network_test.cc2
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h5
-rw-r--r--source/blender/makesdna/DNA_space_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c30
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c50
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c2
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c189
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh52
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/NOD_type_conversions.hh4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc51
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc89
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc35
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc67
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc145
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc175
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_scale.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_separate.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_translate.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc163
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc56
-rw-r--r--source/blender/nodes/intern/type_conversions.cc112
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c176
-rw-r--r--source/blender/python/intern/CMakeLists.txt2
-rw-r--r--source/blender/python/intern/bpy_interface.c11
-rw-r--r--source/blender/python/intern/bpy_operator.c8
-rw-r--r--source/blender/python/intern/bpy_rna_operator.c150
-rw-r--r--source/blender/python/intern/bpy_rna_operator.h31
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c18
-rw-r--r--source/blender/windowmanager/WM_types.h10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c4
-rw-r--r--source/blender/windowmanager/intern/wm_files.c71
-rw-r--r--source/blender/windowmanager/wm_files.h3
-rw-r--r--source/creator/CMakeLists.txt9
-rw-r--r--source/creator/creator_intern.h2
209 files changed, 6891 insertions, 3896 deletions
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index a3d694b4bc3..fb79eee62be 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -113,7 +113,7 @@ include(cmake/expat.cmake)
include(cmake/yamlcpp.cmake)
include(cmake/opencolorio.cmake)
-if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
+if(BLENDER_PLATFORM_ARM)
include(cmake/sse2neon.cmake)
endif()
diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake
index 8b36af7dc41..5170a3a123e 100644
--- a/build_files/build_environment/cmake/boost.cmake
+++ b/build_files/build_environment/cmake/boost.cmake
@@ -18,6 +18,12 @@
set(BOOST_ADDRESS_MODEL 64)
+if(BLENDER_PLATFORM_ARM)
+ set(BOOST_ARCHITECTURE arm)
+else()
+ set(BOOST_ARCHITECTURE x86)
+endif()
+
if(WIN32)
set(BOOST_TOOLSET toolset=msvc-14.1)
set(BOOST_COMPILER_STRING -vc141)
@@ -29,7 +35,6 @@ if(WIN32)
if(BUILD_MODE STREQUAL Release)
set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-${BOOST_VERSION_NODOTS_SHORT}/ ${HARVEST_TARGET}/boost/include/)
endif()
-
elseif(APPLE)
set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
set(BOOST_BUILD_COMMAND ./b2)
@@ -93,7 +98,7 @@ ExternalProject_Add(external_boost
UPDATE_COMMAND ""
PATCH_COMMAND ${BOOST_PATCH_COMMAND}
CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND}
- BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=x86 address-model=${BOOST_ADDRESS_MODEL} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install
+ BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=${BOOST_ARCHITECTURE} address-model=${BOOST_ADDRESS_MODEL} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install
BUILD_IN_SOURCE 1
INSTALL_COMMAND "${BOOST_HARVEST_CMD}"
)
diff --git a/build_files/build_environment/cmake/embree.cmake b/build_files/build_environment/cmake/embree.cmake
index 4830630def0..cd693d766dc 100644
--- a/build_files/build_environment/cmake/embree.cmake
+++ b/build_files/build_environment/cmake/embree.cmake
@@ -47,7 +47,7 @@ else()
set(EMBREE_BUILD_DIR)
endif()
-if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
+if(BLENDER_PLATFORM_ARM)
ExternalProject_Add(external_embree
GIT_REPOSITORY ${EMBREE_ARM_GIT}
GIT_TAG "blender-arm"
diff --git a/build_files/build_environment/cmake/gmp.cmake b/build_files/build_environment/cmake/gmp.cmake
index 323630a63aa..6ca81678a32 100644
--- a/build_files/build_environment/cmake/gmp.cmake
+++ b/build_files/build_environment/cmake/gmp.cmake
@@ -25,19 +25,12 @@ else()
set(GMP_OPTIONS --enable-static --disable-shared )
endif()
-if(APPLE)
- if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
- set(GMP_OPTIONS
- ${GMP_OPTIONS}
- --disable-assembly
- )
- else()
- set(GMP_OPTIONS
- ${GMP_OPTIONS}
- --with-pic
- )
- endif()
-elseif(UNIX)
+if(APPLE AND NOT BLENDER_PLATFORM_ARM)
+ set(GMP_OPTIONS
+ ${GMP_OPTIONS}
+ --with-pic
+ )
+elseif(UNIX AND NOT APPLE)
set(GMP_OPTIONS
${GMP_OPTIONS}
--with-pic
@@ -45,6 +38,13 @@ elseif(UNIX)
)
endif()
+if(BLENDER_PLATFORM_ARM)
+ set(GMP_OPTIONS
+ ${GMP_OPTIONS}
+ --disable-assembly
+ )
+endif()
+
ExternalProject_Add(external_gmp
URL file://${PACKAGE_DIR}/${GMP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 23d0dcbab7b..fc7e652a028 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -109,9 +109,9 @@ harvest(llvm/lib llvm/lib "libclang*.a")
if(APPLE)
harvest(openmp/lib openmp/lib "*")
harvest(openmp/include openmp/include "*.h")
- if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
- harvest(sse2neon sse2neon "*.h")
- endif()
+endif()
+if(BLENDER_PLATFORM_ARM)
+ harvest(sse2neon sse2neon "*.h")
endif()
harvest(ogg/lib ffmpeg/lib "*.a")
harvest(openal/include openal/include "*.h")
diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake
index f067267a416..cbb986410aa 100644
--- a/build_files/build_environment/cmake/llvm.cmake
+++ b/build_files/build_environment/cmake/llvm.cmake
@@ -16,7 +16,7 @@
#
# ***** END GPL LICENSE BLOCK *****
-if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
+if(BLENDER_PLATFORM_ARM)
set(LLVM_TARGETS AArch64$<SEMICOLON>ARM)
else()
set(LLVM_TARGETS X86)
diff --git a/build_files/build_environment/cmake/opencolorio.cmake b/build_files/build_environment/cmake/opencolorio.cmake
index bd03be5ebff..28c93973cf5 100644
--- a/build_files/build_environment/cmake/opencolorio.cmake
+++ b/build_files/build_environment/cmake/opencolorio.cmake
@@ -36,7 +36,7 @@ set(OPENCOLORIO_EXTRA_ARGS
-Dyaml-cpp_ROOT=${LIBDIR}/yamlcpp
)
-if(APPLE AND NOT("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64"))
+if(BLENDER_PLATFORM_ARM)
set(OPENCOLORIO_EXTRA_ARGS
${OPENCOLORIO_EXTRA_ARGS}
-DOCIO_USE_SSE=OFF
diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake
index 486b3d1a802..8930bd70fab 100644
--- a/build_files/build_environment/cmake/options.cmake
+++ b/build_files/build_environment/cmake/options.cmake
@@ -137,6 +137,10 @@ else()
endif()
set(OSX_SYSROOT ${XCODE_DEV_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk)
+ if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
+ set(BLENDER_PLATFORM_ARM ON)
+ endif()
+
set(PLATFORM_CFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
set(PLATFORM_CXXFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -std=c++11 -stdlib=libc++ -arch ${CMAKE_OSX_ARCHITECTURES}")
set(PLATFORM_LDFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
@@ -151,6 +155,10 @@ else()
-DCMAKE_OSX_SYSROOT:PATH=${OSX_SYSROOT}
)
else()
+ if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64")
+ set(BLENDER_PLATFORM_ARM ON)
+ endif()
+
set(PLATFORM_CFLAGS "-fPIC")
set(PLATFORM_CXXFLAGS "-std=c++11 -fPIC")
set(PLATFORM_LDFLAGS)
diff --git a/build_files/build_environment/cmake/png.cmake b/build_files/build_environment/cmake/png.cmake
index d9248b61c98..458d3a1fd98 100644
--- a/build_files/build_environment/cmake/png.cmake
+++ b/build_files/build_environment/cmake/png.cmake
@@ -22,8 +22,8 @@ set(PNG_EXTRA_ARGS
-DPNG_STATIC=ON
)
-if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
- set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=on -DCMAKE_SYSTEM_PROCESSOR="aarch64")
+if(BLENDER_PLATFORM_ARM)
+ set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=ON -DCMAKE_SYSTEM_PROCESSOR="aarch64")
endif()
ExternalProject_Add(external_png
diff --git a/build_files/build_environment/cmake/sse2neon.cmake b/build_files/build_environment/cmake/sse2neon.cmake
index dca2d94f913..d7987fdfd2f 100644
--- a/build_files/build_environment/cmake/sse2neon.cmake
+++ b/build_files/build_environment/cmake/sse2neon.cmake
@@ -16,15 +16,13 @@
#
# ***** END GPL LICENSE BLOCK *****
-if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
- ExternalProject_Add(external_sse2neon
- GIT_REPOSITORY ${SSE2NEON_GIT}
- GIT_TAG ${SSE2NEON_GIT_HASH}
- DOWNLOAD_DIR ${DOWNLOAD_DIR}
- PREFIX ${BUILD_DIR}/sse2neon
- CONFIGURE_COMMAND echo sse2neon - Nothing to configure
- BUILD_COMMAND echo sse2neon - nothing to build
- INSTALL_COMMAND mkdir -p ${LIBDIR}/sse2neon && cp ${BUILD_DIR}/sse2neon/src/external_sse2neon/sse2neon.h ${LIBDIR}/sse2neon
- INSTALL_DIR ${LIBDIR}/sse2neon
- )
-endif()
+ExternalProject_Add(external_sse2neon
+ GIT_REPOSITORY ${SSE2NEON_GIT}
+ GIT_TAG ${SSE2NEON_GIT_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/sse2neon
+ CONFIGURE_COMMAND echo sse2neon - Nothing to configure
+ BUILD_COMMAND echo sse2neon - nothing to build
+ INSTALL_COMMAND mkdir -p ${LIBDIR}/sse2neon && cp ${BUILD_DIR}/sse2neon/src/external_sse2neon/sse2neon.h ${LIBDIR}/sse2neon
+ INSTALL_DIR ${LIBDIR}/sse2neon
+)
diff --git a/build_files/build_environment/cmake/ssl.cmake b/build_files/build_environment/cmake/ssl.cmake
index 4426cc876c6..615b88167ec 100644
--- a/build_files/build_environment/cmake/ssl.cmake
+++ b/build_files/build_environment/cmake/ssl.cmake
@@ -22,7 +22,9 @@ set(SSL_PATCH_CMD echo .)
if(APPLE)
set(SSL_OS_COMPILER "blender-darwin-${CMAKE_OSX_ARCHITECTURES}")
else()
- if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ if(BLENDER_PLATFORM_ARM)
+ set(SSL_OS_COMPILER "blender-linux-aarch64")
+ elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(SSL_EXTRA_ARGS enable-ec_nistp_64_gcc_128)
set(SSL_OS_COMPILER "blender-linux-x86_64")
else()
diff --git a/build_files/build_environment/cmake/ssl.conf b/build_files/build_environment/cmake/ssl.conf
index 8a9c9dcab4c..fa59bcf2825 100644
--- a/build_files/build_environment/cmake/ssl.conf
+++ b/build_files/build_environment/cmake/ssl.conf
@@ -8,6 +8,11 @@ my %targets = (
inherit_from => [ "linux-x86_64" ],
cflags => add("-fPIC"),
},
+ "blender-linux-aarch64" => {
+ inherit_from => [ "linux-aarch64" ],
+ cxxflags => add("-fPIC"),
+ cflags => add("-fPIC"),
+ },
"blender-darwin-x86_64" => {
inherit_from => [ "darwin64-x86_64-cc" ],
cflags => add("-fPIC"),
diff --git a/build_files/build_environment/cmake/tbb.cmake b/build_files/build_environment/cmake/tbb.cmake
index b006898e6fd..44307cd2afb 100644
--- a/build_files/build_environment/cmake/tbb.cmake
+++ b/build_files/build_environment/cmake/tbb.cmake
@@ -21,6 +21,7 @@ if(WIN32)
-DTBB_BUILD_TBBMALLOC=On
-DTBB_BUILD_TBBMALLOC_PROXY=On
-DTBB_BUILD_STATIC=Off
+ -DTBB_BUILD_TESTS=Off
)
set(TBB_LIBRARY tbb)
set(TBB_STATIC_LIBRARY Off)
@@ -30,6 +31,7 @@ else()
-DTBB_BUILD_TBBMALLOC=On
-DTBB_BUILD_TBBMALLOC_PROXY=Off
-DTBB_BUILD_STATIC=On
+ -DTBB_BUILD_TESTS=Off
)
set(TBB_LIBRARY tbb_static)
set(TBB_STATIC_LIBRARY On)
@@ -42,7 +44,7 @@ ExternalProject_Add(external_tbb
URL_HASH ${TBB_HASH_TYPE}=${TBB_HASH}
PREFIX ${BUILD_DIR}/tbb
PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_tbb.txt ${BUILD_DIR}/tbb/src/external_tbb/CMakeLists.txt &&
- ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2013/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/src/tbb/version_string.ver &&
+ ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2013/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/build/version_string.ver.in &&
${PATCH_CMD} -p 1 -d ${BUILD_DIR}/tbb/src/external_tbb < ${PATCH_DIR}/tbb.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tbb ${DEFAULT_CMAKE_FLAGS} ${TBB_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/tbb
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 97da5d54d48..83e438614b6 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -152,7 +152,7 @@ set(OPENCOLORIO_HASH 1a2e3478b6cd9a1549f24e1b2205e3f0)
set(OPENCOLORIO_HASH_TYPE MD5)
set(OPENCOLORIO_FILE OpenColorIO-${OPENCOLORIO_VERSION}.tar.gz)
-if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
+if(BLENDER_PLATFORM_ARM)
# Newer version required by ISPC with arm support.
set(LLVM_VERSION 11.0.1)
set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz)
@@ -398,11 +398,20 @@ set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df)
set(LZMA_HASH_TYPE SHA256)
set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2)
-set(SSL_VERSION 1.1.1g)
-set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
-set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46)
-set(SSL_HASH_TYPE SHA256)
-set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
+if(BLENDER_PLATFORM_ARM)
+ # Need at least 1.1.1i for aarch64 support (https://github.com/openssl/openssl/pull/13218)
+ set(SSL_VERSION 1.1.1i)
+ set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
+ set(SSL_HASH e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242)
+ set(SSL_HASH_TYPE SHA256)
+ set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
+else()
+ set(SSL_VERSION 1.1.1g)
+ set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
+ set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46)
+ set(SSL_HASH_TYPE SHA256)
+ set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
+endif()
set(SQLITE_VERSION 3.31.1)
set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip)
@@ -453,7 +462,7 @@ set(XR_OPENXR_SDK_HASH 0df6b2fd6045423451a77ff6bc3e1a75)
set(XR_OPENXR_SDK_HASH_TYPE MD5)
set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz)
-if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
+if(BLENDER_PLATFORM_ARM)
# Unreleased version with macOS arm support.
set(ISPC_URI https://github.com/ispc/ispc/archive/f5949c055eb9eeb93696978a3da4bfb3a6a30b35.zip)
set(ISPC_HASH d382fea18d01dbd0cd05d9e1ede36d7d)
diff --git a/build_files/build_environment/cmake/x264.cmake b/build_files/build_environment/cmake/x264.cmake
index a32f119d184..08d698cc3ad 100644
--- a/build_files/build_environment/cmake/x264.cmake
+++ b/build_files/build_environment/cmake/x264.cmake
@@ -20,24 +20,16 @@ if(WIN32)
set(X264_EXTRA_ARGS --enable-win32thread --cross-prefix=${MINGW_HOST}- --host=${MINGW_HOST})
endif()
-
-if(APPLE)
- if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
- set(X264_EXTRA_ARGS ${X264_EXTRA_ARGS} "--disable-asm")
- set(X264_CONFIGURE_ENV echo .)
- else()
- set(X264_CONFIGURE_ENV
- export AS=${LIBDIR}/nasm/bin/nasm
- )
- endif()
-else()
- set(X264_CONFIGURE_ENV echo .)
+if(BLENDER_PLATFORM_ARM)
+ set(X264_EXTRA_ARGS ${X264_EXTRA_ARGS} "--disable-asm")
endif()
-if(UNIX AND NOT APPLE)
+if((APPLE AND NOT BLENDER_PLATFORM_ARM) OR (UNIX AND NOT APPLE))
set(X264_CONFIGURE_ENV
export AS=${LIBDIR}/nasm/bin/nasm
)
+else()
+ set(X264_CONFIGURE_ENV echo .)
endif()
ExternalProject_Add(external_x264
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 7cd21b2885c..7d8c2ca3181 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -1797,6 +1797,10 @@ compile_OCIO() {
cmake_d="$cmake_d -D OCIO_BUILD_PYTHON=OFF"
cmake_d="$cmake_d -D OCIO_BUILD_GPU_TESTS=OFF"
+ if [ $(uname -m) == "aarch64" ]; then
+ cmake_d="$cmake_d -D OCIO_USE_SSE=OFF"
+ fi
+
if file /bin/cp | grep -q '32-bit'; then
cflags="-fPIC -m32 -march=i686"
else
@@ -2059,7 +2063,10 @@ compile_OIIO() {
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
cmake_d="$cmake_d -D STOP_ON_WARNING=OFF"
cmake_d="$cmake_d -D LINKSTATIC=OFF"
- cmake_d="$cmake_d -D USE_SIMD=sse2"
+
+ if [ $(uname -m) != "aarch64" ]; then
+ cmake_d="$cmake_d -D USE_SIMD=sse2"
+ fi
cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION"
@@ -2079,7 +2086,7 @@ compile_OIIO() {
cmake_d="$cmake_d -D USE_OPENCV=OFF"
cmake_d="$cmake_d -D BUILD_TESTING=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TESTS=OFF"
- cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=ON"
+ cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=OFF"
cmake_d="$cmake_d -D TXT2MAN="
#cmake_d="$cmake_d -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
#cmake_d="$cmake_d -D CMAKE_VERBOSE_MAKEFILE=ON"
@@ -2209,10 +2216,15 @@ compile_LLVM() {
mkdir build
cd build
+ LLVM_TARGETS="X86"
+ if [ $(uname -m) == "aarch64" ]; then
+ LLVM_TARGETS="AArch64"
+ fi
+
cmake_d="-D CMAKE_BUILD_TYPE=Release"
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
cmake_d="$cmake_d -D LLVM_ENABLE_FFI=ON"
- cmake_d="$cmake_d -D LLVM_TARGETS_TO_BUILD=X86"
+ cmake_d="$cmake_d -D LLVM_TARGETS_TO_BUILD=$LLVM_TARGETS"
cmake_d="$cmake_d -D LLVM_ENABLE_TERMINFO=OFF"
if [ -d $_FFI_INCLUDE_DIR ]; then
@@ -2329,13 +2341,16 @@ compile_OSL() {
cmake_d="$cmake_d -D STOP_ON_WARNING=OFF"
cmake_d="$cmake_d -D OSL_BUILD_PLUGINS=OFF"
cmake_d="$cmake_d -D OSL_BUILD_TESTS=OFF"
- cmake_d="$cmake_d -D USE_SIMD=sse2"
cmake_d="$cmake_d -D USE_LLVM_BITCODE=OFF"
cmake_d="$cmake_d -D USE_PARTIO=OFF"
cmake_d="$cmake_d -D OSL_BUILD_MATERIALX=OFF"
cmake_d="$cmake_d -D USE_QT=OFF"
cmake_d="$cmake_d -D USE_PYTHON=OFF"
+ if [ $(uname -m) != "aarch64" ]; then
+ cmake_d="$cmake_d -D USE_SIMD=sse2"
+ fi
+
cmake_d="$cmake_d -D CMAKE_CXX_STANDARD=14"
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
diff --git a/build_files/build_environment/patches/cmakelists_tbb.txt b/build_files/build_environment/patches/cmakelists_tbb.txt
index 4032e5d6f83..e05f27afdd6 100644
--- a/build_files/build_environment/patches/cmakelists_tbb.txt
+++ b/build_files/build_environment/patches/cmakelists_tbb.txt
@@ -1,5 +1,32 @@
-cmake_minimum_required (VERSION 2.8)
-project(tbb CXX)
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+if (POLICY CMP0048)
+ # cmake warns if loaded from a min-3.0-required parent dir, so silence the warning:
+ cmake_policy(SET CMP0048 NEW)
+endif()
+
+project (tbb CXX)
+
+include(CheckCXXCompilerFlag)
+include(CheckCXXSourceRuns)
+
+if(POLICY CMP0058)
+ cmake_policy(SET CMP0058 NEW)
+endif()
+
+if(POLICY CMP0068)
+ cmake_policy(SET CMP0068 NEW)
+endif()
+
+if (POLICY CMP0078)
+ # swig standard target names
+ cmake_policy(SET CMP0078 NEW)
+endif ()
+
+if (POLICY CMP0086)
+ # UseSWIG honors SWIG_MODULE_NAME via -module flag
+ cmake_policy(SET CMP0086 NEW)
+endif ()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as none was specified.")
@@ -8,12 +35,36 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
"MinSizeRel" "RelWithDebInfo")
endif()
-include_directories(include src src/rml/include )
+if(NOT TBB_INSTALL_RUNTIME_DIR)
+ set(TBB_INSTALL_RUNTIME_DIR bin)
+endif()
+if(NOT TBB_INSTALL_LIBRARY_DIR)
+ set(TBB_INSTALL_LIBRARY_DIR lib)
+endif()
+if(NOT TBB_INSTALL_ARCHIVE_DIR)
+ set(TBB_INSTALL_ARCHIVE_DIR lib)
+endif()
+if(NOT TBB_INSTALL_INCLUDE_DIR)
+ set(TBB_INSTALL_INCLUDE_DIR include)
+endif()
+if(NOT TBB_CMAKE_PACKAGE_INSTALL_DIR)
+ set(TBB_CMAKE_PACKAGE_INSTALL_DIR lib/cmake/tbb)
+endif()
+
+include_directories(include src src/rml/include ${CMAKE_CURRENT_BINARY_DIR})
option(TBB_BUILD_SHARED "Build TBB shared library" ON)
option(TBB_BUILD_STATIC "Build TBB static library" ON)
option(TBB_BUILD_TBBMALLOC "Build TBB malloc library" ON)
option(TBB_BUILD_TBBMALLOC_PROXY "Build TBB malloc proxy library" ON)
+option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" ON)
+option(TBB_NO_DATE "Do not save the configure date in the version string" OFF)
+option(TBB_BUILD_PYTHON "Build TBB Python bindings" OFF)
+option(TBB_SET_SOVERSION "Set the SOVERSION (shared library build version suffix)?" OFF)
+
+# When this repository is part of a larger build system of a parent project
+# we may not want TBB to set up default installation targets
+option(TBB_INSTALL_TARGETS "Include build targets for 'make install'" ON)
if(APPLE)
set(CMAKE_MACOSX_RPATH ON)
@@ -39,66 +90,143 @@ set(tbbmalloc_proxy_src
src/tbbmalloc/proxy.cpp
src/tbbmalloc/tbb_function_replacement.cpp)
-if (NOT APPLE)
- add_definitions(-DDO_ITT_NOTIFY)
-else()
+add_library (tbb_interface INTERFACE)
+add_definitions(-DTBB_SUPPRESS_DEPRECATED_MESSAGES=1)
+
+if (CMAKE_SYSTEM_PROCESSOR MATCHES "(i386|x86_64)")
+ if (NOT APPLE AND NOT MINGW)
+ target_compile_definitions(tbb_interface INTERFACE DO_ITT_NOTIFY)
+ endif()
+endif()
+
+if (APPLE)
# Disable annoying "has no symbols" warnings
- set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
- set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+ set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+ set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
endif()
-if (UNIX)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DUSE_PTHREAD")
- if(NOT CMAKE_CXX_FLAGS MATCHES "-mno-rtm")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mrtm")
- endif()
- if (APPLE)
- set(ARCH_PREFIX "mac")
- else()
- set(ARCH_PREFIX "lin")
- endif()
- if (CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(ARCH_PREFIX "${ARCH_PREFIX}64")
+macro(CHECK_CXX_COMPILER_AND_LINKER_FLAGS _RESULT _CXX_FLAGS _LINKER_FLAGS)
+ set(CMAKE_REQUIRED_FLAGS ${_CXX_FLAGS})
+ set(CMAKE_REQUIRED_LIBRARIES ${_LINKER_FLAGS})
+ set(CMAKE_REQUIRED_QUIET TRUE)
+ check_cxx_source_runs("#include <iostream>\nint main(int argc, char **argv) { std::cout << \"test\"; return 0; }" ${_RESULT})
+ set(CMAKE_REQUIRED_FLAGS "")
+ set(CMAKE_REQUIRED_LIBRARIES "")
+endmacro()
+
+# Prefer libc++ in conjunction with Clang
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ if (CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+")
+ message(STATUS "TBB: using libc++.")
else()
- set(ARCH_PREFIX "${ARCH_PREFIX}32")
+ CHECK_CXX_COMPILER_AND_LINKER_FLAGS(HAS_LIBCPP "-stdlib=libc++" "-stdlib=libc++")
+ if (HAS_LIBCPP)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -D_LIBCPP_VERSION")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++")
+ message(STATUS "TBB: using libc++.")
+ else()
+ message(STATUS "TBB: NOT using libc++.")
+ endif()
endif()
- set(ENABLE_RTTI "-frtti -fexceptions ")
- set(DISABLE_RTTI "-fno-rtti -fno-exceptions ")
+endif()
+
+set (CMAKE_CXX_STANDARD 11)
+
+if (UNIX)
+ target_compile_definitions(tbb_interface INTERFACE USE_PTHREAD)
+
+ check_cxx_compiler_flag ("-mrtm -Werror" SUPPORTS_MRTM)
+ if (SUPPORTS_MRTM)
+ target_compile_options(tbb_interface INTERFACE "-mrtm")
+ endif ()
+
elseif(WIN32)
- cmake_minimum_required (VERSION 3.1)
- enable_language(ASM_MASM)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS- /Zc:wchar_t /Zc:forScope /DUSE_WINTHREAD")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_CRT_SECURE_NO_DEPRECATE /D_WIN32_WINNT=0x0600 /volatile:iso")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4800 /wd4146 /wd4244 /wd4018")
-
- if (CMAKE_SIZEOF_VOID_P EQUAL 8)
- list(APPEND tbb_src src/tbb/intel64-masm/atomic_support.asm
- src/tbb/intel64-masm/itsx.asm src/tbb/intel64-masm/intel64_misc.asm)
- list(APPEND tbbmalloc_src src/tbb/intel64-masm/atomic_support.asm)
- set(CMAKE_ASM_MASM_FLAGS "/DEM64T=1")
- set(ARCH_PREFIX "win64")
- else()
- list(APPEND tbb_src src/tbb/ia32-masm/atomic_support.asm
- src/tbb/ia32-masm/itsx.asm src/tbb/ia32-masm/lock_byte.asm)
- list(APPEND tbbmalloc_src src/tbb/ia32-masm/atomic_support.asm)
- set(ARCH_PREFIX "win32")
- endif()
+ target_compile_definitions(tbb_interface INTERFACE USE_WINTHREAD _WIN32_WINNT=0x0600)
+ if (MSVC)
+ enable_language(ASM_MASM)
+ target_compile_options(tbb_interface INTERFACE /GS- /Zc:wchar_t /Zc:forScope)
+ check_cxx_compiler_flag ("/volatile:iso" SUPPORTS_VOLATILE_FLAG)
+ if (SUPPORTS_VOLATILE_FLAG)
+ target_compile_options(tbb_interface INTERFACE /volatile:iso)
+ endif ()
+ target_compile_options(tbb_interface INTERFACE $<$<COMPILE_LANGUAGE:CXX>:/wd4267 /wd4800 /wd4146 /wd4244 /wd4577 /wd4018>)
+ if (NOT CMAKE_SIZEOF_VOID_P)
+ message(FATAL_ERROR "'CMAKE_SIZEOF_VOID_P' is undefined. Please delete your build directory and rerun CMake again!")
+ endif()
+
+ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND tbb_src src/tbb/intel64-masm/atomic_support.asm
+ src/tbb/intel64-masm/itsx.asm src/tbb/intel64-masm/intel64_misc.asm)
+ list(APPEND tbbmalloc_src src/tbb/intel64-masm/atomic_support.asm)
+ set(CMAKE_ASM_MASM_FLAGS "/DEM64T=1 ${CMAKE_ASM_MASM_FLAGS}")
+ else()
+ list(APPEND tbb_src src/tbb/ia32-masm/atomic_support.asm
+ src/tbb/ia32-masm/itsx.asm src/tbb/ia32-masm/lock_byte.asm)
+ # Enable SAFESEH feature for assembly (x86 builds only).
+ set(CMAKE_ASM_MASM_FLAGS "/safeseh ${CMAKE_ASM_MASM_FLAGS}")
+ endif()
+ elseif (MINGW)
+ target_compile_options(tbb_interface INTERFACE "-mthreads")
+ endif ()
+endif()
+
+if (MSVC)
set(ENABLE_RTTI "/EHsc /GR ")
set(DISABLE_RTTI "/EHs- /GR- ")
+elseif (UNIX)
+ set(ENABLE_RTTI "-frtti -fexceptions ")
+ set(DISABLE_RTTI "-fno-rtti -fno-exceptions ")
+endif ()
+
+##--------
+# - Added TBB_USE_GLIBCXX_VERSION macro to specify the version of GNU
+# libstdc++ when it cannot be properly recognized, e.g. when used
+# with Clang on Linux* OS. Inspired by a contribution from David A.
+if (NOT TBB_USE_GLIBCXX_VERSION AND UNIX AND NOT APPLE)
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # using Clang
+ string(REPLACE "." "0" TBB_USE_GLIBCXX_VERSION ${CMAKE_CXX_COMPILER_VERSION})
+ endif()
endif()
+if (TBB_USE_GLIBCXX_VERSION)
+ target_compile_definitions(tbb_interface INTERFACE TBB_USE_GLIBCXX_VERSION=${TBB_USE_GLIBCXX_VERSION})
+endif()
+
+##-------
+
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- include(CheckCXXCompilerFlag)
- check_cxx_compiler_flag("-flifetime-dse=1" SUPPORTS_FLIFETIME)
- if (SUPPORTS_FLIFETIME)
- add_definitions(-flifetime-dse=1)
- endif()
+ check_cxx_compiler_flag ("-flifetime-dse=1" SUPPORTS_FLIFETIME)
+ if (SUPPORTS_FLIFETIME)
+ target_compile_options(tbb_interface INTERFACE -flifetime-dse=1)
+ endif()
endif()
# Linker export definitions
-if (WIN32)
+if (APPLE)
+ set (ARCH_PREFIX "mac")
+elseif(WIN32)
+ set (ARCH_PREFIX "win")
+else()
+ set (ARCH_PREFIX "lin")
+endif()
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(ARCH_PREFIX "${ARCH_PREFIX}64")
+else()
+ set(ARCH_PREFIX "${ARCH_PREFIX}32")
+endif()
+
+if (MINGW)
+ set (ARCH_PREFIX "${ARCH_PREFIX}-gcc")
+ # there's no win32-gcc-tbb-export.def, use lin32-tbb-export.def
+ execute_process (COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/lin32-tbb-export.def ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/win32-gcc-tbb-export.def)
+endif()
+
+if (MSVC)
add_custom_command(OUTPUT tbb.def
COMMAND ${CMAKE_CXX_COMPILER} /TC /EP ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include > tbb.def
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def
@@ -110,18 +238,15 @@ if (WIN32)
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def
COMMENT "Preprocessing tbbmalloc.def"
)
- list(APPEND tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/tbb_resource.rc)
- list(APPEND tbbmalloc_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc)
- list(APPEND tbbmalloc_proxy_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc)
else()
add_custom_command(OUTPUT tbb.def
- COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def
+ COMMAND ${CMAKE_CXX_COMPILER} -xc++ -std=c++11 -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def
COMMENT "Preprocessing tbb.def"
)
add_custom_command(OUTPUT tbbmalloc.def
- COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbbmalloc.def
+ COMMAND ${CMAKE_CXX_COMPILER} -xc++ -std=c++11 -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbbmalloc.def
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def
COMMENT "Preprocessing tbbmalloc.def"
)
@@ -132,34 +257,80 @@ add_custom_target(tbb_def_files DEPENDS tbb.def tbbmalloc.def)
# TBB library
if (TBB_BUILD_STATIC)
add_library(tbb_static STATIC ${tbb_src})
- set_property(TARGET tbb_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_BUILD=1")
- set_property(TARGET tbb_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1")
+ target_link_libraries(tbb_static PRIVATE tbb_interface)
+ target_include_directories(tbb_static INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" "$<INSTALL_INTERFACE:${TBB_INSTALL_INCLUDE_DIR}>")
set_property(TARGET tbb_static APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI})
- install(TARGETS tbb_static ARCHIVE DESTINATION lib)
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS tbb_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR})
+ endif()
+
+ target_compile_definitions(tbb_static
+ PRIVATE
+ -D__TBB_BUILD=1
+ -D__TBB_DYNAMIC_LOAD_ENABLED=0
+ -D__TBB_SOURCE_DIRECTLY_INCLUDED=1)
+
+ if (MSVC)
+ target_compile_definitions(tbb_static
+ PUBLIC -D__TBB_NO_IMPLICIT_LINKAGE=1
+ PRIVATE -D_CRT_SECURE_NO_WARNINGS)
+ endif()
+
+ if (UNIX AND NOT APPLE)
+ target_link_libraries(tbb_static PUBLIC pthread dl)
+ endif()
endif()
if (TBB_BUILD_SHARED)
add_library(tbb SHARED ${tbb_src})
- set_property(TARGET tbb APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_BUILD=1")
+ target_link_libraries(tbb PRIVATE tbb_interface)
+ target_include_directories(tbb INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" "$<INSTALL_INTERFACE:${TBB_INSTALL_INCLUDE_DIR}>")
set_property(TARGET tbb APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI})
+ if (TBB_SET_SOVERSION)
+ set_property(TARGET tbb PROPERTY SOVERSION 2)
+ endif ()
+
+ target_compile_definitions(tbb
+ PRIVATE -D__TBB_BUILD=1)
+
+ if (MSVC)
+ target_compile_definitions(tbb
+ PUBLIC -D__TBB_NO_IMPLICIT_LINKAGE=1
+ PRIVATE -D_CRT_SECURE_NO_WARNINGS)
+ endif()
+
add_dependencies(tbb tbb_def_files)
+
if (APPLE)
- set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
- elseif(UNIX)
- set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
- elseif(WIN32)
- set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
-
+ set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"")
+ elseif (MSVC)
+ set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"")
+ else ()
+ set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"")
endif()
- install(TARGETS tbb DESTINATION lib)
- if(WIN32)
- set_target_properties(tbb PROPERTIES OUTPUT_NAME "tbb$<$<CONFIG:Debug>:_debug>")
+
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS tbb EXPORT TBB
+ LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR}
+ ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}
+ RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR})
+ if (MSVC)
+ install(FILES $<TARGET_PDB_FILE:tbb> DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL)
+ endif()
+ endif()
+
+ if (UNIX AND NOT APPLE)
+ target_link_libraries(tbb PUBLIC pthread dl)
endif()
endif()
-if(CMAKE_COMPILER_IS_GNUCC)
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Quench a warning on GCC
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/governor.cpp COMPILE_FLAGS "-Wno-missing-field-initializers ")
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # Quench a warning on Clang
+ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/itt_notify.cpp COMPILE_FLAGS "-Wno-varargs ")
elseif(MSVC)
# Quench a warning on MSVC
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/scheduler.cpp COMPILE_FLAGS "/wd4458 ")
@@ -169,24 +340,50 @@ if(TBB_BUILD_TBBMALLOC)
# TBB malloc library
if (TBB_BUILD_STATIC)
add_library(tbbmalloc_static STATIC ${tbbmalloc_static_src})
+ target_link_libraries(tbbmalloc_static PRIVATE tbb_interface)
set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
+ set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_DYNAMIC_LOAD_ENABLED=0")
+ set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1")
set_property(TARGET tbbmalloc_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
- install(TARGETS tbbmalloc_static ARCHIVE DESTINATION lib)
+ if (MSVC)
+ target_compile_definitions(tbbmalloc_static PUBLIC __TBB_NO_IMPLICIT_LINKAGE=1 __TBBMALLOC_NO_IMPLICIT_LINKAGE=1)
+ endif()
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS tbbmalloc_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR})
+ endif()
endif()
if (TBB_BUILD_SHARED)
add_library(tbbmalloc SHARED ${tbbmalloc_src})
+ target_link_libraries(tbbmalloc PRIVATE tbb_interface)
set_property(TARGET tbbmalloc APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
set_property(TARGET tbbmalloc APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
+ if (TBB_SET_SOVERSION)
+ set_property(TARGET tbbmalloc PROPERTY SOVERSION 2)
+ endif ()
add_dependencies(tbbmalloc tbb_def_files)
if (APPLE)
- set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def")
- elseif(UNIX)
- set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def")
- elseif(WIN32)
- set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def")
+ set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"")
+ elseif (MSVC)
+ set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"")
+ else ()
+ set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"")
+ endif()
+ if (MSVC)
+ target_compile_definitions(tbbmalloc PUBLIC __TBB_NO_IMPLICIT_LINKAGE=1 __TBBMALLOC_NO_IMPLICIT_LINKAGE=1)
+ endif()
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS tbbmalloc EXPORT TBB
+ LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR}
+ ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}
+ RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR})
+ if (MSVC)
+ install(FILES $<TARGET_PDB_FILE:tbbmalloc> DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL)
+ endif()
+ endif()
+ if (UNIX AND NOT APPLE)
+ target_link_libraries(tbbmalloc PUBLIC pthread dl)
endif()
- install(TARGETS tbbmalloc DESTINATION lib)
endif()
endif()
@@ -194,19 +391,298 @@ if(TBB_BUILD_TBBMALLOC_PROXY)
# TBB malloc proxy library
if (TBB_BUILD_STATIC)
add_library(tbbmalloc_proxy_static STATIC ${tbbmalloc_proxy_src})
+ target_link_libraries(tbbmalloc_proxy_static PRIVATE tbb_interface)
set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
+ set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_DYNAMIC_LOAD_ENABLED=0")
+ set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1")
set_property(TARGET tbbmalloc_proxy_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
- link_libraries(tbbmalloc_proxy_static tbbmalloc)
- install(TARGETS tbbmalloc_proxy_static ARCHIVE DESTINATION lib)
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS tbbmalloc_proxy_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR})
+ endif()
endif()
if (TBB_BUILD_SHARED)
add_library(tbbmalloc_proxy SHARED ${tbbmalloc_proxy_src})
+ target_link_libraries(tbbmalloc_proxy PRIVATE tbb_interface)
set_property(TARGET tbbmalloc_proxy APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
set_property(TARGET tbbmalloc_proxy APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
- target_link_libraries(tbbmalloc_proxy tbbmalloc)
- install(TARGETS tbbmalloc_proxy DESTINATION lib)
+ if (TBB_SET_SOVERSION)
+ set_property(TARGET tbbmalloc_proxy PROPERTY SOVERSION 2)
+ endif ()
+ target_link_libraries(tbbmalloc_proxy PUBLIC tbbmalloc)
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS tbbmalloc_proxy EXPORT TBB
+ LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR}
+ ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}
+ RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR})
+ if (MSVC)
+ install(FILES $<TARGET_PDB_FILE:tbbmalloc_proxy> DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL)
+ endif()
+ endif()
+ if (UNIX AND NOT APPLE)
+ target_link_libraries(tbbmalloc_proxy PUBLIC pthread dl)
+ endif()
endif()
endif()
-install(DIRECTORY include/tbb DESTINATION include)
+if (TBB_INSTALL_TARGETS)
+ install(DIRECTORY include/tbb DESTINATION ${TBB_INSTALL_INCLUDE_DIR})
+ if (TBB_BUILD_SHARED)
+ install(EXPORT TBB DESTINATION ${TBB_CMAKE_PACKAGE_INSTALL_DIR} NAMESPACE TBB:: FILE TBBConfig.cmake)
+ endif()
+endif()
+
+# version file
+if (TBB_INSTALL_TARGETS)
+ set (_VERSION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/include/tbb/tbb_stddef.h)
+ file (STRINGS ${_VERSION_FILE} _VERSION_MAJOR_STRING REGEX ".*define[ ]+TBB_VERSION_MAJOR[ ]+[0-9]+.*")
+ file (STRINGS ${_VERSION_FILE} _VERSION_MINOR_STRING REGEX ".*define[ ]+TBB_VERSION_MINOR[ ]+[0-9]+.*")
+ string (REGEX REPLACE ".*TBB_VERSION_MAJOR[ ]+([0-9]+)" "\\1" TBB_MAJOR_VERSION ${_VERSION_MAJOR_STRING})
+ string (REGEX REPLACE ".*TBB_VERSION_MINOR[ ]+([0-9]+)" "\\1" TBB_MINOR_VERSION ${_VERSION_MINOR_STRING})
+ set (TBB_VERSION_STRING "${TBB_MAJOR_VERSION}.${TBB_MINOR_VERSION}")
+ include (CMakePackageConfigHelpers)
+ write_basic_package_version_file (TBBConfigVersion.cmake VERSION "${TBB_VERSION_STRING}" COMPATIBILITY AnyNewerVersion)
+ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/TBBConfigVersion.cmake DESTINATION "${TBB_CMAKE_PACKAGE_INSTALL_DIR}")
+endif()
+
+# version_string.ver
+if (UNIX AND NOT TBB_NO_DATE)
+ execute_process (COMMAND date "+%a, %d %b %Y %H:%M:%S %z"
+ OUTPUT_VARIABLE _configure_date
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+elseif (WIN32 AND NOT TBB_NO_DATE)
+ execute_process (COMMAND cmd " /C date /T"
+ OUTPUT_VARIABLE _configure_date
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+else ()
+ set (_configure_date "Unknown")
+endif()
+set (TBB_CONFIG_DATE "${_configure_date}" CACHE STRING "First time that TBB was configured")
+set (_configure_date "${TBB_CONFIG_DATE}")
+include_directories (${CMAKE_BINARY_DIR})
+configure_file (build/version_string.ver.in version_string.ver @ONLY)
+
+if (TBB_BUILD_TESTS)
+ enable_language (C)
+ enable_testing ()
+
+ find_library (LIBRT_LIBRARIES rt)
+ find_library (LIDL_LIBRARIES dl)
+ find_package (Threads)
+ if (NOT APPLE)
+ find_package (OpenMP)
+ endif()
+
+ macro (tbb_add_test testname)
+ set (full_testname tbb_test_${testname})
+ add_executable (${full_testname} src/test/test_${testname}.cpp)
+ target_link_libraries(${full_testname} PRIVATE tbb_interface)
+ if (TBB_BUILD_SHARED)
+ target_link_libraries (${full_testname} PRIVATE tbb tbbmalloc)
+ target_compile_definitions (${full_testname} PRIVATE __TBB_LIB_NAME=tbb)
+ else ()
+ target_link_libraries (${full_testname} PRIVATE tbb_static tbbmalloc_static)
+ target_compile_definitions (${full_testname} PRIVATE __TBB_LIB_NAME=tbb_static)
+ endif ()
+ if (LIBRT_LIBRARIES)
+ target_link_libraries (${full_testname} PRIVATE ${LIBRT_LIBRARIES})
+ endif ()
+ if (LIDL_LIBRARIES)
+ target_link_libraries (${full_testname} PRIVATE ${LIDL_LIBRARIES})
+ endif ()
+ if (Threads_FOUND)
+ target_link_libraries (${full_testname} PRIVATE ${CMAKE_THREAD_LIBS_INIT})
+ endif ()
+ if (OPENMP_FOUND AND "${testname}" MATCHES "openmp")
+ set_target_properties (${full_testname} PROPERTIES COMPILE_FLAGS "${OpenMP_CXX_FLAGS}")
+ set_target_properties (${full_testname} PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}")
+ endif()
+ if (MINGW)
+ target_link_libraries (${full_testname} PRIVATE psapi)
+ endif ()
+ add_test (NAME ${full_testname} COMMAND ${full_testname})
+ endmacro ()
+
+ tbb_add_test (aggregator)
+ tbb_add_test (aligned_space)
+ tbb_add_test (assembly)
+ if (NOT WIN32)
+ tbb_add_test (async_msg) # msvc64/debug timeouts
+ endif()
+ tbb_add_test (async_node)
+ # tbb_add_test (atomic) # msvc64/debug timeouts: Compile-time initialization fails for static tbb::atomic variables
+ tbb_add_test (blocked_range2d)
+ tbb_add_test (blocked_range3d)
+ tbb_add_test (blocked_range)
+ tbb_add_test (broadcast_node)
+ tbb_add_test (buffer_node)
+ tbb_add_test (cache_aligned_allocator)
+ if (NOT WIN32)
+ tbb_add_test (cache_aligned_allocator_STL)
+ endif()
+ tbb_add_test (cilk_dynamic_load)
+ tbb_add_test (cilk_interop)
+ tbb_add_test (combinable)
+ tbb_add_test (composite_node)
+ tbb_add_test (concurrent_hash_map)
+ tbb_add_test (concurrent_lru_cache)
+ # tbb_add_test (concurrent_monitor) # too long
+ # tbb_add_test (concurrent_priority_queue)
+ if (NOT WIN32)
+ tbb_add_test (concurrent_queue) # msvc64/debug timeouts
+ endif()
+ # tbb_add_test (concurrent_queue_whitebox)
+ tbb_add_test (concurrent_unordered_map)
+ # tbb_add_test (concurrent_unordered_set)
+ tbb_add_test (concurrent_vector)
+ tbb_add_test (continue_node)
+ tbb_add_test (critical_section)
+ tbb_add_test (dynamic_link)
+ # tbb_add_test (eh_algorithms)
+ tbb_add_test (eh_flow_graph)
+ # tbb_add_test (eh_tasks)
+ tbb_add_test (enumerable_thread_specific)
+ tbb_add_test (examples_common_utility)
+ # tbb_add_test (fast_random)
+ tbb_add_test (flow_graph)
+ tbb_add_test (flow_graph_whitebox)
+ # tbb_add_test (fp) # mingw: harness_fp.h:66, assertion !checkConsistency || (ctl.mxcsr & SSE_RND_MODE_MASK) >> 3 == (ctl.x87cw & FE_RND_MODE_MASK): failed
+ # tbb_add_test (function_node) # mingw:random timeout
+ # tbb_add_test (global_control)
+ # tbb_add_test (global_control_whitebox)
+ tbb_add_test (halt)
+ tbb_add_test (handle_perror)
+ # tbb_add_test (hw_concurrency)
+ tbb_add_test (indexer_node)
+ tbb_add_test (inits_loop)
+ tbb_add_test (intrusive_list)
+ tbb_add_test (ittnotify)
+ # tbb_add_test (join_node) #msvc/64: fatal error C1128: number of sections exceeded object file format limit: compile with /bigob
+ tbb_add_test (lambda)
+ tbb_add_test (limiter_node)
+ # tbb_add_test (malloc_atexit)
+ # tbb_add_test (malloc_compliance) #mingw: Limits should be decreased for the test to work
+ tbb_add_test (malloc_init_shutdown)
+ # tbb_add_test (malloc_lib_unload)
+ # tbb_add_test (malloc_overload)
+ tbb_add_test (malloc_pools)
+ tbb_add_test (malloc_regression)
+ # tbb_add_test (malloc_used_by_lib)
+ # tbb_add_test (malloc_whitebox)
+ tbb_add_test (model_plugin)
+ # tbb_add_test (multifunction_node) # too long
+ tbb_add_test (mutex)
+ tbb_add_test (mutex_native_threads)
+ # tbb_add_test (opencl_node)
+ if (OPENMP_FOUND)
+ tbb_add_test (openmp)
+ endif ()
+ tbb_add_test (overwrite_node)
+ # tbb_add_test (parallel_do)
+ # This seems to fail on CI platforms (AppVeyor/Travis), perhaps because the VM exposes just 1 core?
+ tbb_add_test (parallel_for)
+ tbb_add_test (parallel_for_each)
+ tbb_add_test (parallel_for_vectorization)
+ tbb_add_test (parallel_invoke)
+ tbb_add_test (parallel_pipeline)
+ tbb_add_test (parallel_reduce)
+ tbb_add_test (parallel_scan)
+ tbb_add_test (parallel_sort)
+ tbb_add_test (parallel_while)
+ # tbb_add_test (partitioner_whitebox) # too long
+ tbb_add_test (pipeline)
+ # tbb_add_test (pipeline_with_tbf) # takes forever on appveyor
+ tbb_add_test (priority_queue_node)
+ tbb_add_test (queue_node)
+ tbb_add_test (reader_writer_lock)
+ # tbb_add_test (runtime_loader) # LINK : fatal error LNK1104: cannot open file 'tbbproxy.lib' [C:\projects\tbb\test_runtime_loader.vcxproj]
+ tbb_add_test (rwm_upgrade_downgrade)
+ # tbb_add_test (ScalableAllocator)
+ if (NOT WIN32)
+ tbb_add_test (ScalableAllocator_STL)
+ endif()
+ tbb_add_test (semaphore)
+ # tbb_add_test (sequencer_node) # msvc: timeout
+ tbb_add_test (source_node)
+ tbb_add_test (split_node)
+ tbb_add_test (static_assert)
+ tbb_add_test (std_thread)
+ tbb_add_test (tagged_msg)
+ # tbb_add_test (task_arena) # LINK : fatal error LNK1104: cannot open file '__TBB_LIB_NAME.lib' [C:\projects\tbb\test_task_arena.vcxproj]
+ # tbb_add_test (task_assertions)
+ tbb_add_test (task_auto_init)
+ tbb_add_test (task)
+ # tbb_add_test (task_enqueue) # too long
+ tbb_add_test (task_group)
+ # tbb_add_test (task_leaks)
+ # tbb_add_test (task_priority)
+ # tbb_add_test (task_scheduler_init) # msvc: test_task_scheduler_init.cpp:68, assertion !test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(threads): failed
+ tbb_add_test (task_scheduler_observer)
+ tbb_add_test (task_steal_limit)
+ tbb_add_test (tbb_condition_variable)
+ tbb_add_test (tbb_fork)
+ # tbb_add_test (tbb_header)
+ tbb_add_test (tbb_thread)
+ # tbb_add_test (tbb_version)
+ tbb_add_test (tick_count)
+ tbb_add_test (tuple)
+ tbb_add_test (write_once_node)
+ tbb_add_test (yield)
+endif ()
+
+if (TBB_BUILD_PYTHON)
+ find_package(PythonInterp)
+ find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT)
+ find_package(SWIG 3)
+ if (PythonLibs_FOUND AND SWIG_FOUND AND TBB_BUILD_SHARED)
+ include (${SWIG_USE_FILE})
+ set_source_files_properties (python/tbb/api.i PROPERTIES CPLUSPLUS ON)
+ set (CMAKE_SWIG_FLAGS "-threads")
+
+ # swig_add_module is deprecated
+ if (CMAKE_VERSION VERSION_LESS 3.8)
+ swig_add_module (api python python/tbb/api.i)
+ else ()
+ swig_add_library (api LANGUAGE python SOURCES python/tbb/api.i)
+ endif ()
+
+ # UseSWIG generates now standard target names
+ if (CMAKE_VERSION VERSION_LESS 3.13)
+ set (module_target ${SWIG_MODULE_api_REAL_NAME})
+ else ()
+ set (module_target api)
+ endif ()
+
+ target_include_directories(${module_target} PRIVATE ${PYTHON_INCLUDE_DIRS})
+ target_link_libraries(${module_target} PRIVATE tbb)
+ if(WIN32)
+ target_link_libraries(${module_target} ${PYTHON_LIBRARIES})
+ elseif(APPLE)
+ set_target_properties(${module_target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
+ endif()
+
+ if (WIN32)
+ set (PYTHON_SITE_PACKAGES Lib/site-packages)
+ else ()
+ set (PYTHON_SITE_PACKAGES lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages)
+ endif ()
+ if (TBB_INSTALL_TARGETS)
+ install(FILES python/TBB.py
+ DESTINATION ${PYTHON_SITE_PACKAGES})
+ install(FILES python/tbb/__init__.py python/tbb/pool.py python/tbb/test.py python/tbb/__main__.py ${CMAKE_CURRENT_BINARY_DIR}/api.py
+ DESTINATION ${PYTHON_SITE_PACKAGES}/tbb)
+ install(TARGETS ${module_target}
+ DESTINATION ${PYTHON_SITE_PACKAGES}/tbb)
+ endif()
+
+ if(UNIX AND NOT APPLE)
+ add_library(irml SHARED python/rml/ipc_server.cpp python/rml/ipc_utils.cpp src/tbb/cache_aligned_allocator.cpp src/tbb/dynamic_link.cpp src/tbb/tbb_misc_ex.cpp src/tbb/tbb_misc.cpp)
+ target_compile_definitions(irml PRIVATE DO_ITT_NOTIFY=0 USE_PTHREAD=1)
+ target_link_libraries(irml PRIVATE tbb)
+ set_target_properties(irml PROPERTIES VERSION 1)
+ if (TBB_INSTALL_TARGETS)
+ install(TARGETS irml DESTINATION ${TBB_INSTALL_LIBRARY_DIR})
+ endif()
+ endif ()
+ endif ()
+endif ()
diff --git a/build_files/build_environment/patches/tbb.diff b/build_files/build_environment/patches/tbb.diff
index c05c35bca95..07f70aa7007 100644
--- a/build_files/build_environment/patches/tbb.diff
+++ b/build_files/build_environment/patches/tbb.diff
@@ -10,4 +10,15 @@ index 7a8d06a0..886699d8 100644
+ #if (__cplusplus >= 201402L && (!defined(_MSC_VER) || _MSC_VER >= 1920))
#define __TBB_DEPRECATED [[deprecated]]
#define __TBB_DEPRECATED_MSG(msg) [[deprecated(msg)]]
- #elif _MSC_VER \ No newline at end of file
+ #elif _MSC_VER
+--- a/src/tbb/tools_api/ittnotify_config.h
++++ b/src/tbb/tools_api/ittnotify_config.h
+@@ -162,7 +162,7 @@
+ # define ITT_ARCH ITT_ARCH_IA32E
+ # elif defined _M_IA64 || defined __ia64__
+ # define ITT_ARCH ITT_ARCH_IA64
+-# elif defined _M_ARM || defined __arm__
++# elif defined _M_ARM || defined __arm__ || defined __aarch64__
+ # define ITT_ARCH ITT_ARCH_ARM
+ # elif defined __powerpc64__
+ # define ITT_ARCH ITT_ARCH_PPC64
diff --git a/build_files/build_environment/patches/theora.diff b/build_files/build_environment/patches/theora.diff
index 3abadb66be9..4436577816e 100644
--- a/build_files/build_environment/patches/theora.diff
+++ b/build_files/build_environment/patches/theora.diff
@@ -4,7 +4,7 @@
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
-+ | aarch64 \
++ | aarch64 \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
@@ -12,7 +12,7 @@
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
-+ | aarch64-* \
++ | aarch64-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
diff --git a/build_files/build_environment/patches/usd.diff b/build_files/build_environment/patches/usd.diff
index 42527a4f443..dc4982ad114 100644
--- a/build_files/build_environment/patches/usd.diff
+++ b/build_files/build_environment/patches/usd.diff
@@ -53,3 +53,147 @@ diff -ru USD-20.11/pxr/base/tf/pxrLZ4/lz4.cpp external_usd/pxr/base/tf/pxrLZ4/lz
/*-******************************
* Compression functions
+
+From 442d087962f762deeb8b6e49a0955753fcf9aeb9 Mon Sep 17 00:00:00 2001
+From: Tsahi Zidenberg <tsahee@amazon.com>
+Date: Sun, 15 Nov 2020 15:18:24 +0000
+Subject: [PATCH 1/2] stackTrace: support aarch64/linux
+
+stacktrace calls syscall directly via assembler. Create compatible
+aarch64 code.
+---
+ pxr/base/arch/stackTrace.cpp | 30 ++++++++++++++++++++++++------
+ 1 file changed, 24 insertions(+), 6 deletions(-)
+
+diff --git a/pxr/base/arch/stackTrace.cpp b/pxr/base/arch/stackTrace.cpp
+index dcc1dfd46..c11aabeb1 100644
+--- a/pxr/base/arch/stackTrace.cpp
++++ b/pxr/base/arch/stackTrace.cpp
+@@ -583,7 +583,6 @@ nonLockingLinux__execve (const char *file,
+ char *const argv[],
+ char *const envp[])
+ {
+-#if defined(ARCH_BITS_64)
+ /*
+ * We make a direct system call here, because we can't find an
+ * execve which corresponds with the non-locking fork we call
+@@ -594,7 +593,27 @@ nonLockingLinux__execve (const char *file,
+ * hangs in a threaded app. (We use the non-locking fork to get
+ * around problems with forking when we have had memory
+ * corruption.) whew.
+- *
++ */
++
++ unsigned long result;
++
++#if defined (__aarch64__)
++ {
++ register long __file_result asm ("x0") = (long)file;
++ register char* const* __argv asm ("x1") = argv;
++ register char* const* __envp asm ("x2") = envp;
++ register long __num_execve asm ("x8") = 221;
++ __asm__ __volatile__ (
++ "svc 0"
++ : "=r" (__file_result)
++ : "r"(__num_execve), "r" (__file_result), "r" (__argv), "r" (__envp)
++ : "memory"
++ );
++ result = __file_result;
++ }
++#elif defined(ARCH_CPU_INTEL) && defined(ARCH_BITS_64)
++
++ /*
+ * %rdi, %rsi, %rdx, %rcx, %r8, %r9 are args 0-5
+ * syscall clobbers %rcx and %r11
+ *
+@@ -603,7 +622,6 @@ nonLockingLinux__execve (const char *file,
+ * constraints to gcc.
+ */
+
+- unsigned long result;
+ __asm__ __volatile__ (
+ "mov %0, %%rdi \n\t"
+ "mov %%rcx, %%rsi \n\t"
+@@ -614,6 +632,9 @@ nonLockingLinux__execve (const char *file,
+ : "0" (file), "c" (argv), "d" (envp)
+ : "memory", "cc", "r11"
+ );
++#else
++#error Unknown architecture
++#endif
+
+ if (result >= 0xfffffffffffff000) {
+ errno = -result;
+@@ -621,9 +642,6 @@ nonLockingLinux__execve (const char *file,
+ }
+
+ return result;
+-#else
+-#error Unknown architecture
+-#endif
+ }
+
+ #endif
+
+From a1dffe02519bb3c6ccbbe8c6c58304da5db98995 Mon Sep 17 00:00:00 2001
+From: Tsahi Zidenberg <tsahee@amazon.com>
+Date: Sun, 15 Nov 2020 15:22:52 +0000
+Subject: [PATCH 2/2] timing: support aarch64/linux
+
+The aarch64 arch-timer is directly accessible to userspace via two
+registers:
+CNTVCT_EL0 - holds the current counter value
+CNTFRQ_EL0 - holds the counter frequency (in Hz)
+---
+ pxr/base/arch/timing.cpp | 6 ++++++
+ pxr/base/arch/timing.h | 6 +++++-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/pxr/base/arch/timing.cpp b/pxr/base/arch/timing.cpp
+index 27ad58fed..9022950c1 100644
+--- a/pxr/base/arch/timing.cpp
++++ b/pxr/base/arch/timing.cpp
+@@ -59,6 +59,11 @@ ARCH_HIDDEN
+ void
+ Arch_InitTickTimer()
+ {
++#ifdef __aarch64__
++ uint64_t counter_hz;
++ __asm __volatile("mrs %0, CNTFRQ_EL0" : "=&r" (counter_hz));
++ Arch_NanosecondsPerTick = double(1e9) / double(counter_hz);
++#else
+ // NOTE: Normally ifstream would be cleaner, but it causes crashes when
+ // used in conjunction with DSOs and the Intel Compiler.
+ FILE *in;
+@@ -135,6 +140,7 @@ Arch_InitTickTimer()
+ }
+
+ Arch_NanosecondsPerTick = double(1e9) / double(cpuHz);
++#endif
+ }
+ #elif defined(ARCH_OS_WINDOWS)
+
+diff --git a/pxr/base/arch/timing.h b/pxr/base/arch/timing.h
+index 67ec0d15f..6dc3e85a0 100644
+--- a/pxr/base/arch/timing.h
++++ b/pxr/base/arch/timing.h
+@@ -36,7 +36,7 @@
+ /// \addtogroup group_arch_SystemFunctions
+ ///@{
+
+-#if defined(ARCH_OS_LINUX)
++#if defined(ARCH_OS_LINUX) && defined(ARCH_CPU_INTEL)
+ #include <x86intrin.h>
+ #elif defined(ARCH_OS_DARWIN)
+ #include <mach/mach_time.h>
+@@ -69,6 +69,10 @@ ArchGetTickTime()
+ #elif defined(ARCH_CPU_INTEL)
+ // On Intel we'll use the rdtsc instruction.
+ return __rdtsc();
++#elif defined (__aarch64__)
++ uint64_t result;
++ __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
++ return result;
+ #else
+ #error Unknown architecture.
+ #endif
diff --git a/build_files/buildbot/buildbot_utils.py b/build_files/buildbot/buildbot_utils.py
index 057c2155fb6..7e9858d9268 100644
--- a/build_files/buildbot/buildbot_utils.py
+++ b/build_files/buildbot/buildbot_utils.py
@@ -85,8 +85,8 @@ class VersionInfo:
version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION'))
version_number_patch = int(self._parse_header_file(blender_h, 'BLENDER_VERSION_PATCH'))
version_numbers = (version_number // 100, version_number % 100, version_number_patch)
- self.short_version = "%d.%02d" % (version_numbers[0], version_numbers[1])
- self.version = "%d.%02d.%d" % version_numbers
+ self.short_version = "%d.%d" % (version_numbers[0], version_numbers[1])
+ self.version = "%d.%d.%d" % version_numbers
self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE')
self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
diff --git a/build_files/cmake/Modules/FindEmbree.cmake b/build_files/cmake/Modules/FindEmbree.cmake
index 7f7f2ae0fb3..e6105a885f3 100644
--- a/build_files/cmake/Modules/FindEmbree.cmake
+++ b/build_files/cmake/Modules/FindEmbree.cmake
@@ -34,7 +34,7 @@ FIND_PATH(EMBREE_INCLUDE_DIR
include
)
-IF(NOT (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")))
+IF(NOT (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") OR (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))))
SET(_embree_SIMD_COMPONENTS
embree_sse42
embree_avx
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 91881441c95..813ac013cdf 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -923,10 +923,6 @@ function(get_blender_version)
math(EXPR _out_version_major "${_out_version} / 100")
math(EXPR _out_version_minor "${_out_version} % 100")
- # Zero pad the minor version so `_out_version_minor` is always two characters.
- # This is needed if the minor version is a single digit.
- string(REGEX REPLACE "^([0-9])$" "0\\1" _out_version_minor "${_out_version_minor}")
-
# output vars
set(BLENDER_VERSION "${_out_version_major}.${_out_version_minor}" PARENT_SCOPE)
set(BLENDER_VERSION_MAJOR "${_out_version_major}" PARENT_SCOPE)
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index f9055f02bcf..201d2208486 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 = "V2.93"
+PROJECT_NUMBER = "V3.0"
# 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/doc/python_api/rst/info_gotcha.rst b/doc/python_api/rst/info_gotcha.rst
index e5ff56063b5..df6e7297e26 100644
--- a/doc/python_api/rst/info_gotcha.rst
+++ b/doc/python_api/rst/info_gotcha.rst
@@ -50,7 +50,8 @@ you should be able to find the poll function with no knowledge of C.
Blender does have the functionality for poll functions to describe why they fail,
but its currently not used much, if you're interested to help improve the API
- feel free to add calls to ``CTX_wm_operator_poll_msg_set`` where its not obvious why poll fails, e.g:
+ feel free to add calls to :class:`bpy.types.Operator.poll_message_set` (``CTX_wm_operator_poll_msg_set`` in C)
+ where its not obvious why poll fails, e.g:
>>> bpy.ops.gpencil.draw()
RuntimeError: Operator bpy.ops.gpencil.draw.poll() Failed to find Grease Pencil data to draw into
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index f6b4b963a7a..ea0f16c9233 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -93,6 +93,7 @@ set(SRC_BVH_HEADERS
bvh/bvh_local.h
bvh/bvh_traversal.h
bvh/bvh_types.h
+ bvh/bvh_util.h
bvh/bvh_volume.h
bvh/bvh_volume_all.h
bvh/bvh_embree.h
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 3049f243ae9..3a3f38539c5 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -29,9 +29,10 @@
# include "kernel/bvh/bvh_embree.h"
#endif
-CCL_NAMESPACE_BEGIN
-
#include "kernel/bvh/bvh_types.h"
+#include "kernel/bvh/bvh_util.h"
+
+CCL_NAMESPACE_BEGIN
#ifndef __KERNEL_OPTIX__
@@ -533,97 +534,4 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
}
#endif /* __VOLUME_RECORD_ALL__ */
-/* Ray offset to avoid self intersection.
- *
- * This function should be used to compute a modified ray start position for
- * rays leaving from a surface. */
-
-ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
-{
-#ifdef __INTERSECTION_REFINE__
- const float epsilon_f = 1e-5f;
- /* ideally this should match epsilon_f, but instancing and motion blur
- * precision makes it problematic */
- const float epsilon_test = 1.0f;
- const int epsilon_i = 32;
-
- float3 res;
-
- /* x component */
- if (fabsf(P.x) < epsilon_test) {
- res.x = P.x + Ng.x * epsilon_f;
- }
- else {
- uint ix = __float_as_uint(P.x);
- ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
- res.x = __uint_as_float(ix);
- }
-
- /* y component */
- if (fabsf(P.y) < epsilon_test) {
- res.y = P.y + Ng.y * epsilon_f;
- }
- else {
- uint iy = __float_as_uint(P.y);
- iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
- res.y = __uint_as_float(iy);
- }
-
- /* z component */
- if (fabsf(P.z) < epsilon_test) {
- res.z = P.z + Ng.z * epsilon_f;
- }
- else {
- uint iz = __float_as_uint(P.z);
- iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
- res.z = __uint_as_float(iz);
- }
-
- return res;
-#else
- const float epsilon_f = 1e-4f;
- return P + epsilon_f * Ng;
-#endif
-}
-
-#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
-/* ToDo: Move to another file? */
-ccl_device int intersections_compare(const void *a, const void *b)
-{
- const Intersection *isect_a = (const Intersection *)a;
- const Intersection *isect_b = (const Intersection *)b;
-
- if (isect_a->t < isect_b->t)
- return -1;
- else if (isect_a->t > isect_b->t)
- return 1;
- else
- return 0;
-}
-#endif
-
-#if defined(__SHADOW_RECORD_ALL__)
-ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
-{
-# ifdef __KERNEL_GPU__
- /* Use bubble sort which has more friendly memory pattern on GPU. */
- bool swapped;
- do {
- swapped = false;
- for (int j = 0; j < num_hits - 1; ++j) {
- if (hits[j].t > hits[j + 1].t) {
- struct Intersection tmp = hits[j];
- hits[j] = hits[j + 1];
- hits[j + 1] = tmp;
- swapped = true;
- }
- }
- --num_hits;
- } while (swapped);
-# else
- qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
-# endif
-}
-#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index dccd257d2de..2e94b1d7c37 100644
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -180,25 +180,10 @@ ccl_device_inline
/* todo: optimize so primitive visibility flag indicates if
* the primitive has a transparent shadow shader? */
- int prim = kernel_tex_fetch(__prim_index, isect_array->prim);
- int shader = 0;
-
-#ifdef __HAIR__
- if (kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
-#endif
- {
- shader = kernel_tex_fetch(__tri_shader, prim);
- }
-#ifdef __HAIR__
- else {
- float4 str = kernel_tex_fetch(__curves, prim);
- shader = __float_as_int(str.z);
- }
-#endif
- int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
+ const int flags = intersection_get_shader_flags(kg, isect_array);
/* if no transparent shadows, all light is blocked */
- if (!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
+ if (!(flags & SD_HAS_TRANSPARENT_SHADOW)) {
return true;
}
/* if maximum number of hits reached, block all light */
diff --git a/intern/cycles/kernel/bvh/bvh_util.h b/intern/cycles/kernel/bvh/bvh_util.h
new file mode 100644
index 00000000000..a694e4dc259
--- /dev/null
+++ b/intern/cycles/kernel/bvh/bvh_util.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Ray offset to avoid self intersection.
+ *
+ * This function should be used to compute a modified ray start position for
+ * rays leaving from a surface. */
+
+ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
+{
+#ifdef __INTERSECTION_REFINE__
+ const float epsilon_f = 1e-5f;
+ /* ideally this should match epsilon_f, but instancing and motion blur
+ * precision makes it problematic */
+ const float epsilon_test = 1.0f;
+ const int epsilon_i = 32;
+
+ float3 res;
+
+ /* x component */
+ if (fabsf(P.x) < epsilon_test) {
+ res.x = P.x + Ng.x * epsilon_f;
+ }
+ else {
+ uint ix = __float_as_uint(P.x);
+ ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
+ res.x = __uint_as_float(ix);
+ }
+
+ /* y component */
+ if (fabsf(P.y) < epsilon_test) {
+ res.y = P.y + Ng.y * epsilon_f;
+ }
+ else {
+ uint iy = __float_as_uint(P.y);
+ iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
+ res.y = __uint_as_float(iy);
+ }
+
+ /* z component */
+ if (fabsf(P.z) < epsilon_test) {
+ res.z = P.z + Ng.z * epsilon_f;
+ }
+ else {
+ uint iz = __float_as_uint(P.z);
+ iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
+ res.z = __uint_as_float(iz);
+ }
+
+ return res;
+#else
+ const float epsilon_f = 1e-4f;
+ return P + epsilon_f * Ng;
+#endif
+}
+
+#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
+/* ToDo: Move to another file? */
+ccl_device int intersections_compare(const void *a, const void *b)
+{
+ const Intersection *isect_a = (const Intersection *)a;
+ const Intersection *isect_b = (const Intersection *)b;
+
+ if (isect_a->t < isect_b->t)
+ return -1;
+ else if (isect_a->t > isect_b->t)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+#if defined(__SHADOW_RECORD_ALL__)
+ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
+{
+ kernel_assert(num_hits > 0);
+
+# ifdef __KERNEL_GPU__
+ /* Use bubble sort which has more friendly memory pattern on GPU. */
+ bool swapped;
+ do {
+ swapped = false;
+ for (int j = 0; j < num_hits - 1; ++j) {
+ if (hits[j].t > hits[j + 1].t) {
+ struct Intersection tmp = hits[j];
+ hits[j] = hits[j + 1];
+ hits[j + 1] = tmp;
+ swapped = true;
+ }
+ }
+ --num_hits;
+ } while (swapped);
+# else
+ qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
+# endif
+}
+#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
+
+/* Utility to quickly get a shader flags from an intersection. */
+
+ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals *ccl_restrict kg,
+ const Intersection *isect)
+{
+ const int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ int shader = 0;
+
+#ifdef __HAIR__
+ if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
+#endif
+ {
+ shader = kernel_tex_fetch(__tri_shader, prim);
+ }
+#ifdef __HAIR__
+ else {
+ float4 str = kernel_tex_fetch(__curves, prim);
+ shader = __float_as_int(str.z);
+ }
+#endif
+
+ return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
+}
+
+ccl_device_forceinline int intersection_get_shader(KernelGlobals *ccl_restrict kg,
+ const Intersection *isect)
+{
+ const int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ int shader = 0;
+
+#ifdef __HAIR__
+ if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
+#endif
+ {
+ shader = kernel_tex_fetch(__tri_shader, prim);
+ }
+#ifdef __HAIR__
+ else {
+ float4 str = kernel_tex_fetch(__curves, prim);
+ shader = __float_as_int(str.z);
+ }
+#endif
+
+ return shader & SHADER_MASK;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 5681510fc25..dd2390808ea 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -65,7 +65,6 @@ ccl_device_forceinline bool kernel_path_scene_intersect(KernelGlobals *kg,
uint visibility = path_state_ray_visibility(kg, state);
if (path_state_ao_bounce(kg, state)) {
- visibility = PATH_RAY_SHADOW;
ray->t = kernel_data.background.ao_distance;
}
@@ -416,7 +415,13 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
break;
}
else if (path_state_ao_bounce(kg, state)) {
- break;
+ if (intersection_get_shader_flags(kg, &isect) &
+ (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ else {
+ break;
+ }
}
/* Setup shader data. */
@@ -554,7 +559,13 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
break;
}
else if (path_state_ao_bounce(kg, state)) {
- break;
+ if (intersection_get_shader_flags(kg, &isect) &
+ (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
+ state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
+ }
+ else {
+ break;
+ }
}
/* Setup shader data. */
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index ab54fda14af..18c4d2f86ad 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -895,6 +895,8 @@ enum ShaderDataFlag {
SD_HAS_CONSTANT_EMISSION = (1 << 27),
/* Needs to access attributes for volume rendering */
SD_NEED_VOLUME_ATTRIBUTES = (1 << 28),
+ /* Shader has emission */
+ SD_HAS_EMISSION = (1 << 29),
SD_SHADER_FLAGS = (SD_USE_MIS | SD_HAS_TRANSPARENT_SHADOW | SD_HAS_VOLUME | SD_HAS_ONLY_VOLUME |
SD_HETEROGENEOUS_VOLUME | SD_HAS_BSSRDF_BUMP | SD_VOLUME_EQUIANGULAR |
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 5ecbd92d96d..44a48cd2839 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -528,6 +528,8 @@ void ShaderManager::device_update_common(Device *device,
if (shader->get_use_mis())
flag |= SD_USE_MIS;
+ if (shader->has_surface_emission)
+ flag |= SD_HAS_EMISSION;
if (shader->has_surface_transparent && shader->get_use_transparent_shadow())
flag |= SD_HAS_TRANSPARENT_SHADOW;
if (shader->has_volume) {
diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h
index 718ec9266b1..8e8caa98a1b 100644
--- a/intern/cycles/util/util_simd.h
+++ b/intern/cycles/util/util_simd.h
@@ -124,7 +124,7 @@ static struct StepTy {
template<class type, int i0, int i1, int i2, int i3> type shuffle_neon(const type &a)
{
if (i0 == i1 && i0 == i2 && i0 == i3) {
- return vdupq_laneq_s32(a, i0);
+ return type(vdupq_laneq_s32(int32x4_t(a), i0));
}
static const uint8_t tbl[16] = {(i0 * 4) + 0,
(i0 * 4) + 1,
@@ -143,7 +143,7 @@ template<class type, int i0, int i1, int i2, int i3> type shuffle_neon(const typ
(i3 * 4) + 2,
(i3 * 4) + 3};
- return vqtbl1q_s8(int8x16_t(a), *(int8x16_t *)tbl);
+ return type(vqtbl1q_s8(int8x16_t(a), *(uint8x16_t *)tbl));
}
template<class type, int i0, int i1, int i2, int i3>
@@ -167,7 +167,7 @@ type shuffle_neon(const type &a, const type &b)
(i3 * 4) + 2,
(i3 * 4) + 3};
- return vqtbl1q_s8(int8x16_t(b), *(int8x16_t *)tbl);
+ return type(vqtbl1q_s8(int8x16_t(b), *(uint8x16_t *)tbl));
}
else {
@@ -188,7 +188,7 @@ type shuffle_neon(const type &a, const type &b)
(i3 * 4) + 2 + 16,
(i3 * 4) + 3 + 16};
- return vqtbl2q_s8((int8x16x2_t){a, b}, *(int8x16_t *)tbl);
+ return type(vqtbl2q_s8((int8x16x2_t){int8x16_t(a), int8x16_t(b)}, *(uint8x16_t *)tbl));
}
}
#endif /* __KERNEL_NEON */
diff --git a/intern/cycles/util/util_sseb.h b/intern/cycles/util/util_sseb.h
index 1488da46b09..4dbd5b8046e 100644
--- a/intern/cycles/util/util_sseb.h
+++ b/intern/cycles/util/util_sseb.h
@@ -283,7 +283,7 @@ __forceinline uint32_t popcnt(const sseb &a)
{
# if defined(__KERNEL_NEON__)
const int32x4_t mask = {1, 1, 1, 1};
- int32x4_t t = vandq_s32(a.m128, mask);
+ int32x4_t t = vandq_s32(vreinterpretq_s32_m128(a.m128), mask);
return vaddvq_s32(t);
# else
return _mm_popcnt_u32(_mm_movemask_ps(a));
@@ -299,7 +299,7 @@ __forceinline uint32_t popcnt(const sseb &a)
__forceinline bool reduce_and(const sseb &a)
{
# if defined(__KERNEL_NEON__)
- return vaddvq_s32(a.m128) == -4;
+ return vaddvq_s32(vreinterpretq_s32_m128(a.m128)) == -4;
# else
return _mm_movemask_ps(a) == 0xf;
# endif
@@ -307,7 +307,7 @@ __forceinline bool reduce_and(const sseb &a)
__forceinline bool reduce_or(const sseb &a)
{
# if defined(__KERNEL_NEON__)
- return vaddvq_s32(a.m128) != 0x0;
+ return vaddvq_s32(vreinterpretq_s32_m128(a.m128)) != 0x0;
# else
return _mm_movemask_ps(a) != 0x0;
# endif
@@ -315,7 +315,7 @@ __forceinline bool reduce_or(const sseb &a)
__forceinline bool all(const sseb &b)
{
# if defined(__KERNEL_NEON__)
- return vaddvq_s32(b.m128) == -4;
+ return vaddvq_s32(vreinterpretq_s32_m128(b.m128)) == -4;
# else
return _mm_movemask_ps(b) == 0xf;
# endif
@@ -323,7 +323,7 @@ __forceinline bool all(const sseb &b)
__forceinline bool any(const sseb &b)
{
# if defined(__KERNEL_NEON__)
- return vaddvq_s32(b.m128) != 0x0;
+ return vaddvq_s32(vreinterpretq_s32_m128(b.m128)) != 0x0;
# else
return _mm_movemask_ps(b) != 0x0;
# endif
@@ -331,7 +331,7 @@ __forceinline bool any(const sseb &b)
__forceinline bool none(const sseb &b)
{
# if defined(__KERNEL_NEON__)
- return vaddvq_s32(b.m128) == 0x0;
+ return vaddvq_s32(vreinterpretq_s32_m128(b.m128)) == 0x0;
# else
return _mm_movemask_ps(b) == 0x0;
# endif
diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h
index d039b50a7d2..0c81ed87553 100644
--- a/intern/cycles/util/util_ssef.h
+++ b/intern/cycles/util/util_ssef.h
@@ -596,7 +596,7 @@ template<size_t i0, size_t i1, size_t i2, size_t i3>
__forceinline const ssef shuffle(const ssef &b)
{
# ifdef __KERNEL_NEON__
- return shuffle_neon<ssef, i0, i1, i2, i3>(b.m128);
+ return shuffle_neon<float32x4_t, i0, i1, i2, i3>(b.m128);
# else
return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(i3, i2, i1, i0)));
# endif
@@ -625,7 +625,7 @@ __forceinline const ssef shuffle(const ssef &a, const ssef &b)
template<size_t i0> __forceinline const ssef shuffle(const ssef &a, const ssef &b)
{
# ifdef __KERNEL_NEON__
- return shuffle<float32x4_t, i0, i0, i0, i0>(a, b);
+ return shuffle_neon<float32x4_t, i0, i0, i0, i0>(a, b);
# else
return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i0, i0, i0, i0));
# endif
diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/util_ssei.h
index 3ec69ab3700..cd51dbff2f1 100644
--- a/intern/cycles/util/util_ssei.h
+++ b/intern/cycles/util/util_ssei.h
@@ -446,7 +446,8 @@ template<size_t i0, size_t i1, size_t i2, size_t i3>
__forceinline const ssei shuffle(const ssei &a)
{
# ifdef __KERNEL_NEON__
- return shuffle_neon<ssei, i0, i1, i2, i3>(a);
+ int32x4_t result = shuffle_neon<int32x4_t, i0, i1, i2, i3>(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(result);
# else
return _mm_shuffle_epi32(a, _MM_SHUFFLE(i3, i2, i1, i0));
# endif
@@ -456,7 +457,9 @@ template<size_t i0, size_t i1, size_t i2, size_t i3>
__forceinline const ssei shuffle(const ssei &a, const ssei &b)
{
# ifdef __KERNEL_NEON__
- return shuffle_neon<ssei, i0, i1, i2, i3>(a, b);
+ int32x4_t result = shuffle_neon<int32x4_t, i0, i1, i2, i3>(vreinterpretq_s32_m128i(a),
+ vreinterpretq_s32_m128i(b));
+ return vreinterpretq_m128i_s32(result);
# else
return _mm_castps_si128(
_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
@@ -514,7 +517,7 @@ __forceinline const ssei vreduce_add(const ssei &v)
__forceinline int reduce_min(const ssei &v)
{
# ifdef __KERNEL_NEON__
- return vminvq_s32(v);
+ return vminvq_s32(vreinterpretq_s32_m128i(v));
# else
return extract<0>(vreduce_min(v));
# endif
@@ -522,7 +525,7 @@ __forceinline int reduce_min(const ssei &v)
__forceinline int reduce_max(const ssei &v)
{
# ifdef __KERNEL_NEON__
- return vmaxvq_s32(v);
+ return vmaxvq_s32(vreinterpretq_s32_m128i(v));
# else
return extract<0>(vreduce_max(v));
# endif
@@ -530,7 +533,7 @@ __forceinline int reduce_max(const ssei &v)
__forceinline int reduce_add(const ssei &v)
{
# ifdef __KERNEL_NEON__
- return vaddvq_s32(v);
+ return vaddvq_s32(vreinterpretq_s32_m128i(v));
# else
return extract<0>(vreduce_add(v));
# endif
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 2c1716ce515..6500a59e42c 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -166,12 +166,33 @@ static void __cpuid(int data[4], int selector)
string system_cpu_brand_string()
{
+#if !defined(WIN32) && !defined(__x86_64__) && !defined(__i386__)
+ FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
+ if (cpuinfo != nullptr) {
+ char cpuinfo_buf[513] = "";
+ fread(cpuinfo_buf, sizeof(cpuinfo_buf) - 1, 1, cpuinfo);
+ fclose(cpuinfo);
+
+ char *modelname = strstr(cpuinfo_buf, "model name");
+ if (modelname != nullptr) {
+ modelname = strchr(modelname, ':');
+ if (modelname != nullptr) {
+ modelname += 2;
+ char *modelname_end = strchr(modelname, '\n');
+ if (modelname_end != nullptr) {
+ *modelname_end = '\0';
+ return modelname;
+ }
+ }
+ }
+ }
+#else
char buf[49] = {0};
int result[4] = {0};
__cpuid(result, 0x80000000);
- if (result[0] >= (int)0x80000004) {
+ if (result[0] != 0 && result[0] >= (int)0x80000004) {
__cpuid((int *)(buf + 0), 0x80000002);
__cpuid((int *)(buf + 16), 0x80000003);
__cpuid((int *)(buf + 32), 0x80000004);
@@ -183,7 +204,7 @@ string system_cpu_brand_string()
return brand;
}
-
+#endif
return "Unknown CPU";
}
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index 70a68ce6847..babb3e30c6d 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index 190f0282339..b7a15bbbc19 100644
--- a/release/scripts/modules/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -219,6 +219,40 @@ def RKS_GEN_scaling(_ksi, _context, ks, data):
else:
ks.paths.add(id_block, path)
+
+# Custom Properties
+def RKS_GEN_custom_props(_ksi, _context, ks, data):
+ # get id-block and path info
+ id_block, base_path, grouping = get_transform_generators_base_info(data)
+
+ # Only some RNA types can be animated.
+ prop_type_compat = {bpy.types.BoolProperty,
+ bpy.types.IntProperty,
+ bpy.types.FloatProperty}
+
+ # When working with a pose, 'id_block' is the armature object (which should
+ # get the animation data), whereas 'data' is the bone being keyed.
+ for cprop_name in data.keys():
+ # ignore special "_RNA_UI" used for UI editing
+ if cprop_name == "_RNA_UI":
+ continue
+
+ prop_path = '["%s"]' % bpy.utils.escape_identifier(cprop_name)
+ try:
+ rna_property = data.path_resolve(prop_path, False)
+ except ValueError as ex:
+ # This happens when a custom property is set to None. In that case it cannot
+ # be converted to an FCurve-compatible value, so we can't keyframe it anyway.
+ continue
+ if rna_property.rna_type not in prop_type_compat:
+ continue
+
+ path = "%s%s" % (base_path, prop_path)
+ if grouping:
+ ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
+ else:
+ ks.paths.add(id_block, path)
+
# ------
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 7547184dc04..f77f00d2234 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -99,6 +99,15 @@ class PREFERENCES_OT_copy_prev(Operator):
version = bpy.app.version
version_new = ((version[0] * 100) + version[1])
version_old = ((version[0] * 100) + version[1]) - 1
+
+ # Special case, remove when the version is > 3.0.
+ if version_new == 300:
+ version_new = 294
+ version_old = 293
+ else:
+ print("TODO: remove exception!")
+ # End special case.
+
# Ensure we only try to copy files from a point release.
# The check below ensures the second numbers match.
while (version_new % 100) // 10 == (version_old % 100) // 10:
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index c1d60a127d2..3064b33c7f7 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -821,6 +821,12 @@ class GreasePencilLayerMasksPanel:
col2.menu("GPENCIL_MT_layer_mask_menu", icon='ADD', text="")
col2.operator("gpencil.layer_mask_remove", icon='REMOVE', text="")
+ col2.separator()
+
+ sub = col2.column(align=True)
+ sub.operator("gpencil.layer_mask_move", icon='TRIA_UP', text="").type = 'UP'
+ sub.operator("gpencil.layer_mask_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
class GreasePencilLayerRelationsPanel:
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index cd65980fc0d..3a97b104271 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -92,16 +92,15 @@ class INFO_MT_area(Menu):
layout.separator()
- layout.operator("screen.area_dupli", icon='WINDOW')
-
- layout.separator()
-
layout.operator("screen.screen_full_area")
layout.operator(
"screen.screen_full_area",
- text="Toggle Fullscreen Area",
- icon='FULLSCREEN_ENTER',
- ).use_hide_panels = True
+ text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.operator("screen.area_dupli")
+
+ layout.separator()
+
+ layout.operator("screen.area_close")
class INFO_MT_context_menu(Menu):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 04b7a11bde1..de78b88c0f6 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -570,7 +570,7 @@ class USERPREF_PT_system_sound(SystemPanel, CenterAlignMixIn, Panel):
layout.prop(system, "audio_device", expand=False)
sub = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
- sub.active = system.audio_device not in {'NONE', 'Null'}
+ sub.active = system.audio_device not in {'NONE', 'None'}
sub.prop(system, "audio_channels", text="Channels")
sub.prop(system, "audio_mixing_buffer", text="Mixing Buffer")
sub.prop(system, "audio_sample_rate", text="Sample Rate")
diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py
index 012febc7cc7..83151a3480c 100644
--- a/release/scripts/startup/keyingsets_builtins.py
+++ b/release/scripts/startup/keyingsets_builtins.py
@@ -44,6 +44,7 @@ ANIM_KS_LOCATION_ID = "Location"
ANIM_KS_ROTATION_ID = "Rotation"
ANIM_KS_SCALING_ID = "Scaling"
ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale"
+ANIM_KS_LOC_ROT_SCALE_CPROP_ID = "LocRotScaleCProp"
ANIM_KS_AVAILABLE_ID = "Available"
ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter"
ANIM_KS_WHOLE_CHARACTER_SELECTED_ID = "WholeCharacterSelected"
@@ -159,6 +160,22 @@ class BUILTIN_KSI_LocRotScale(KeyingSetInfo):
keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
+# LocRotScaleCProp
+class BUILTIN_KSI_LocRotScaleCProp(KeyingSetInfo):
+ """Key location/rotation/scale as well as custom properties"""
+ bl_idname = ANIM_KS_LOC_ROT_SCALE_CPROP_ID
+ bl_label = "Location, Rotation, Scale & Custom Properties"
+
+ poll = keyingsets_utils.RKS_POLL_selected_items
+ iterator = keyingsets_utils.RKS_ITER_selected_item
+
+ def generate(self, context, ks, data):
+ keyingsets_utils.RKS_GEN_location(self, context, ks, data)
+ keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
+ keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
+ keyingsets_utils.RKS_GEN_custom_props(self, context, ks, data)
+
+
# RotScale
class BUILTIN_KSI_RotScale(KeyingSetInfo):
"""Insert a keyframe on each of the rotation and scale channels"""
@@ -350,7 +367,7 @@ class BUILTIN_KSI_Available(KeyingSetInfo):
bl_label = "Available"
# poll - selected objects or selected object with animation data
- def poll(ksi, context):
+ def poll(self, context):
ob = context.active_object
if ob:
# TODO: this fails if one animation-less object is active, but many others are selected
@@ -366,14 +383,7 @@ class BUILTIN_KSI_Available(KeyingSetInfo):
###############################
-
-# All properties that are likely to get animated in a character rig
-class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
- """Insert a keyframe for all properties that are likely to get animated in a character rig """ \
- """(useful when blocking out a shot)"""
- bl_idname = ANIM_KS_WHOLE_CHARACTER_ID
- bl_label = "Whole Character"
-
+class WholeCharacterMixin:
# these prefixes should be avoided, as they are not really bones
# that animators should be touching (or need to touch)
badBonePrefixes = (
@@ -387,38 +397,37 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
)
# poll - pose-mode on active object only
- def poll(ksi, context):
+ def poll(self, context):
return ((context.active_object) and (context.active_object.pose) and
(context.active_object.mode == 'POSE'))
# iterator - all bones regardless of selection
- def iterator(ksi, context, ks):
+ def iterator(self, context, ks):
for bone in context.active_object.pose.bones:
- if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
- ksi.generate(context, ks, bone)
+ if not bone.name.startswith(self.badBonePrefixes):
+ self.generate(context, ks, bone)
# generator - all unlocked bone transforms + custom properties
- def generate(ksi, context, ks, bone):
+ def generate(self, context, ks, bone):
# loc, rot, scale - only include unlocked ones
if not bone.bone.use_connect:
- ksi.doLoc(ks, bone)
+ self.doLoc(ks, bone)
if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
- ksi.doRot4d(ks, bone)
+ self.doRot4d(ks, bone)
else:
- ksi.doRot3d(ks, bone)
- ksi.doScale(ks, bone)
+ self.doRot3d(ks, bone)
+ self.doScale(ks, bone)
# bbone properties?
- ksi.doBBone(context, ks, bone)
+ self.doBBone(context, ks, bone)
# custom props?
- ksi.doCustomProps(ks, bone)
-
+ self.doCustomProps(ks, bone)
# ----------------
# helper to add some bone's property to the Keying Set
- def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
+ def addProp(self, ks, bone, prop, index=-1, use_groups=True):
# add the property name to the base path
id_path = bone.path_from_id()
id_block = bone.id_data
@@ -439,16 +448,16 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
# ----------------
# location properties
- def doLoc(ksi, ks, bone):
+ def doLoc(self, ks, bone):
if bone.lock_location == (False, False, False):
- ksi.addProp(ks, bone, "location")
+ self.addProp(ks, bone, "location")
else:
for i in range(3):
if not bone.lock_location[i]:
- ksi.addProp(ks, bone, "location", i)
+ self.addProp(ks, bone, "location", i)
# rotation properties
- def doRot4d(ksi, ks, bone):
+ def doRot4d(self, ks, bone):
# rotation mode affects the property used
if bone.rotation_mode == 'QUATERNION':
prop = "rotation_quaternion"
@@ -459,40 +468,40 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
if bone.lock_rotations_4d:
# can check individually
if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w is False):
- ksi.addProp(ks, bone, prop)
+ self.addProp(ks, bone, prop)
else:
if bone.lock_rotation_w is False:
- ksi.addProp(ks, bone, prop, 0) # w = 0
+ self.addProp(ks, bone, prop, 0) # w = 0
for i in range(3):
if not bone.lock_rotation[i]:
- ksi.addProp(ks, bone, prop, i + 1) # i + 1, since here x/y/z = 1,2,3, and w=0
+ self.addProp(ks, bone, prop, i + 1) # i + 1, since here x/y/z = 1,2,3, and w=0
elif True not in bone.lock_rotation:
# if axis-angle rotations get locked as eulers, then it's too messy to allow anything
# other than all open unless we keyframe the whole lot
- ksi.addProp(ks, bone, prop)
+ self.addProp(ks, bone, prop)
- def doRot3d(ksi, ks, bone):
+ def doRot3d(self, ks, bone):
if bone.lock_rotation == (False, False, False):
- ksi.addProp(ks, bone, "rotation_euler")
+ self.addProp(ks, bone, "rotation_euler")
else:
for i in range(3):
if not bone.lock_rotation[i]:
- ksi.addProp(ks, bone, "rotation_euler", i)
+ self.addProp(ks, bone, "rotation_euler", i)
# scale properties
- def doScale(ksi, ks, bone):
+ def doScale(self, ks, bone):
if bone.lock_scale == (0, 0, 0):
- ksi.addProp(ks, bone, "scale")
+ self.addProp(ks, bone, "scale")
else:
for i in range(3):
if not bone.lock_scale[i]:
- ksi.addProp(ks, bone, "scale", i)
+ self.addProp(ks, bone, "scale", i)
# ----------------
# bendy bone properties
- def doBBone(ksi, context, ks, pchan):
+ def doBBone(self, context, ks, pchan):
bone = pchan.bone
# This check is crude, but is the best we can do for now
@@ -500,12 +509,12 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
# (and the bone is a control bone). This may lead to some
# false positives...
if bone.bbone_segments > 1:
- keyingsets_utils.RKS_GEN_bendy_bones(ksi, context, ks, pchan)
+ keyingsets_utils.RKS_GEN_bendy_bones(self, context, ks, pchan)
# ----------------
# custom properties
- def doCustomProps(ksi, ks, bone):
+ def doCustomProps(self, ks, bone):
prop_type_compat = {bpy.types.BoolProperty,
bpy.types.IntProperty,
@@ -528,39 +537,34 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
# be converted to an FCurve-compatible value, so we can't keyframe it anyway.
continue
if rna_property.rna_type in prop_type_compat:
- ksi.addProp(ks, bone, prop_path)
+ self.addProp(ks, bone, prop_path)
elif prop_rna.is_animatable:
- ksi.addProp(ks, bone, prop)
+ self.addProp(ks, bone, prop)
-# All properties that are likely to get animated in a character rig, only selected bones.
+
+class BUILTIN_KSI_WholeCharacter(WholeCharacterMixin, KeyingSetInfo):
+ """Insert a keyframe for all properties that are likely to get animated in a character rig """ \
+ """(useful when blocking out a shot)"""
+ bl_idname = ANIM_KS_WHOLE_CHARACTER_ID
+ bl_label = "Whole Character"
-class BUILTIN_KSI_WholeCharacterSelected(KeyingSetInfo):
+class BUILTIN_KSI_WholeCharacterSelected(WholeCharacterMixin, KeyingSetInfo):
"""Insert a keyframe for all properties that are likely to get animated in a character rig """ \
"""(only selected bones)"""
bl_idname = ANIM_KS_WHOLE_CHARACTER_SELECTED_ID
bl_label = "Whole Character (Selected Bones Only)"
# iterator - all bones regardless of selection
- def iterator(ksi, context, ks):
+ def iterator(self, context, ks):
# Use either the selected bones, or all of them if none are selected.
bones = context.selected_pose_bones_from_active_object or context.active_object.pose.bones
for bone in bones:
- if bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
+ if bone.name.startswith(self.badBonePrefixes):
continue
- ksi.generate(context, ks, bone)
-
- # Poor man's subclassing. Blender breaks when we actually subclass BUILTIN_KSI_WholeCharacter.
- poll = BUILTIN_KSI_WholeCharacter.poll
- generate = BUILTIN_KSI_WholeCharacter.generate
- addProp = BUILTIN_KSI_WholeCharacter.addProp
- doLoc = BUILTIN_KSI_WholeCharacter.doLoc
- doRot4d = BUILTIN_KSI_WholeCharacter.doRot4d
- doRot3d = BUILTIN_KSI_WholeCharacter.doRot3d
- doScale = BUILTIN_KSI_WholeCharacter.doScale
- doBBone = BUILTIN_KSI_WholeCharacter.doBBone
- doCustomProps = BUILTIN_KSI_WholeCharacter.doCustomProps
+ self.generate(context, ks, bone)
+
###############################
@@ -578,7 +582,7 @@ class BUILTIN_KSI_DeltaLocation(KeyingSetInfo):
iterator = keyingsets_utils.RKS_ITER_selected_objects
# generator - delta location channels only
- def generate(ksi, context, ks, data):
+ def generate(self, context, ks, data):
# get id-block and path info
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
@@ -604,7 +608,7 @@ class BUILTIN_KSI_DeltaRotation(KeyingSetInfo):
iterator = keyingsets_utils.RKS_ITER_selected_objects
# generator - delta location channels only
- def generate(ksi, context, ks, data):
+ def generate(self, context, ks, data):
# get id-block and path info
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
@@ -638,7 +642,7 @@ class BUILTIN_KSI_DeltaScale(KeyingSetInfo):
iterator = keyingsets_utils.RKS_ITER_selected_objects
# generator - delta location channels only
- def generate(ksi, context, ks, data):
+ def generate(self, context, ks, data):
# get id-block and path info
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
@@ -664,6 +668,7 @@ classes = (
BUILTIN_KSI_Scaling,
BUILTIN_KSI_LocRot,
BUILTIN_KSI_LocRotScale,
+ BUILTIN_KSI_LocRotScaleCProp,
BUILTIN_KSI_LocScale,
BUILTIN_KSI_RotScale,
BUILTIN_KSI_DeltaLocation,
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index ab4d9353e1b..ad2de08bcf2 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -550,6 +550,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeMath"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeFloatCompare"),
+ NodeItem("GeometryNodeSwitch"),
]),
GeometryNodeCategory("GEO_VECTOR", "Vector", items=[
NodeItem("ShaderNodeSeparateXYZ"),
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 120b4e08b9c..5feae1bf4ca 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -20,6 +20,7 @@
#include "FN_cpp_type.hh"
#include "FN_generic_span.hh"
+#include "FN_generic_virtual_array.hh"
#include "BKE_attribute.h"
@@ -30,6 +31,10 @@
namespace blender::bke {
using fn::CPPType;
+using fn::GVArray;
+using fn::GVArrayPtr;
+using fn::GVMutableArray;
+using fn::GVMutableArrayPtr;
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
@@ -37,282 +42,193 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
/**
- * This class offers an indirection for reading an attribute.
- * This is useful for the following reasons:
- * - Blender does not store all attributes the same way.
- * The simplest case are custom data layers with primitive types.
- * A bit more complex are mesh attributes like the position of vertices,
- * which are embedded into the MVert struct.
- * Even more complex to access are vertex weights.
- * - Sometimes attributes are stored on one domain, but we want to access
- * the attribute on a different domain. Therefore, we have to interpolate
- * between the domains.
+ * Used when looking up a "plain attribute" based on a name for reading from it.
*/
-class ReadAttribute {
- protected:
- const AttributeDomain domain_;
- const CPPType &cpp_type_;
- const CustomDataType custom_data_type_;
- const int64_t size_;
-
- /* Protects the span below, so that no two threads initialize it at the same time. */
- mutable std::mutex span_mutex_;
- /* When it is not null, it points to the attribute array or a temporary array that contains all
- * the attribute values. */
- mutable void *array_buffer_ = nullptr;
- /* Is true when the buffer above is owned by the attribute accessor. */
- mutable bool array_is_temporary_ = false;
+struct ReadAttributeLookup {
+ /* The virtual array that is used to read from this attribute. */
+ GVArrayPtr varray;
+ /* Domain the attribute lives on in the geometry. */
+ AttributeDomain domain;
- public:
- ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
- : domain_(domain),
- cpp_type_(cpp_type),
- custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
- size_(size)
- {
- }
-
- virtual ~ReadAttribute();
-
- AttributeDomain domain() const
+ /* Convenience function to check if the attribute has been found. */
+ operator bool() const
{
- return domain_;
+ return this->varray.get() != nullptr;
}
+};
- const CPPType &cpp_type() const
- {
- return cpp_type_;
- }
+/**
+ * Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
+ */
+struct WriteAttributeLookup {
+ /* The virtual array that is used to read from and write to the attribute. */
+ GVMutableArrayPtr varray;
+ /* Domain the attributes lives on in the geometry. */
+ AttributeDomain domain;
- CustomDataType custom_data_type() const
+ /* Convenience function to check if the attribute has been found. */
+ operator bool() const
{
- return custom_data_type_;
+ return this->varray.get() != nullptr;
}
+};
- int64_t size() const
- {
- return size_;
- }
+/**
+ * An output attribute allows writing to an attribute (and optionally reading as well). It adds
+ * some convenience features on top of `GVMutableArray` that are very commonly used.
+ *
+ * Supported convenience features:
+ * - Implicit type conversion when writing to builtin attributes.
+ * - Supports simple access to a span containing the attribute values (that avoids the use of
+ * VMutableArray_Span in many cases).
+ * - An output attribute can live side by side with an existing attribute with a different domain
+ * or data type. The old attribute will only be overwritten when the #save function is called.
+ */
+class OutputAttribute {
+ public:
+ using SaveFn = std::function<void(OutputAttribute &)>;
- void get(const int64_t index, void *r_value) const
- {
- BLI_assert(index < size_);
- this->get_internal(index, r_value);
- }
+ private:
+ GVMutableArrayPtr varray_;
+ AttributeDomain domain_;
+ SaveFn save_;
+ std::optional<fn::GVMutableArray_GSpan> optional_span_varray_;
+ bool ignore_old_values_ = false;
+ bool save_has_been_called_ = false;
- /* Get a span that contains all attribute values. */
- fn::GSpan get_span() const;
+ public:
+ OutputAttribute() = default;
- template<typename T> Span<T> get_span() const
+ OutputAttribute(GVMutableArrayPtr varray,
+ AttributeDomain domain,
+ SaveFn save,
+ const bool ignore_old_values)
+ : varray_(std::move(varray)),
+ domain_(domain),
+ save_(std::move(save)),
+ ignore_old_values_(ignore_old_values)
{
- return this->get_span().typed<T>();
}
- protected:
- /* r_value is expected to be uninitialized. */
- virtual void get_internal(const int64_t index, void *r_value) const = 0;
+ OutputAttribute(OutputAttribute &&other) = default;
- virtual void initialize_span() const;
-};
+ ~OutputAttribute();
-/**
- * This exists for similar reasons as the ReadAttribute class, except that
- * it does not deal with interpolation between domains.
- */
-class WriteAttribute {
- protected:
- const AttributeDomain domain_;
- const CPPType &cpp_type_;
- const CustomDataType custom_data_type_;
- const int64_t size_;
-
- /* When not null, this points either to the attribute array or to a temporary array. */
- void *array_buffer_ = nullptr;
- /* True, when the buffer points to a temporary array. */
- bool array_is_temporary_ = false;
- /* This helps to protect against forgetting to apply changes done to the array. */
- bool array_should_be_applied_ = false;
-
- public:
- WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
- : domain_(domain),
- cpp_type_(cpp_type),
- custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
- size_(size)
+ operator bool() const
{
+ return varray_.get() != nullptr;
}
- virtual ~WriteAttribute();
-
- AttributeDomain domain() const
+ GVMutableArray &operator*()
{
- return domain_;
+ return *varray_;
}
- const CPPType &cpp_type() const
+ GVMutableArray *operator->()
{
- return cpp_type_;
+ return varray_.get();
}
- CustomDataType custom_data_type() const
+ GVMutableArray &varray()
{
- return custom_data_type_;
+ return *varray_;
}
- int64_t size() const
+ AttributeDomain domain() const
{
- return size_;
+ return domain_;
}
- void get(const int64_t index, void *r_value) const
+ const CPPType &cpp_type() const
{
- BLI_assert(index < size_);
- this->get_internal(index, r_value);
+ return varray_->type();
}
- void set(const int64_t index, const void *value)
+ CustomDataType custom_data_type() const
{
- BLI_assert(index < size_);
- this->set_internal(index, value);
+ return cpp_type_to_custom_data_type(this->cpp_type());
}
- /* Get a span that new attribute values can be written into. When all values have been changed,
- * #apply_span has to be called. */
- fn::GMutableSpan get_span();
- /* The span returned by this method might not contain the current attribute values. */
- fn::GMutableSpan get_span_for_write_only();
- /* Write the changes to the span into the actual attribute, if they aren't already. */
- void apply_span();
-
- template<typename T> MutableSpan<T> get_span()
+ fn::GMutableSpan as_span()
{
- return this->get_span().typed<T>();
+ if (!optional_span_varray_.has_value()) {
+ const bool materialize_old_values = !ignore_old_values_;
+ optional_span_varray_.emplace(*varray_, materialize_old_values);
+ }
+ fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
+ return span_varray;
}
- template<typename T> MutableSpan<T> get_span_for_write_only()
+ template<typename T> MutableSpan<T> as_span()
{
- return this->get_span_for_write_only().typed<T>();
+ return this->as_span().typed<T>();
}
- protected:
- virtual void get_internal(const int64_t index, void *r_value) const = 0;
- virtual void set_internal(const int64_t index, const void *value) = 0;
-
- virtual void initialize_span(const bool write_only);
- virtual void apply_span_if_necessary();
+ void save();
};
-using ReadAttributePtr = std::unique_ptr<ReadAttribute>;
-using WriteAttributePtr = std::unique_ptr<WriteAttribute>;
-
-/* This provides type safe access to an attribute.
- * The underlying ReadAttribute is owned optionally. */
-template<typename T> class TypedReadAttribute {
+/**
+ * Same as OutputAttribute, but should be used when the data type is known at compile time.
+ */
+template<typename T> class OutputAttribute_Typed {
private:
- std::unique_ptr<const ReadAttribute> owned_attribute_;
- const ReadAttribute *attribute_;
+ OutputAttribute attribute_;
+ std::optional<fn::GVMutableArray_Typed<T>> optional_varray_;
+ VMutableArray<T> *varray_ = nullptr;
public:
- TypedReadAttribute(ReadAttributePtr attribute) : TypedReadAttribute(*attribute)
- {
- owned_attribute_ = std::move(attribute);
- BLI_assert(owned_attribute_);
- }
-
- TypedReadAttribute(const ReadAttribute &attribute) : attribute_(&attribute)
+ OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
{
- BLI_assert(attribute_->cpp_type().is<T>());
+ if (attribute_) {
+ optional_varray_.emplace(attribute_.varray());
+ varray_ = &**optional_varray_;
+ }
}
- int64_t size() const
+ operator bool() const
{
- return attribute_->size();
+ return varray_ != nullptr;
}
- T operator[](const int64_t index) const
+ VMutableArray<T> &operator*()
{
- BLI_assert(index < attribute_->size());
- T value;
- value.~T();
- attribute_->get(index, &value);
- return value;
+ return *varray_;
}
- /* Get a span to that contains all attribute values for faster and more convenient access. */
- Span<T> get_span() const
+ VMutableArray<T> *operator->()
{
- return attribute_->get_span().template typed<T>();
+ return varray_;
}
-};
-
-/* This provides type safe access to an attribute.
- * The underlying WriteAttribute is owned optionally. */
-template<typename T> class TypedWriteAttribute {
- private:
- std::unique_ptr<WriteAttribute> owned_attribute_;
- WriteAttribute *attribute_;
- public:
- TypedWriteAttribute(WriteAttributePtr attribute) : TypedWriteAttribute(*attribute)
+ VMutableArray<T> &varray()
{
- owned_attribute_ = std::move(attribute);
- BLI_assert(owned_attribute_);
+ return *varray_;
}
- TypedWriteAttribute(WriteAttribute &attribute) : attribute_(&attribute)
- {
- BLI_assert(attribute_->cpp_type().is<T>());
- }
-
- int64_t size() const
+ AttributeDomain domain() const
{
- return attribute_->size();
+ return attribute_.domain();
}
- T operator[](const int64_t index) const
+ const CPPType &cpp_type() const
{
- BLI_assert(index < attribute_->size());
- T value;
- value.~T();
- attribute_->get(index, &value);
- return value;
+ return CPPType::get<T>();
}
- void set(const int64_t index, const T &value)
+ CustomDataType custom_data_type() const
{
- attribute_->set(index, &value);
+ return cpp_type_to_custom_data_type(this->cpp_type());
}
- /* Get a span that new values can be written into. Once all values have been updated #apply_span
- * has to be called. */
- MutableSpan<T> get_span()
+ MutableSpan<T> as_span()
{
- return attribute_->get_span().typed<T>();
- }
- /* The span returned by this method might not contain the current attribute values. */
- MutableSpan<T> get_span_for_write_only()
- {
- return attribute_->get_span_for_write_only().typed<T>();
+ return attribute_.as_span<T>();
}
- /* Write back all changes to the actual attribute, if necessary. */
- void apply_span()
+ void save()
{
- attribute_->apply_span();
+ attribute_.save();
}
};
-using BooleanReadAttribute = TypedReadAttribute<bool>;
-using FloatReadAttribute = TypedReadAttribute<float>;
-using Float2ReadAttribute = TypedReadAttribute<float2>;
-using Float3ReadAttribute = TypedReadAttribute<float3>;
-using Int32ReadAttribute = TypedReadAttribute<int>;
-using Color4fReadAttribute = TypedReadAttribute<Color4f>;
-using BooleanWriteAttribute = TypedWriteAttribute<bool>;
-using FloatWriteAttribute = TypedWriteAttribute<float>;
-using Float2WriteAttribute = TypedWriteAttribute<float2>;
-using Float3WriteAttribute = TypedWriteAttribute<float3>;
-using Int32WriteAttribute = TypedWriteAttribute<int>;
-using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
-
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 16fc0db60fb..65ac5b5bfa8 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -21,13 +21,17 @@
#include "DNA_customdata_types.h"
+#include "FN_cpp_type.hh"
+
namespace blender::attribute_math {
+using fn::CPPType;
+
/**
* Utility function that simplifies calling a templated function based on a custom data type.
*/
template<typename Func>
-void convert_to_static_type(const CustomDataType data_type, const Func &func)
+inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -54,6 +58,32 @@ void convert_to_static_type(const CustomDataType data_type, const Func &func)
}
}
+template<typename Func>
+inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func)
+{
+ if (cpp_type.is<float>()) {
+ func(float());
+ }
+ else if (cpp_type.is<float2>()) {
+ func(float2());
+ }
+ else if (cpp_type.is<float3>()) {
+ func(float3());
+ }
+ else if (cpp_type.is<int>()) {
+ func(int());
+ }
+ else if (cpp_type.is<bool>()) {
+ func(bool());
+ }
+ else if (cpp_type.is<Color4f>()) {
+ func(Color4f());
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+}
+
/* -------------------------------------------------------------------- */
/** \name Mix three values of the same type.
*
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 08aea043fc7..61489aa7494 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -31,15 +31,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 293
+#define BLENDER_VERSION 300
/* 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 19
+#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_context.h b/source/blender/blenkernel/BKE_context.h
index 3d30188e517..50aa6027840 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -206,8 +206,25 @@ void CTX_wm_area_set(bContext *C, struct ScrArea *area);
void CTX_wm_region_set(bContext *C, struct ARegion *region);
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
-const char *CTX_wm_operator_poll_msg_get(struct bContext *C);
+
+/**
+ * Values to create the message that describes the reason poll failed.
+ *
+ * \note This must be called in the same context as the poll function that created it.
+ */
+struct bContextPollMsgDyn_Params {
+ /** The result is allocated . */
+ char *(*get_fn)(bContext *C, void *user_data);
+ /** Optionally free the user-data. */
+ void (*free_fn)(bContext *C, void *user_data);
+ void *user_data;
+};
+
+const char *CTX_wm_operator_poll_msg_get(struct bContext *C, bool *r_free);
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg);
+void CTX_wm_operator_poll_msg_set_dynamic(bContext *C,
+ const struct bContextPollMsgDyn_Params *params);
+void CTX_wm_operator_poll_msg_clear(struct bContext *C);
/* Data Context
*
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index d94b2e7902b..027338a5d5c 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -56,72 +56,77 @@ class ComponentAttributeProviders;
class GeometryComponent;
/**
- * An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final
- * destination yet. Therefore, once the attribute has been filled with data, the #save method has
- * to be called, to store the attribute where it belongs (possibly by replacing an existing
- * attribute with the same name).
- *
- * This is useful for example in the Attribute Color Ramp node, when the same attribute name is
- * used as input and output. Typically the input is a float attribute, and the output is a color.
- * Those two attributes cannot exist at the same time, due to a name collision. To handle this
- * situation well, first the output colors have to be computed before the input floats are deleted.
- * Therefore, the outputs have to be written to a temporary buffer that replaces the existing
- * attribute once all computations are done.
+ * Contains information about an attribute in a geometry component.
+ * More information can be added in the future. E.g. whether the attribute is builtin and how it is
+ * stored (uv map, vertex group, ...).
*/
-class OutputAttributePtr {
- private:
- blender::bke::WriteAttributePtr attribute_;
-
- public:
- OutputAttributePtr() = default;
- OutputAttributePtr(blender::bke::WriteAttributePtr attribute);
- OutputAttributePtr(GeometryComponent &component,
- AttributeDomain domain,
- std::string name,
- CustomDataType data_type);
+struct AttributeMetaData {
+ AttributeDomain domain;
+ CustomDataType data_type;
+};
- ~OutputAttributePtr();
+/* Returns false when the iteration should be stopped. */
+using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name,
+ const AttributeMetaData &meta_data)>;
- /* Returns false, when this wrapper is empty. */
- operator bool() const
+/**
+ * Base class for the attribute intializer types described below.
+ */
+struct AttributeInit {
+ enum class Type {
+ Default,
+ VArray,
+ MoveArray,
+ };
+ Type type;
+ AttributeInit(const Type type) : type(type)
{
- return static_cast<bool>(attribute_);
}
+};
- /* Get a reference to the underlying #WriteAttribute. */
- blender::bke::WriteAttribute &get()
+/**
+ * Create an attribute using the default value for the data type.
+ * The default values may depend on the attribute provider implementation.
+ */
+struct AttributeInitDefault : public AttributeInit {
+ AttributeInitDefault() : AttributeInit(Type::Default)
{
- BLI_assert(attribute_);
- return *attribute_;
}
+};
- blender::bke::WriteAttribute &operator*()
- {
- return *attribute_;
- }
+/**
+ * Create an attribute by copying data from an existing virtual array. The virtual array
+ * must have the same type as the newly created attribute.
+ *
+ * Note that this can be used to fill the new attribute with the default
+ */
+struct AttributeInitVArray : public AttributeInit {
+ const blender::fn::GVArray *varray;
- blender::bke::WriteAttribute *operator->()
+ AttributeInitVArray(const blender::fn::GVArray *varray)
+ : AttributeInit(Type::VArray), varray(varray)
{
- return attribute_.get();
}
-
- void save();
- void apply_span_and_save();
};
/**
- * Contains information about an attribute in a geometry component.
- * More information can be added in the future. E.g. whether the attribute is builtin and how it is
- * stored (uv map, vertex group, ...).
+ * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
+ * Sometimes data is created before a geometry component is available. In that case, it's
+ * preferable to move data directly to the created attribute to avoid a new allocation and a copy.
+ *
+ * Note that this will only have a benefit for attributes that are stored directly as contigious
+ * arrays, so not for some built-in attributes.
+ *
+ * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
+ * can't be used directly, and that is generally how Blender expects custom data to be allocated.
*/
-struct AttributeMetaData {
- AttributeDomain domain;
- CustomDataType data_type;
-};
+struct AttributeInitMove : public AttributeInit {
+ void *data = nullptr;
-/* Returns false when the iteration should be stopped. */
-using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name,
- const AttributeMetaData &meta_data)>;
+ AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
+ {
+ }
+};
/**
* This is the base class for specialized geometry component types.
@@ -156,26 +161,34 @@ class GeometryComponent {
/* Return true when any attribute with this name exists, including built in attributes. */
bool attribute_exists(const blender::StringRef attribute_name) const;
+ /* Return the data type and domain of an attribute with the given name if it exists. */
+ std::optional<AttributeMetaData> attribute_get_meta_data(
+ const blender::StringRef attribute_name) const;
+
/* Returns true when the geometry component supports this attribute domain. */
bool attribute_domain_supported(const AttributeDomain domain) const;
/* Can only be used with supported domain types. */
virtual int attribute_domain_size(const AttributeDomain domain) const;
+ bool attribute_is_builtin(const blender::StringRef attribute_name) const;
+
/* Get read-only access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::StringRef attribute_name) const;
/* Get read and write access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
- blender::bke::WriteAttributePtr attribute_try_get_for_write(
+ blender::bke::WriteAttributeLookup attribute_try_get_for_write(
const blender::StringRef attribute_name);
/* Get a read-only attribute for the domain based on the given attribute. This can be used to
* interpolate from one domain to another.
* Returns null if the interpolation is not implemented. */
- virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain(
- blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const;
+ virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
+ std::unique_ptr<blender::fn::GVArray> varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const;
/* Returns true when the attribute has been deleted. */
bool attribute_try_delete(const blender::StringRef attribute_name);
@@ -183,82 +196,104 @@ class GeometryComponent {
/* Returns true when the attribute has been created. */
bool attribute_try_create(const blender::StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType data_type);
+ const CustomDataType data_type,
+ const AttributeInit &initializer);
+
+ /* Try to create the builtin attribute with the given name. No data type or domain has to be
+ * provided, because those are fixed for builtin attributes. */
+ bool attribute_try_create_builtin(const blender::StringRef attribute_name,
+ const AttributeInit &initializer);
blender::Set<std::string> attribute_names() const;
bool attribute_foreach(const AttributeForeachCallback callback) const;
virtual bool is_empty() const;
- /* Get a read-only attribute for the given domain and data type.
- * Returns null when it does not exist. */
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ /* Get a virtual array to read the data of an attribute on the given domain and data type.
+ * Returns null when the attribute does not exist or cannot be converted to the requested domain
+ * and data type. */
+ std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type) const;
- /* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged.
- * Returns null when the attribute does not exist. */
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ /* Get a virtual array to read the data of an attribute on the given domain. The data type is
+ * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
+ * requested domain. */
+ std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
const blender::StringRef attribute_name, const AttributeDomain domain) const;
- /* Get a read-only attribute for the given domain and data type.
- * Returns a constant attribute based on the default value if the attribute does not exist.
- * Never returns null. */
- blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const;
+ /* Get a virtual array to read data of an attribute with the given data type. The domain is
+ * left unchanged. Returns null when the attribute does not exist or cannot be converted to the
+ * requested data type. */
+ blender::bke::ReadAttributeLookup attribute_try_get_for_read(
+ const blender::StringRef attribute_name, const CustomDataType data_type) const;
- /* Get a typed read-only attribute for the given domain and type. */
- template<typename T>
- blender::bke::TypedReadAttribute<T> attribute_get_for_read(
+ /* Get a virtual array to read the data of an attribute. If that is not possible, the returned
+ * virtual array will contain a default value. This never returns null. */
+ std::unique_ptr<blender::fn::GVArray> attribute_get_for_read(
const blender::StringRef attribute_name,
const AttributeDomain domain,
- const T &default_value) const
+ const CustomDataType data_type,
+ const void *default_value = nullptr) const;
+
+ /* Should be used instead of the method above when the requested data type is known at compile
+ * time for better type safety. */
+ template<typename T>
+ blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const T &default_value) const
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_get_for_read(attribute_name, domain, type, &default_value);
+ std::unique_ptr varray = this->attribute_get_for_read(
+ attribute_name, domain, type, &default_value);
+ return blender::fn::GVArray_Typed<T>(std::move(varray));
}
- /* Get a read-only dummy attribute that always returns the same value. */
- blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain,
- const CustomDataType data_type,
- const void *value) const;
+ /**
+ * Returns an "output attribute", which is essentially a mutable virtual array with some commonly
+ * used convince features. The returned output attribute might be empty if requested attribute
+ * cannot exist on the geometry.
+ *
+ * The included convenience features are:
+ * - Implicit type conversion when writing to builtin attributes.
+ * - If the attribute name exists already, but has a different type/domain, a temporary attribute
+ * is created that will overwrite the existing attribute in the end.
+ */
+ blender::bke::OutputAttribute attribute_try_get_for_output(
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value = nullptr);
- /* Create a read-only dummy attribute that always returns the same value.
- * The given value is converted to the correct type if necessary. */
- blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted(
+ /* Same as attribute_try_get_for_output, but should be used when the original values in the
+ * attributes are not read, i.e. the attribute is used only for output. Since values are not read
+ * from this attribute, no default value is necessary. */
+ blender::bke::OutputAttribute attribute_try_get_for_output_only(
+ const blender::StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType in_data_type,
- const CustomDataType out_data_type,
- const void *value) const;
+ const CustomDataType data_type);
- /* Get a read-only dummy attribute that always returns the same value. */
+ /* Statically typed method corresponding to the equally named generic one. */
template<typename T>
- blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain,
- const T &value) const
+ blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
+ const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value)
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_get_constant_for_read(domain, type, &value);
+ const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value);
}
- /**
- * If an attribute with the given params exist, it is returned.
- * If no attribute with the given name exists, create it and
- * fill it with the default value if it is provided.
- * If an attribute with the given name but different domain or type exists, a temporary attribute
- * is created that has to be saved after the output has been computed. This avoids deleting
- * another attribute, before a computation is finished.
- *
- * This might return no attribute when the attribute cannot exist on the component.
- */
- OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value = nullptr);
+ /* Statically typed method corresponding to the equally named generic one. */
+ template<typename T>
+ blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
+ const blender::StringRef attribute_name, const AttributeDomain domain)
+ {
+ const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
+ const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ return this->attribute_try_get_for_output_only(attribute_name, domain, data_type);
+ }
private:
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
@@ -377,8 +412,10 @@ class MeshComponent : public GeometryComponent {
Mesh *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
- blender::bke::ReadAttributePtr attribute_try_adapt_domain(
- blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const final;
+ std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
+ std::unique_ptr<blender::fn::GVArray> varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const final;
bool is_empty() const final;
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
new file mode 100644
index 00000000000..f504650e349
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "FN_generic_virtual_array.hh"
+
+#include "BLI_float3.hh"
+
+#include "BKE_attribute.h"
+
+struct Mesh;
+
+namespace blender::bke::mesh_surface_sample {
+
+using fn::CPPType;
+using fn::GMutableSpan;
+using fn::GSpan;
+using fn::GVArray;
+
+void sample_point_attribute(const Mesh &mesh,
+ Span<int> looptri_indices,
+ Span<float3> bary_coords,
+ const GVArray &data_in,
+ GMutableSpan data_out);
+
+void sample_corner_attribute(const Mesh &mesh,
+ Span<int> looptri_indices,
+ Span<float3> bary_coords,
+ const GVArray &data_in,
+ GMutableSpan data_out);
+
+void sample_face_attribute(const Mesh &mesh,
+ Span<int> looptri_indices,
+ const GVArray &data_in,
+ GMutableSpan data_out);
+
+} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d6c4ad037e2..2a33c4819e3 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1413,6 +1413,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
#define GEO_NODE_BOUNDING_BOX 1042
+#define GEO_NODE_SWITCH 1043
/** \} */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 59e2c74ead1..adf321da8f0 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -190,6 +190,7 @@ set(SRC
intern/mesh_remap.c
intern/mesh_remesh_voxel.c
intern/mesh_runtime.c
+ intern/mesh_sample.cc
intern/mesh_tangent.c
intern/mesh_validate.c
intern/mesh_validate.cc
@@ -379,6 +380,7 @@ set(SRC
BKE_mesh_remap.h
BKE_mesh_remesh_voxel.h
BKE_mesh_runtime.h
+ BKE_mesh_sample.hh
BKE_mesh_tangent.h
BKE_mesh_types.h
BKE_mesh_wrapper.h
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 1075a46e72b..bcfd34ab42f 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -137,7 +137,7 @@ static char *blender_version_decimal(const int version)
{
static char version_str[5];
BLI_assert(version < 1000);
- BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", version / 100, version % 100);
+ BLI_snprintf(version_str, sizeof(version_str), "%d.%d", version / 100, version % 100);
return version_str;
}
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index ac582fc30e7..5b2f588959f 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -44,196 +44,10 @@ using blender::float3;
using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
-using blender::bke::ReadAttributePtr;
-using blender::bke::WriteAttributePtr;
using blender::fn::GMutableSpan;
namespace blender::bke {
-/* -------------------------------------------------------------------- */
-/** \name Attribute Accessor implementations
- * \{ */
-
-ReadAttribute::~ReadAttribute()
-{
- if (array_is_temporary_ && array_buffer_ != nullptr) {
- cpp_type_.destruct_n(array_buffer_, size_);
- MEM_freeN(array_buffer_);
- }
-}
-
-fn::GSpan ReadAttribute::get_span() const
-{
- if (size_ == 0) {
- return fn::GSpan(cpp_type_);
- }
- if (array_buffer_ == nullptr) {
- std::lock_guard lock{span_mutex_};
- if (array_buffer_ == nullptr) {
- this->initialize_span();
- }
- }
- return fn::GSpan(cpp_type_, array_buffer_, size_);
-}
-
-void ReadAttribute::initialize_span() const
-{
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- for (const int i : IndexRange(size_)) {
- this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
- }
-}
-
-WriteAttribute::~WriteAttribute()
-{
- if (array_should_be_applied_) {
- CLOG_ERROR(&LOG, "Forgot to call apply_span.");
- }
- if (array_is_temporary_ && array_buffer_ != nullptr) {
- cpp_type_.destruct_n(array_buffer_, size_);
- MEM_freeN(array_buffer_);
- }
-}
-
-/**
- * Get a mutable span that can be modified. When all modifications to the attribute are done,
- * #apply_span should be called. */
-fn::GMutableSpan WriteAttribute::get_span()
-{
- if (size_ == 0) {
- return fn::GMutableSpan(cpp_type_);
- }
- if (array_buffer_ == nullptr) {
- this->initialize_span(false);
- }
- array_should_be_applied_ = true;
- return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
-}
-
-fn::GMutableSpan WriteAttribute::get_span_for_write_only()
-{
- if (size_ == 0) {
- return fn::GMutableSpan(cpp_type_);
- }
- if (array_buffer_ == nullptr) {
- this->initialize_span(true);
- }
- array_should_be_applied_ = true;
- return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
-}
-
-void WriteAttribute::initialize_span(const bool write_only)
-{
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(element_size * size_, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- if (write_only) {
- /* This does nothing for trivial types, but is necessary for general correctness. */
- cpp_type_.construct_default_n(array_buffer_, size_);
- }
- else {
- for (const int i : IndexRange(size_)) {
- this->get(i, POINTER_OFFSET(array_buffer_, i * element_size));
- }
- }
-}
-
-void WriteAttribute::apply_span()
-{
- this->apply_span_if_necessary();
- array_should_be_applied_ = false;
-}
-
-void WriteAttribute::apply_span_if_necessary()
-{
- /* Only works when the span has been initialized beforehand. */
- BLI_assert(array_buffer_ != nullptr);
-
- const int element_size = cpp_type_.size();
- for (const int i : IndexRange(size_)) {
- this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
- }
-}
-
-/* This is used by the #OutputAttributePtr class. */
-class TemporaryWriteAttribute final : public WriteAttribute {
- public:
- GMutableSpan data;
- GeometryComponent &component;
- std::string final_name;
-
- TemporaryWriteAttribute(AttributeDomain domain,
- GMutableSpan data,
- GeometryComponent &component,
- std::string final_name)
- : WriteAttribute(domain, data.type(), data.size()),
- data(data),
- component(component),
- final_name(std::move(final_name))
- {
- }
-
- ~TemporaryWriteAttribute() override
- {
- if (data.data() != nullptr) {
- cpp_type_.destruct_n(data.data(), data.size());
- MEM_freeN(data.data());
- }
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- data.type().copy_to_uninitialized(data[index], r_value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- data.type().copy_to_initialized(value, data[index]);
- }
-
- void initialize_span(const bool UNUSED(write_only)) override
- {
- array_buffer_ = data.data();
- array_is_temporary_ = false;
- }
-
- void apply_span_if_necessary() override
- {
- /* Do nothing, because the span contains the attribute itself already. */
- }
-};
-
-class ConvertedReadAttribute final : public ReadAttribute {
- private:
- const CPPType &from_type_;
- const CPPType &to_type_;
- ReadAttributePtr base_attribute_;
- void (*convert_)(const void *src, void *dst);
-
- public:
- ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
- : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
- from_type_(base_attribute->cpp_type()),
- to_type_(to_type),
- base_attribute_(std::move(base_attribute))
- {
- const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
- convert_ = conversions.get_conversion_functions(base_attribute_->cpp_type(), to_type)
- ->convert_single_to_uninitialized;
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
- base_attribute_->get(index, buffer);
- convert_(buffer, r_value);
- }
-};
-
-/** \} */
-
const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
{
switch (type) {
@@ -368,7 +182,27 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
-ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
+void OutputAttribute::save()
+{
+ save_has_been_called_ = true;
+ if (optional_span_varray_.has_value()) {
+ optional_span_varray_->save();
+ }
+ if (save_) {
+ save_(*this);
+ }
+}
+
+OutputAttribute::~OutputAttribute()
+{
+ if (!save_has_been_called_) {
+ if (varray_) {
+ std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
+ }
+ }
+}
+
+GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read(
const GeometryComponent &component) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -384,7 +218,7 @@ ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
return as_read_attribute_(data, domain_size);
}
-WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write(
+GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
GeometryComponent &component) const
{
if (writable_ != Writable) {
@@ -430,7 +264,43 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
return delete_success;
}
-bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const
+static bool add_custom_data_layer_from_attribute_init(CustomData &custom_data,
+ const CustomDataType data_type,
+ const int domain_size,
+ const AttributeInit &initializer)
+{
+ switch (initializer.type) {
+ case AttributeInit::Type::Default: {
+ void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+ return data != nullptr;
+ }
+ case AttributeInit::Type::VArray: {
+ void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+ if (data == nullptr) {
+ return false;
+ }
+ const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+ varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
+ return true;
+ }
+ case AttributeInit::Type::MoveArray: {
+ void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+ void *data = CustomData_add_layer(
+ &custom_data, data_type, CD_ASSIGN, source_data, domain_size);
+ if (data == nullptr) {
+ MEM_freeN(source_data);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ BLI_assert_unreachable();
+ return false;
+}
+
+bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
+ const AttributeInit &initializer) const
{
if (createable_ != Creatable) {
return false;
@@ -443,10 +313,10 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) co
/* Exists already. */
return false;
}
+
const int domain_size = component.attribute_domain_size(domain_);
- const void *data = CustomData_add_layer(
- custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
- const bool success = data != nullptr;
+ const bool success = add_custom_data_layer_from_attribute_init(
+ *custom_data, stored_type_, domain_size, initializer);
if (success) {
custom_data_access_.update_custom_data_pointers(component);
}
@@ -463,7 +333,7 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
return data != nullptr;
}
-ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
+ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
const GeometryComponent &component, const StringRef attribute_name) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -496,7 +366,7 @@ ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
return {};
}
-WriteAttributePtr CustomDataAttributeProvider::try_get_for_write(
+WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
GeometryComponent &component, const StringRef attribute_name) const
{
CustomData *custom_data = custom_data_access_.get_custom_data(component);
@@ -548,10 +418,52 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
return false;
}
+static bool add_named_custom_data_layer_from_attribute_init(const StringRef attribute_name,
+ CustomData &custom_data,
+ const CustomDataType data_type,
+ const int domain_size,
+ const AttributeInit &initializer)
+{
+ char attribute_name_c[MAX_NAME];
+ attribute_name.copy(attribute_name_c);
+
+ switch (initializer.type) {
+ case AttributeInit::Type::Default: {
+ void *data = CustomData_add_layer_named(
+ &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ return data != nullptr;
+ }
+ case AttributeInit::Type::VArray: {
+ void *data = CustomData_add_layer_named(
+ &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ if (data == nullptr) {
+ return false;
+ }
+ const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+ varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
+ return true;
+ }
+ case AttributeInit::Type::MoveArray: {
+ void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+ void *data = CustomData_add_layer_named(
+ &custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_name_c);
+ if (data == nullptr) {
+ MEM_freeN(source_data);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ BLI_assert_unreachable();
+ return false;
+}
+
bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
const StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType data_type) const
+ const CustomDataType data_type,
+ const AttributeInit &initializer) const
{
if (domain_ != domain) {
return false;
@@ -569,10 +481,8 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
}
}
const int domain_size = component.attribute_domain_size(domain_);
- char attribute_name_c[MAX_NAME];
- attribute_name.copy(attribute_name_c);
- CustomData_add_layer_named(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ add_named_custom_data_layer_from_attribute_init(
+ attribute_name, *custom_data, data_type, domain_size, initializer);
return true;
}
@@ -595,7 +505,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
return true;
}
-ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
+ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
const GeometryComponent &component, const StringRef attribute_name) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -606,14 +516,14 @@ ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
if (layer.type == stored_type_) {
if (layer.name == attribute_name) {
const int domain_size = component.attribute_domain_size(domain_);
- return as_read_attribute_(layer.data, domain_size);
+ return {as_read_attribute_(layer.data, domain_size), domain_};
}
}
}
return {};
}
-WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
+WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
GeometryComponent &component, const StringRef attribute_name) const
{
CustomData *custom_data = custom_data_access_.get_custom_data(component);
@@ -630,7 +540,7 @@ WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
if (data_old != data_new) {
custom_data_access_.update_custom_data_pointers(component);
}
- return as_write_attribute_(layer.data, domain_size);
+ return {as_write_attribute_(layer.data, domain_size), domain_};
}
}
}
@@ -708,7 +618,17 @@ int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain
return 0;
}
-ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
+bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const
+{
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return false;
+ }
+ return providers->builtin_attribute_providers().contains_as(attribute_name);
+}
+
+blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name) const
{
using namespace blender::bke;
@@ -719,11 +639,11 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider != nullptr) {
- return builtin_provider->try_get_for_read(*this);
+ return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
- ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
+ ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
if (attribute) {
return attribute;
}
@@ -731,16 +651,19 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
return {};
}
-ReadAttributePtr GeometryComponent::attribute_try_adapt_domain(
- ReadAttributePtr attribute, const AttributeDomain new_domain) const
+std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain(
+ std::unique_ptr<blender::fn::GVArray> varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
- if (attribute && attribute->domain() == new_domain) {
- return attribute;
+ if (from_domain == to_domain) {
+ return varray;
}
return {};
}
-WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef attribute_name)
+blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
+ const StringRef attribute_name)
{
using namespace blender::bke;
const ComponentAttributeProviders *providers = this->get_attribute_providers();
@@ -750,11 +673,11 @@ WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider != nullptr) {
- return builtin_provider->try_get_for_write(*this);
+ return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
- WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
+ WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
if (attribute) {
return attribute;
}
@@ -784,7 +707,8 @@ bool GeometryComponent::attribute_try_delete(const StringRef attribute_name)
bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType data_type)
+ const CustomDataType data_type,
+ const AttributeInit &initializer)
{
using namespace blender::bke;
if (attribute_name.is_empty()) {
@@ -803,17 +727,36 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
if (builtin_provider->data_type() != data_type) {
return false;
}
- return builtin_provider->try_create(*this);
+ return builtin_provider->try_create(*this, initializer);
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
- if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) {
+ if (dynamic_provider->try_create(*this, attribute_name, domain, data_type, initializer)) {
return true;
}
}
return false;
}
+bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name,
+ const AttributeInit &initializer)
+{
+ using namespace blender::bke;
+ if (attribute_name.is_empty()) {
+ return false;
+ }
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return false;
+ }
+ const BuiltinAttributeProvider *builtin_provider =
+ providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
+ if (builtin_provider == nullptr) {
+ return false;
+ }
+ return builtin_provider->try_create(*this, initializer);
+}
+
Set<std::string> GeometryComponent::attribute_names() const
{
Set<std::string> attributes;
@@ -867,264 +810,283 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
{
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (attribute) {
return true;
}
return false;
}
-static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute,
- const blender::fn::CPPType &to_type)
+std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
+ const StringRef attribute_name) const
{
- const blender::fn::CPPType &from_type = attribute->cpp_type();
- if (from_type == to_type) {
- return attribute;
- }
+ std::optional<AttributeMetaData> result{std::nullopt};
+ this->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
+ if (attribute_name == name) {
+ result = meta_data;
+ return false;
+ }
+ return true;
+ });
+ return result;
+}
+static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type(
+ std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type)
+{
const blender::nodes::DataTypeConversions &conversions =
blender::nodes::get_implicit_type_conversions();
- if (!conversions.is_convertible(from_type, to_type)) {
- return {};
- }
-
- return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type);
+ return conversions.try_convert(std::move(varray), to_type);
}
-ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
+std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type) const
{
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
}
- if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
- attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
- if (!attribute) {
+ std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray);
+ if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) {
+ varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
+ if (!varray) {
return {};
}
}
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
- if (attribute->cpp_type() != *cpp_type) {
- attribute = try_adapt_data_type(std::move(attribute), *cpp_type);
- if (!attribute) {
+ if (varray->type() != *cpp_type) {
+ varray = try_adapt_data_type(std::move(varray), *cpp_type);
+ if (!varray) {
return {};
}
}
- return attribute;
+ return varray;
}
-ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name,
- const AttributeDomain domain) const
+std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read(
+ const StringRef attribute_name, const AttributeDomain domain) const
{
if (!this->attribute_domain_supported(domain)) {
return {};
}
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
}
- if (attribute->domain() != domain) {
- attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
- if (!attribute) {
- return {};
- }
+ if (attribute.domain != domain) {
+ return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain);
}
- return attribute;
+ return std::move(attribute.varray);
}
-ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const
+blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
+ const blender::StringRef attribute_name, const CustomDataType data_type) const
{
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
- if (attribute) {
- return attribute;
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
+ if (!attribute) {
+ return {};
}
- return this->attribute_get_constant_for_read(domain, data_type, default_value);
-}
-
-blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read(
- const AttributeDomain domain, const CustomDataType data_type, const void *value) const
-{
- BLI_assert(this->attribute_domain_supported(domain));
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
- if (value == nullptr) {
- value = cpp_type->default_value();
+ const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ BLI_assert(type != nullptr);
+ if (attribute.varray->type() == *type) {
+ return attribute;
}
- const int domain_size = this->attribute_domain_size(domain);
- return std::make_unique<blender::bke::ConstantReadAttribute>(
- domain, domain_size, *cpp_type, value);
+ const blender::nodes::DataTypeConversions &conversions =
+ blender::nodes::get_implicit_type_conversions();
+ return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
}
-blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted(
+std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read(
+ const StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType in_data_type,
- const CustomDataType out_data_type,
- const void *value) const
+ const CustomDataType data_type,
+ const void *default_value) const
{
- BLI_assert(this->attribute_domain_supported(domain));
- if (value == nullptr || in_data_type == out_data_type) {
- return this->attribute_get_constant_for_read(domain, out_data_type, value);
+ std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read(
+ attribute_name, domain, data_type);
+ if (varray) {
+ return varray;
+ }
+ const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ if (default_value == nullptr) {
+ default_value = type->default_value();
}
-
- const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type(
- in_data_type);
- const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type(
- out_data_type);
- BLI_assert(in_cpp_type != nullptr);
- BLI_assert(out_cpp_type != nullptr);
-
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
- BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type));
-
- void *out_value = alloca(out_cpp_type->size());
- conversions.convert_to_uninitialized(*in_cpp_type, *out_cpp_type, value, out_value);
-
const int domain_size = this->attribute_domain_size(domain);
- blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>(
- domain, domain_size, *out_cpp_type, out_value);
-
- out_cpp_type->destruct(out_value);
- return attribute;
+ return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value);
}
-OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value)
-{
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
-
- WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
+class GVMutableAttribute_For_OutputAttribute
+ : public blender::fn::GVMutableArray_For_GMutableSpan {
+ public:
+ GeometryComponent *component;
+ std::string final_name;
- /* If the attribute doesn't exist, make a new one with the correct type. */
- if (!attribute) {
- this->attribute_try_create(attribute_name, domain, data_type);
- attribute = this->attribute_try_get_for_write(attribute_name);
- if (attribute && default_value != nullptr) {
- void *data = attribute->get_span_for_write_only().data();
- cpp_type->fill_initialized(default_value, data, attribute->size());
- attribute->apply_span();
- }
- return OutputAttributePtr(std::move(attribute));
+ GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
+ GeometryComponent &component,
+ std::string final_name)
+ : blender::fn::GVMutableArray_For_GMutableSpan(data),
+ component(&component),
+ final_name(std::move(final_name))
+ {
}
- /* If an existing attribute has a matching domain and type, just use that. */
- if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
- return OutputAttributePtr(std::move(attribute));
+ ~GVMutableAttribute_For_OutputAttribute() override
+ {
+ type_->destruct_n(data_, size_);
+ MEM_freeN(data_);
}
+};
- /* Otherwise create a temporary buffer to use before saving the new attribute. */
- return OutputAttributePtr(*this, domain, attribute_name, data_type);
-}
-
-/* Construct from an attribute that already exists in the geometry component. */
-OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute)
- : attribute_(std::move(attribute))
+static void save_output_attribute(blender::bke::OutputAttribute &output_attribute)
{
-}
+ using namespace blender;
+ using namespace blender::fn;
+ using namespace blender::bke;
-/* Construct a temporary attribute that has to replace an existing one later on. */
-OutputAttributePtr::OutputAttributePtr(GeometryComponent &component,
- AttributeDomain domain,
- std::string final_name,
- CustomDataType data_type)
-{
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
+ GVMutableAttribute_For_OutputAttribute &varray =
+ dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray());
- const int domain_size = component.attribute_domain_size(domain);
- void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
- GMutableSpan new_span{*cpp_type, buffer, domain_size};
+ GeometryComponent &component = *varray.component;
+ const StringRefNull name = varray.final_name;
+ const AttributeDomain domain = output_attribute.domain();
+ const CustomDataType data_type = output_attribute.custom_data_type();
+ const CPPType &cpp_type = output_attribute.cpp_type();
- /* Copy converted values from conflicting attribute, in case the value is read.
- * TODO: An optimization could be to not do this, when the caller says that the attribute will
- * only be written. */
- ReadAttributePtr src_attribute = component.attribute_get_for_read(
- final_name, domain, data_type, nullptr);
- for (const int i : blender::IndexRange(domain_size)) {
- src_attribute->get(i, new_span[i]);
+ component.attribute_try_delete(name);
+ if (!component.attribute_try_create(
+ varray.final_name, domain, data_type, AttributeInitDefault())) {
+ CLOG_WARN(&LOG,
+ "Could not create the '%s' attribute with type '%s'.",
+ name.c_str(),
+ cpp_type.name().c_str());
+ return;
+ }
+ WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
+ BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
+ for (const int i : IndexRange(varray.size())) {
+ varray.get(i, buffer);
+ write_attribute.varray->set_by_relocate(i, buffer);
}
-
- attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
- domain, new_span, component, std::move(final_name));
}
-/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
- * might delete another attribute with the same name. */
-void OutputAttributePtr::save()
+static blender::bke::OutputAttribute create_output_attribute(
+ GeometryComponent &component,
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const bool ignore_old_values,
+ const void *default_value)
{
- if (!attribute_) {
- CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore.");
- return;
+ using namespace blender;
+ using namespace blender::fn;
+ using namespace blender::bke;
+
+ if (attribute_name.is_empty()) {
+ return {};
}
- blender::bke::TemporaryWriteAttribute *attribute =
- dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get());
+ const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
+ BLI_assert(cpp_type != nullptr);
+ const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
- if (attribute == nullptr) {
- /* The attribute is saved already. */
- attribute_.reset();
- return;
+ if (component.attribute_is_builtin(attribute_name)) {
+ WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ if (default_value) {
+ const int64_t domain_size = component.attribute_domain_size(domain);
+ const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
+ component.attribute_try_create_builtin(attribute_name,
+ AttributeInitVArray(&default_varray));
+ }
+ else {
+ component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
+ }
+ attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ /* Builtin attribute does not exist and can't be created. */
+ return {};
+ }
+ }
+ if (attribute.domain != domain) {
+ /* Builtin attribute is on different domain. */
+ return {};
+ }
+ GVMutableArrayPtr varray = std::move(attribute.varray);
+ if (varray->type() == *cpp_type) {
+ /* Builtin attribute matches exactly. */
+ return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+ }
+ /* Builtin attribute is on the same domain but has a different data type. */
+ varray = conversions.try_convert(std::move(varray), *cpp_type);
+ return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
}
- StringRefNull name = attribute->final_name;
- const blender::fn::CPPType &cpp_type = attribute->cpp_type();
+ const int domain_size = component.attribute_domain_size(domain);
- /* Delete an existing attribute with the same name if necessary. */
- attribute->component.attribute_try_delete(name);
+ WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ if (default_value) {
+ const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
+ component.attribute_try_create(
+ attribute_name, domain, data_type, AttributeInitVArray(&default_varray));
+ }
+ else {
+ component.attribute_try_create(attribute_name, domain, data_type, AttributeInitDefault());
+ }
- if (!attribute->component.attribute_try_create(
- name, attribute_->domain(), attribute_->custom_data_type())) {
- /* Cannot create the target attribute for some reason. */
- CLOG_WARN(&LOG,
- "Creating the '%s' attribute with type '%s' failed.",
- name.c_str(),
- cpp_type.name().c_str());
- attribute_.reset();
- return;
+ attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ /* Can't create the attribute. */
+ return {};
+ }
+ }
+ if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
+ /* Existing generic attribute matches exactly. */
+ return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
}
- WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name);
-
- GMutableSpan temp_span = attribute->data;
- GMutableSpan new_span = new_attribute->get_span_for_write_only();
- BLI_assert(temp_span.size() == new_span.size());
-
- /* Currently we copy over the attribute. In the future we want to reuse the buffer. */
- cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size());
- new_attribute->apply_span();
+ /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
+ * attribute after processing is done. */
+ void *data = MEM_mallocN_aligned(
+ cpp_type->size() * domain_size, cpp_type->alignment(), __func__);
+ if (ignore_old_values) {
+ /* This does nothing for trivially constructible types, but is necessary for correctness. */
+ cpp_type->construct_default_n(data, domain);
+ }
+ else {
+ /* Fill the temporary array with values from the existing attribute. */
+ GVArrayPtr old_varray = component.attribute_get_for_read(
+ attribute_name, domain, data_type, default_value);
+ old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
+ }
+ GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>(
+ GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name);
- attribute_.reset();
+ return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
}
-OutputAttributePtr::~OutputAttributePtr()
+blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value)
{
- if (attribute_) {
- CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save.");
- }
+ return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value);
}
-/* Utility function to call #apply_span and #save in the right order. */
-void OutputAttributePtr::apply_span_and_save()
+blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
{
- BLI_assert(attribute_);
- attribute_->apply_span();
- this->save();
+ return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr);
}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 806d10e9e89..b3a795faa30 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -24,166 +24,8 @@
namespace blender::bke {
-class ConstantReadAttribute final : public ReadAttribute {
- private:
- void *value_;
-
- public:
- ConstantReadAttribute(AttributeDomain domain,
- const int64_t size,
- const CPPType &type,
- const void *value)
- : ReadAttribute(domain, type, size)
- {
- value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
- type.copy_to_uninitialized(value, value_);
- }
-
- ~ConstantReadAttribute() override
- {
- this->cpp_type_.destruct(value_);
- MEM_freeN(value_);
- }
-
- void get_internal(const int64_t UNUSED(index), void *r_value) const override
- {
- this->cpp_type_.copy_to_uninitialized(value_, r_value);
- }
-
- void initialize_span() const override
- {
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
- }
-};
-
-template<typename T> class ArrayReadAttribute final : public ReadAttribute {
- private:
- Span<T> data_;
-
- public:
- ArrayReadAttribute(AttributeDomain domain, Span<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
- private:
- Array<T> data_;
-
- public:
- OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class DerivedArrayReadAttribute final : public ReadAttribute {
- private:
- Span<StructT> data_;
-
- public:
- DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
- : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-};
-
-template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<T> data_;
-
- public:
- ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
- : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- data_[index] = *reinterpret_cast<const T *>(value);
- }
-
- void initialize_span(const bool UNUSED(write_only)) override
- {
- array_buffer_ = data_.data();
- array_is_temporary_ = false;
- }
-
- void apply_span_if_necessary() override
- {
- /* Do nothing, because the span contains the attribute itself already. */
- }
-};
-
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, const ElemT &)>
-class DerivedArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<StructT> data_;
-
- public:
- DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
- : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- StructT &struct_value = data_[index];
- const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
- SetFunc(struct_value, typed_value);
- }
-};
+using fn::GVArrayPtr;
+using fn::GVMutableArrayPtr;
/**
* Utility to group together multiple functions that are used to access custom data on geometry
@@ -244,10 +86,11 @@ class BuiltinAttributeProvider {
{
}
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
+ virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0;
+ virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0;
virtual bool try_delete(GeometryComponent &component) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
+ virtual bool try_create(GeometryComponent &UNUSED(component),
+ const AttributeInit &UNUSED(initializer)) const = 0;
virtual bool exists(const GeometryComponent &component) const = 0;
StringRefNull name() const
@@ -272,15 +115,16 @@ class BuiltinAttributeProvider {
*/
class DynamicAttributesProvider {
public:
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const = 0;
+ virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const = 0;
+ virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const = 0;
virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component),
const StringRef UNUSED(attribute_name),
const AttributeDomain UNUSED(domain),
- const CustomDataType UNUSED(data_type)) const
+ const CustomDataType UNUSED(data_type),
+ const AttributeInit &UNUSED(initializer)) const
{
/* Some providers should not create new attributes. */
return false;
@@ -309,18 +153,19 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final;
+ ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final;
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
bool try_create(GeometryComponent &component,
const StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType data_type) const final;
+ const CustomDataType data_type,
+ const AttributeInit &initializer) const final;
bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const final;
@@ -332,18 +177,21 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
private:
template<typename T>
- ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
- const int domain_size) const
+ ReadAttributeLookup layer_to_read_attribute(const CustomDataLayer &layer,
+ const int domain_size) const
{
- return std::make_unique<ArrayReadAttribute<T>>(
- domain_, Span(static_cast<const T *>(layer.data), domain_size));
+ return {std::make_unique<fn::GVArray_For_Span<T>>(
+ Span(static_cast<const T *>(layer.data), domain_size)),
+ domain_};
}
template<typename T>
- WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
+ WriteAttributeLookup layer_to_write_attribute(CustomDataLayer &layer,
+ const int domain_size) const
{
- return std::make_unique<ArrayWriteAttribute<T>>(
- domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
+ return {std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
+ MutableSpan(static_cast<T *>(layer.data), domain_size)),
+ domain_};
}
bool type_is_supported(CustomDataType data_type) const
@@ -357,8 +205,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
*/
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
const AttributeDomain domain_;
const CustomDataType attribute_type_;
const CustomDataType stored_type_;
@@ -382,10 +230,10 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final;
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final;
+ ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const final;
@@ -398,8 +246,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
* the #MVert struct, but is exposed as float3 attribute.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
using UpdateOnRead = void (*)(const GeometryComponent &component);
using UpdateOnWrite = void (*)(GeometryComponent &component);
const CustomDataType stored_type_;
@@ -430,10 +278,10 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final;
- WriteAttributePtr try_get_for_write(GeometryComponent &component) const final;
+ GVArrayPtr try_get_for_read(const GeometryComponent &component) const final;
+ GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final;
bool try_delete(GeometryComponent &component) const final;
- bool try_create(GeometryComponent &component) const final;
+ bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final;
bool exists(const GeometryComponent &component) const final;
};
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index e8879cdda8f..e84b485c466 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -132,7 +132,7 @@ static void blender_version_init(void)
BLI_snprintf(blender_version_string,
ARRAY_SIZE(blender_version_string),
- "%d.%02d.%d%s",
+ "%d.%01d.%d%s",
BLENDER_VERSION / 100,
BLENDER_VERSION % 100,
BLENDER_VERSION_PATCH,
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index cbf7a4483c0..81830f5bb61 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -80,7 +80,17 @@ struct bContext {
struct ARegion *menu;
struct wmGizmoGroup *gizmo_group;
struct bContextStore *store;
- const char *operator_poll_msg; /* reason for poll failing */
+
+ /* Operator poll. */
+ /**
+ * Store the reason the poll function fails (static string, not allocated).
+ * For more advanced formatting use `operator_poll_msg_dyn_params`.
+ */
+ const char *operator_poll_msg;
+ /**
+ * Store values to dynamically to create the string (called when a tool-tip is shown).
+ */
+ struct bContextPollMsgDyn_Params operator_poll_msg_dyn_params;
} wm;
/* data context */
@@ -113,11 +123,16 @@ bContext *CTX_copy(const bContext *C)
{
bContext *newC = MEM_dupallocN((void *)C);
+ memset(&newC->wm.operator_poll_msg_dyn_params, 0, sizeof(newC->wm.operator_poll_msg_dyn_params));
+
return newC;
}
void CTX_free(bContext *C)
{
+ /* This may contain a dynamically allocated message, free. */
+ CTX_wm_operator_poll_msg_clear(C);
+
MEM_freeN(C);
}
@@ -1003,13 +1018,45 @@ void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
C->wm.gizmo_group = gzgroup;
}
+void CTX_wm_operator_poll_msg_clear(bContext *C)
+{
+ struct bContextPollMsgDyn_Params *params = &C->wm.operator_poll_msg_dyn_params;
+ if (params->free_fn != NULL) {
+ params->free_fn(C, params->user_data);
+ }
+ params->get_fn = NULL;
+ params->free_fn = NULL;
+ params->user_data = NULL;
+
+ C->wm.operator_poll_msg = NULL;
+}
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
{
+ CTX_wm_operator_poll_msg_clear(C);
+
C->wm.operator_poll_msg = msg;
}
-const char *CTX_wm_operator_poll_msg_get(bContext *C)
+void CTX_wm_operator_poll_msg_set_dynamic(bContext *C,
+ const struct bContextPollMsgDyn_Params *params)
{
+ CTX_wm_operator_poll_msg_clear(C);
+
+ C->wm.operator_poll_msg_dyn_params = *params;
+}
+
+const char *CTX_wm_operator_poll_msg_get(bContext *C, bool *r_free)
+{
+ struct bContextPollMsgDyn_Params *params = &C->wm.operator_poll_msg_dyn_params;
+ if (params->get_fn != NULL) {
+ char *msg = params->get_fn(C, params->user_data);
+ if (msg != NULL) {
+ *r_free = true;
+ }
+ return msg;
+ }
+
+ *r_free = false;
return IFACE_(C->wm.operator_poll_msg);
}
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 5697fb2ccde..2ecd0e6bd85 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -32,7 +32,7 @@
/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
-using blender::bke::ReadAttributePtr;
+using blender::fn::GVArray;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -201,14 +201,14 @@ namespace blender::bke {
template<typename T>
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
attribute_math::DefaultMixer<T> mixer(r_values);
for (const int loop_index : IndexRange(mesh.totloop)) {
- const T value = attribute[loop_index];
+ const T value = old_values[loop_index];
const MLoop &loop = mesh.mloop[loop_index];
const int point_index = loop.v;
mixer.mix_in(point_index, value);
@@ -216,43 +216,40 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
/* We compute all interpolated values at once, because for this interpolation, one has to
* iterate over all loops anyway. */
Array<T> values(mesh.totvert);
- adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
for (const int loop_index : IndexRange(mesh.totloop)) {
const int vertex_index = mesh.mloop[loop_index].v;
- r_values[loop_index] = attribute[vertex_index];
+ r_values[loop_index] = old_values[vertex_index];
}
}
-static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
/* It is not strictly necessary to compute the value for all corners here. Instead one could
@@ -260,11 +257,10 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
* when an algorithm only accesses very few of the corner values. However, for the algorithms
* we currently have, precomputing the array is fine. Also, it is easier to implement. */
Array<T> values(mesh.totloop);
- adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
- std::move(values));
+ adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -274,7 +270,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
- Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -291,26 +287,24 @@ static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
- adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
- Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -332,26 +326,24 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
- Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
@@ -370,26 +362,24 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
- adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -401,26 +391,24 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
}
}
-static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
- adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -437,21 +425,19 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -461,7 +447,7 @@ static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -478,21 +464,19 @@ static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
- adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -502,7 +486,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -517,26 +501,24 @@ static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -558,26 +540,24 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
- adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
@@ -593,21 +573,19 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
- adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -617,7 +595,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -634,87 +612,86 @@ static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
- adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
} // namespace blender::bke
-ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
- const AttributeDomain new_domain) const
+blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
+ blender::fn::GVArrayPtr varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
- if (!attribute) {
+ if (!varray) {
return {};
}
- if (attribute->size() == 0) {
+ if (varray->size() == 0) {
return {};
}
- const AttributeDomain old_domain = attribute->domain();
- if (old_domain == new_domain) {
- return attribute;
+ if (from_domain == to_domain) {
+ return varray;
}
- switch (old_domain) {
+ switch (from_domain) {
case ATTR_DOMAIN_CORNER: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_POINT: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_FACE: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_EDGE: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray));
default:
break;
}
@@ -743,25 +720,21 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com
namespace blender::bke {
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- AttributeDomain Domain>
-static ReadAttributePtr make_derived_read_attribute(const void *data, const int domain_size)
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size)
{
- return std::make_unique<DerivedArrayReadAttribute<StructT, ElemT, GetFunc>>(
- Domain, Span<StructT>((const StructT *)data, domain_size));
+ return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
+ Span<StructT>((const StructT *)data, domain_size));
}
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, const ElemT &),
- AttributeDomain Domain>
-static WriteAttributePtr make_derived_write_attribute(void *data, const int domain_size)
+ void (*SetFunc)(StructT &, ElemT)>
+static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size)
{
- return std::make_unique<DerivedArrayWriteAttribute<StructT, ElemT, GetFunc, SetFunc>>(
- Domain, MutableSpan<StructT>((StructT *)data, domain_size));
+ return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(
+ MutableSpan<StructT>((StructT *)data, domain_size));
}
static float3 get_vertex_position(const MVert &vert)
@@ -769,7 +742,7 @@ static float3 get_vertex_position(const MVert &vert)
return float3(vert.co);
}
-static void set_vertex_position(MVert &vert, const float3 &position)
+static void set_vertex_position(MVert &vert, float3 position)
{
copy_v3_v3(vert.co, position);
}
@@ -787,7 +760,7 @@ static int get_material_index(const MPoly &mpoly)
return static_cast<int>(mpoly.mat_nr);
}
-static void set_material_index(MPoly &mpoly, const int &index)
+static void set_material_index(MPoly &mpoly, int index)
{
mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
}
@@ -797,7 +770,7 @@ static bool get_shade_smooth(const MPoly &mpoly)
return mpoly.flag & ME_SMOOTH;
}
-static void set_shade_smooth(MPoly &mpoly, const bool &value)
+static void set_shade_smooth(MPoly &mpoly, bool value)
{
SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
}
@@ -807,7 +780,7 @@ static float2 get_loop_uv(const MLoopUV &uv)
return float2(uv.uv);
}
-static void set_loop_uv(MLoopUV &uv, const float2 &co)
+static void set_loop_uv(MLoopUV &uv, float2 co)
{
copy_v2_v2(uv.uv, co);
}
@@ -821,7 +794,7 @@ static Color4f get_loop_color(const MLoopCol &col)
return linear_color;
}
-static void set_loop_color(MLoopCol &col, const Color4f &linear_color)
+static void set_loop_color(MLoopCol &col, Color4f linear_color)
{
linearrgb_to_srgb_uchar4(&col.r, linear_color);
}
@@ -831,71 +804,62 @@ static float get_crease(const MEdge &edge)
return edge.crease / 255.0f;
}
-static void set_crease(MEdge &edge, const float &value)
+static void set_crease(MEdge &edge, float value)
{
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
-class VertexWeightWriteAttribute final : public WriteAttribute {
+class VMutableArray_For_VertexWeights final : public VMutableArray<float> {
private:
MDeformVert *dverts_;
const int dvert_index_;
public:
- VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
- : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
+ VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
+ : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
- void get_internal(const int64_t index, void *r_value) const override
+ float get_impl(const int64_t index) const override
{
- get_internal(dverts_, dvert_index_, index, r_value);
+ return get_internal(dverts_, dvert_index_, index);
}
- void set_internal(const int64_t index, const void *value) override
+ void set_impl(const int64_t index, const float value) override
{
MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = *reinterpret_cast<const float *>(value);
+ weight->weight = value;
}
- static void get_internal(const MDeformVert *dverts,
- const int dvert_index,
- const int64_t index,
- void *r_value)
+ static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
{
if (dverts == nullptr) {
- *(float *)r_value = 0.0f;
- return;
+ return 0.0f;
}
const MDeformVert &dvert = dverts[index];
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
if (weight.def_nr == dvert_index) {
- *(float *)r_value = weight.weight;
- return;
+ return weight.weight;
}
}
- *(float *)r_value = 0.0f;
+ return 0.0f;
}
};
-class VertexWeightReadAttribute final : public ReadAttribute {
+class VArray_For_VertexWeights final : public VArray<float> {
private:
const MDeformVert *dverts_;
const int dvert_index_;
public:
- VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
+ VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
+ : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
- void get_internal(const int64_t index, void *r_value) const override
+ float get_impl(const int64_t index) const override
{
- VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
+ return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
}
};
@@ -904,8 +868,8 @@ class VertexWeightReadAttribute final : public ReadAttribute {
*/
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
public:
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
+ ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
@@ -917,15 +881,17 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
if (mesh == nullptr || mesh->dvert == nullptr) {
static const float default_value = 0.0f;
- return std::make_unique<ConstantReadAttribute>(
- ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
+ return {std::make_unique<fn::GVArray_For_SingleValueRef>(
+ CPPType::get<float>(), mesh->totvert, &default_value),
+ ATTR_DOMAIN_POINT};
}
- return std::make_unique<VertexWeightReadAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>(
+ mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
+ ATTR_DOMAIN_POINT};
}
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
@@ -946,8 +912,11 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
}
- return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ return {
+ std::make_unique<
+ fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>(
+ mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
+ ATTR_DOMAIN_POINT};
}
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
@@ -1009,7 +978,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
+ GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
{
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
@@ -1022,8 +991,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- return std::make_unique<ArrayReadAttribute<float3>>(
- ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly));
+ return std::make_unique<fn::GVArray_For_Span<float3>>(
+ Span<float3>((const float3 *)data, mesh->totpoly));
}
Array<float3> normals(mesh->totpoly);
@@ -1032,10 +1001,10 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
}
- return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals));
+ return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
}
- WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ GVMutableArrayPtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
{
return {};
}
@@ -1045,7 +1014,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
return false;
}
- bool try_create(GeometryComponent &UNUSED(component)) const final
+ bool try_create(GeometryComponent &UNUSED(component),
+ const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
@@ -1105,12 +1075,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
point_access,
- make_derived_read_attribute<MVert, float3, get_vertex_position, ATTR_DOMAIN_POINT>,
- make_derived_write_attribute<MVert,
- float3,
- get_vertex_position,
- set_vertex_position,
- ATTR_DOMAIN_POINT>,
+ make_derived_read_attribute<MVert, float3, get_vertex_position>,
+ make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>,
tag_normals_dirty_when_writing_position);
static NormalAttributeProvider normal;
@@ -1124,12 +1090,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
- make_derived_read_attribute<MPoly, int, get_material_index, ATTR_DOMAIN_FACE>,
- make_derived_write_attribute<MPoly,
- int,
- get_material_index,
- set_material_index,
- ATTR_DOMAIN_FACE>,
+ make_derived_read_attribute<MPoly, int, get_material_index>,
+ make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>,
nullptr);
static BuiltinCustomDataLayerProvider shade_smooth(
@@ -1141,12 +1103,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
- make_derived_read_attribute<MPoly, bool, get_shade_smooth, ATTR_DOMAIN_FACE>,
- make_derived_write_attribute<MPoly,
- bool,
- get_shade_smooth,
- set_shade_smooth,
- ATTR_DOMAIN_FACE>,
+ make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
+ make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
nullptr);
static BuiltinCustomDataLayerProvider crease(
@@ -1158,8 +1116,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
edge_access,
- make_derived_read_attribute<MEdge, float, get_crease, ATTR_DOMAIN_EDGE>,
- make_derived_write_attribute<MEdge, float, get_crease, set_crease, ATTR_DOMAIN_EDGE>,
+ make_derived_read_attribute<MEdge, float, get_crease>,
+ make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
nullptr);
static NamedLegacyCustomDataProvider uvs(
@@ -1167,20 +1125,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
CD_PROP_FLOAT2,
CD_MLOOPUV,
corner_access,
- make_derived_read_attribute<MLoopUV, float2, get_loop_uv, ATTR_DOMAIN_CORNER>,
- make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv, ATTR_DOMAIN_CORNER>);
+ make_derived_read_attribute<MLoopUV, float2, get_loop_uv>,
+ make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>);
static NamedLegacyCustomDataProvider vertex_colors(
ATTR_DOMAIN_CORNER,
CD_PROP_COLOR,
CD_MLOOPCOL,
corner_access,
- make_derived_read_attribute<MLoopCol, Color4f, get_loop_color, ATTR_DOMAIN_CORNER>,
- make_derived_write_attribute<MLoopCol,
- Color4f,
- get_loop_color,
- set_loop_color,
- ATTR_DOMAIN_CORNER>);
+ make_derived_read_attribute<MLoopCol, Color4f, get_loop_color>,
+ make_derived_write_attribute<MLoopCol, Color4f, get_loop_color, set_loop_color>);
static VertexGroupsAttributeProvider vertex_groups;
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index 135de14b4f7..6c4af7a6d23 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -140,16 +140,17 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
namespace blender::bke {
-template<typename T, AttributeDomain Domain>
-static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
+template<typename T>
+static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size)
{
- return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+ return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size));
}
-template<typename T, AttributeDomain Domain>
-static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+template<typename T>
+static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size)
{
- return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
+ return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
+ MutableSpan<T>((T *)data, domain_size));
}
/**
@@ -179,30 +180,28 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
},
update_custom_data_pointers};
- static BuiltinCustomDataLayerProvider position(
- "position",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- CD_PROP_FLOAT3,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- point_access,
- make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
- nullptr);
- static BuiltinCustomDataLayerProvider radius(
- "radius",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT,
- BuiltinAttributeProvider::Creatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::Deletable,
- point_access,
- make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
- nullptr);
+ static BuiltinCustomDataLayerProvider position("position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_array_read_attribute<float3>,
+ make_array_write_attribute<float3>,
+ nullptr);
+ static BuiltinCustomDataLayerProvider radius("radius",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float>,
+ make_array_write_attribute<float>,
+ nullptr);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 07d0e520c93..47db5d1f901 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -449,13 +449,15 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
BLI_assert(cpp_type != nullptr);
- result.attribute_try_create(entry.key, domain_output, data_type_output);
- WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name);
- if (!write_attribute || &write_attribute->cpp_type() != cpp_type ||
- write_attribute->domain() != domain_output) {
+ result.attribute_try_create(
+ entry.key, domain_output, data_type_output, AttributeInitDefault());
+ WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name);
+ if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
+ write_attribute.domain != domain_output) {
continue;
}
- fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
+
+ fn::GVMutableArray_GSpan dst_span{*write_attribute.varray};
int offset = 0;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -467,11 +469,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
if (domain_size == 0) {
continue; /* Domain size is 0, so no need to increment the offset. */
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
+ GVArrayPtr source_attribute = component.attribute_try_get_for_read(
name, domain_output, data_type_output);
if (source_attribute) {
- fn::GSpan src_span = source_attribute->get_span();
+ fn::GVArray_GSpan src_span{*source_attribute};
const void *src_buffer = src_span.data();
for (const int UNUSED(i) : set_group.transforms.index_range()) {
void *dst_buffer = dst_span[offset];
@@ -486,7 +488,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
}
}
- write_attribute->apply_span();
+ dst_span.save();
}
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 729c38ae7cf..1ec3b6a1cbf 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -1542,7 +1542,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
* check whether it is still true with Mesh */
Mesh tmp = *mesh_dst;
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
- int did_shapekeys = 0;
+ bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;
if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
@@ -1597,7 +1597,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
}
shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
- did_shapekeys = 1;
+ did_shapekeys = true;
}
/* copy texture space */
@@ -1626,13 +1626,18 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
totedge);
}
if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
- /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
- * BKE_mesh_update_customdata_pointers() call below. */
- tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
- tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
-
- CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
- CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ CustomData_add_layer(&tmp.ldata,
+ CD_MLOOP,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mloop :
+ MEM_dupallocN(mesh_src->mloop),
+ tmp.totloop);
+ CustomData_add_layer(&tmp.pdata,
+ CD_MPOLY,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mpoly :
+ MEM_dupallocN(mesh_src->mpoly),
+ tmp.totpoly);
}
/* object had got displacement layer, should copy this layer to save sculpted data */
@@ -1651,9 +1656,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* yes, must be before _and_ after tessellate */
BKE_mesh_update_customdata_pointers(&tmp, false);
- /* since 2.65 caller must do! */
- // BKE_mesh_tessface_calc(&tmp);
-
CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
new file mode 100644
index 00000000000..91c9951ae89
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -0,0 +1,158 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+namespace blender::bke::mesh_surface_sample {
+
+static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
+{
+ /* This only updates a cache and can be considered to be logically const. */
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
+ const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
+ return {looptris, looptris_len};
+}
+
+template<typename T>
+BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const VArray<T> &data_in,
+ const MutableSpan<T> data_out)
+{
+ const Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int v0_index = mesh.mloop[looptri.tri[0]].v;
+ const int v1_index = mesh.mloop[looptri.tri[1]].v;
+ const int v2_index = mesh.mloop[looptri.tri[2]].v;
+
+ const T v0 = data_in[v0_index];
+ const T v1 = data_in[v1_index];
+ const T v2 = data_in[v2_index];
+
+ const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
+ data_out[i] = interpolated_value;
+ }
+}
+
+void sample_point_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const GVArray &data_in,
+ const GMutableSpan data_out)
+{
+ BLI_assert(data_out.size() == looptri_indices.size());
+ BLI_assert(data_out.size() == bary_coords.size());
+ BLI_assert(data_in.size() == mesh.totvert);
+ BLI_assert(data_in.type() == data_out.type());
+
+ const CPPType &type = data_in.type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ sample_point_attribute<T>(
+ mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
+ });
+}
+
+template<typename T>
+BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const VArray<T> &data_in,
+ const MutableSpan<T> data_out)
+{
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int loop_index_0 = looptri.tri[0];
+ const int loop_index_1 = looptri.tri[1];
+ const int loop_index_2 = looptri.tri[2];
+
+ const T v0 = data_in[loop_index_0];
+ const T v1 = data_in[loop_index_1];
+ const T v2 = data_in[loop_index_2];
+
+ const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
+ data_out[i] = interpolated_value;
+ }
+}
+
+void sample_corner_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const GVArray &data_in,
+ const GMutableSpan data_out)
+{
+ BLI_assert(data_out.size() == looptri_indices.size());
+ BLI_assert(data_out.size() == bary_coords.size());
+ BLI_assert(data_in.size() == mesh.totloop);
+ BLI_assert(data_in.type() == data_out.type());
+
+ const CPPType &type = data_in.type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ sample_corner_attribute<T>(
+ mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
+ });
+}
+
+template<typename T>
+void sample_face_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const VArray<T> &data_in,
+ const MutableSpan<T> data_out)
+{
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : data_out.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const int poly_index = looptri.poly;
+ data_out[i] = data_in[poly_index];
+ }
+}
+
+void sample_face_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const GVArray &data_in,
+ const GMutableSpan data_out)
+{
+ BLI_assert(data_out.size() == looptri_indices.size());
+ BLI_assert(data_in.size() == mesh.totpoly);
+ BLI_assert(data_in.type() == data_out.type());
+
+ const CPPType &type = data_in.type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), data_out.typed<T>());
+ });
+}
+
+} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 02195e0d60f..473be34d69a 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4968,6 +4968,7 @@ static void registerGeometryNodes()
register_node_type_geo_sample_texture();
register_node_type_geo_subdivide();
register_node_type_geo_subdivision_surface();
+ register_node_type_geo_switch();
register_node_type_geo_transform();
register_node_type_geo_triangulate();
register_node_type_geo_volume_to_mesh();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 160fb93b835..522b4549f57 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1336,7 +1336,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return (mti->modifyGeometrySet != NULL);
}
if (ob->type == OB_VOLUME) {
- return (mti->modifyVolume != NULL);
+ return (mti->modifyVolume != NULL) || (mti->modifyGeometrySet != NULL);
}
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 7b03839f659..93d5e116131 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -39,6 +39,7 @@
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
+#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -1003,13 +1004,12 @@ static void volume_update_simplify_level(Volume *volume, const Depsgraph *depsgr
#endif
}
-static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
- struct Scene *scene,
- Object *object,
- Volume *volume_input)
+static void volume_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
+ Volume *volume_input,
+ GeometrySet &geometry_set)
{
- Volume *volume = volume_input;
-
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
@@ -1030,25 +1030,22 @@ static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
continue;
}
- if (mti->modifyVolume) {
- /* Ensure we are not modifying the input. */
- if (volume == volume_input) {
- volume = BKE_volume_copy_for_eval(volume, true);
+ if (mti->modifyGeometrySet) {
+ mti->modifyGeometrySet(md, &mectx, &geometry_set);
+ }
+ else if (mti->modifyVolume) {
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ Volume *volume_old = volume_component.get_for_write();
+ if (volume_old == nullptr) {
+ volume_old = BKE_volume_new_for_eval(volume_input);
+ volume_component.replace(volume_old);
}
-
- Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
-
- if (volume_next && volume_next != volume) {
- /* If the modifier returned a new volume, release the old one. */
- if (volume != volume_input) {
- BKE_id_free(nullptr, volume);
- }
- volume = volume_next;
+ Volume *volume_new = mti->modifyVolume(md, &mectx, volume_old);
+ if (volume_new != volume_old) {
+ volume_component.replace(volume_new);
}
}
}
-
- return volume;
}
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
@@ -1072,6 +1069,24 @@ void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
}
}
+static Volume *take_volume_ownership_from_geometry_set(GeometrySet &geometry_set)
+{
+ if (!geometry_set.has<VolumeComponent>()) {
+ return nullptr;
+ }
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ Volume *volume = volume_component.release();
+ if (volume != nullptr) {
+ /* Add back, but only as read-only non-owning component. */
+ volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
+ }
+ else {
+ /* The component was empty, we can remove it. */
+ geometry_set.remove<VolumeComponent>();
+ }
+ return volume;
+}
+
void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
{
/* Free any evaluated data and restore original data. */
@@ -1079,11 +1094,22 @@ void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Ob
/* Evaluate modifiers. */
Volume *volume = (Volume *)object->data;
- Volume *volume_eval = volume_evaluate_modifiers(depsgraph, scene, object, volume);
+ GeometrySet geometry_set;
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
+ volume_evaluate_modifiers(depsgraph, scene, object, volume, geometry_set);
+
+ Volume *volume_eval = take_volume_ownership_from_geometry_set(geometry_set);
+
+ /* If the geometry set did not contain a volume, we still create an empty one. */
+ if (volume_eval == nullptr) {
+ volume_eval = BKE_volume_new_for_eval(volume);
+ }
/* Assign evaluated object. */
- const bool is_owned = (volume != volume_eval);
- BKE_object_eval_assign_data(object, &volume_eval->id, is_owned);
+ const bool eval_is_owned = (volume != volume_eval);
+ BKE_object_eval_assign_data(object, &volume_eval->id, eval_is_owned);
+ object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set));
}
void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, const char *filepath)
diff --git a/source/blender/blenlib/BLI_compiler_attrs.h b/source/blender/blenlib/BLI_compiler_attrs.h
index 680c4bc78da..4b5a7d671f2 100644
--- a/source/blender/blenlib/BLI_compiler_attrs.h
+++ b/source/blender/blenlib/BLI_compiler_attrs.h
@@ -98,3 +98,10 @@
#else
# define ATTR_ALIGN(x) __attribute__((aligned(x)))
#endif
+
+/* Alignment directive */
+#ifdef _WIN64
+# define ALIGN_STRUCT __declspec(align(64))
+#else
+# define ALIGN_STRUCT
+#endif
diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index 9fa69853e44..376bf5df06f 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -247,11 +247,11 @@ class Map {
{
this->add_new_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- void add_new_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ void add_new_as(ForwardKey &&key, ForwardValue &&... value)
{
this->add_new__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -277,11 +277,11 @@ class Map {
{
return this->add_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- bool add_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->add__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -307,11 +307,11 @@ class Map {
{
return this->add_overwrite_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add_overwrite_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->add_overwrite__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -413,12 +413,12 @@ class Map {
{
return this->pop_default_as(key, std::move(default_value));
}
- template<typename ForwardKey, typename ForwardValue>
- Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
+ template<typename ForwardKey, typename... ForwardValue>
+ Value pop_default_as(const ForwardKey &key, ForwardValue &&... default_value)
{
Slot *slot = this->lookup_slot_ptr(key, hash_(key));
if (slot == nullptr) {
- return std::forward<ForwardValue>(default_value);
+ return Value(std::forward<ForwardValue>(default_value)...);
}
Value value = std::move(*slot->value());
slot->remove();
@@ -525,15 +525,15 @@ class Map {
{
return this->lookup_default_as(key, default_value);
}
- template<typename ForwardKey, typename ForwardValue>
- Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
+ template<typename ForwardKey, typename... ForwardValue>
+ Value lookup_default_as(const ForwardKey &key, ForwardValue &&... default_value) const
{
const Value *ptr = this->lookup_ptr_as(key);
if (ptr != nullptr) {
return *ptr;
}
else {
- return std::forward<ForwardValue>(default_value);
+ return Value(std::forward<ForwardValue>(default_value)...);
}
}
@@ -557,11 +557,11 @@ class Map {
{
return this->lookup_or_add_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->lookup_or_add__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -982,7 +982,7 @@ class Map {
SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
Slot &slot = new_slots[slot_index];
if (slot.is_empty()) {
- slot.occupy(std::move(*old_slot.key()), std::move(*old_slot.value()), hash);
+ slot.occupy(std::move(*old_slot.key()), hash, std::move(*old_slot.value()));
return;
}
}
@@ -996,8 +996,8 @@ class Map {
new (this) Map(NoExceptConstructor(), allocator);
}
- template<typename ForwardKey, typename ForwardValue>
- void add_new__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ void add_new__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->contains_as(key));
@@ -1005,7 +1005,7 @@ class Map {
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return;
}
@@ -1013,14 +1013,14 @@ class Map {
MAP_SLOT_PROBING_END();
}
- template<typename ForwardKey, typename ForwardValue>
- bool add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
this->ensure_can_add();
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return true;
}
@@ -1075,7 +1075,7 @@ class Map {
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), create_value(), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, create_value());
occupied_and_removed_slots_++;
return *slot.value();
}
@@ -1086,14 +1086,14 @@ class Map {
MAP_SLOT_PROBING_END();
}
- template<typename ForwardKey, typename ForwardValue>
- Value &lookup_or_add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ Value &lookup_or_add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
this->ensure_can_add();
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return *slot.value();
}
@@ -1104,15 +1104,15 @@ class Map {
MAP_SLOT_PROBING_END();
}
- template<typename ForwardKey, typename ForwardValue>
- bool add_overwrite__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add_overwrite__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
auto create_func = [&](Value *ptr) {
- new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value));
+ new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value)...);
return true;
};
auto modify_func = [&](Value *ptr) {
- *ptr = std::forward<ForwardValue>(value);
+ *ptr = Value(std::forward<ForwardValue>(value)...);
return false;
};
return this->add_or_modify__impl(
@@ -1221,16 +1221,18 @@ template<typename Key, typename Value> class StdUnorderedMapWrapper {
map_.reserve(n);
}
- template<typename ForwardKey, typename ForwardValue>
- void add_new(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ void add_new(ForwardKey &&key, ForwardValue &&... value)
{
- map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)});
+ map_.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)});
}
- template<typename ForwardKey, typename ForwardValue>
- bool add(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add(ForwardKey &&key, ForwardValue &&... value)
{
- return map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)}).second;
+ return map_
+ .insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)})
+ .second;
}
bool contains(const Key &key) const
diff --git a/source/blender/blenlib/BLI_map_slots.hh b/source/blender/blenlib/BLI_map_slots.hh
index c0cb3091a8e..1b4ca11af41 100644
--- a/source/blender/blenlib/BLI_map_slots.hh
+++ b/source/blender/blenlib/BLI_map_slots.hh
@@ -195,11 +195,11 @@ template<typename Key, typename Value> class SimpleMapSlot {
* Change the state of this slot from empty/removed to occupied. The key/value has to be
* constructed by calling the constructor with the given key/value as parameter.
*/
- template<typename ForwardKey, typename ForwardValue>
- void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->is_occupied());
- new (&value_buffer_) Value(std::forward<ForwardValue>(value));
+ new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
state_ = Occupied;
}
@@ -315,12 +315,12 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
return is_equal(key, key_);
}
- template<typename ForwardKey, typename ForwardValue>
- void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->is_occupied());
BLI_assert(KeyInfo::is_not_empty_or_removed(key));
- new (&value_buffer_) Value(std::forward<ForwardValue>(value));
+ new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
}
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index fe511793c46..c3876d4eaf8 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -94,7 +94,7 @@ template<typename T> class Span {
using iterator = const T *;
using size_type = int64_t;
- private:
+ protected:
const T *data_ = nullptr;
int64_t size_ = 0;
@@ -477,7 +477,7 @@ template<typename T> class MutableSpan {
using iterator = T *;
using size_type = int64_t;
- private:
+ protected:
T *data_;
int64_t size_;
@@ -662,6 +662,16 @@ template<typename T> class MutableSpan {
}
/**
+ * Return a reference to the first element in the array. This invokes undefined behavior when the
+ * array is empty.
+ */
+ constexpr T &first() const
+ {
+ BLI_assert(size_ > 0);
+ return data_[0];
+ }
+
+ /**
* Returns a reference to the last element. This invokes undefined behavior when the array is
* empty.
*/
diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh
index 19f77078c5b..d66316a95d9 100644
--- a/source/blender/blenlib/BLI_stack.hh
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -232,13 +232,14 @@ class Stack {
{
this->push_as(std::move(value));
}
- template<typename ForwardT> void push_as(ForwardT &&value)
+ /* This is similar to `std::stack::emplace`. */
+ template<typename... ForwardT> void push_as(ForwardT &&... value)
{
if (top_ == top_chunk_->capacity_end) {
this->activate_next_chunk(1);
}
try {
- new (top_) T(std::forward<ForwardT>(value));
+ new (top_) T(std::forward<ForwardT>(value)...);
top_++;
size_++;
}
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 328d623787b..3ffd5309a04 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -437,13 +437,17 @@ class Vector {
*/
void append(const T &value)
{
- this->ensure_space_for_one();
- this->append_unchecked(value);
+ this->append_as(value);
}
void append(T &&value)
{
+ this->append_as(std::move(value));
+ }
+ /* This is similar to `std::vector::emplace_back`. */
+ template<typename... ForwardValue> void append_as(ForwardValue &&...value)
+ {
this->ensure_space_for_one();
- this->append_unchecked(std::move(value));
+ this->append_unchecked_as(std::forward<ForwardValue>(value)...);
}
/**
@@ -474,10 +478,18 @@ class Vector {
* behavior when not enough capacity has been reserved beforehand. Only use this in performance
* critical code.
*/
- template<typename ForwardT> void append_unchecked(ForwardT &&value)
+ void append_unchecked(const T &value)
+ {
+ this->append_unchecked_as(value);
+ }
+ void append_unchecked(T &&value)
+ {
+ this->append_unchecked_as(std::move(value));
+ }
+ template<typename... ForwardT> void append_unchecked_as(ForwardT &&...value)
{
BLI_assert(end_ < capacity_end_);
- new (end_) T(std::forward<ForwardT>(value));
+ new (end_) T(std::forward<ForwardT>(value)...);
end_++;
UPDATE_VECTOR_SIZE(this);
}
@@ -657,6 +669,21 @@ class Vector {
}
/**
+ * Return a reference to the first element in the vector.
+ * This invokes undefined behavior when the vector is empty.
+ */
+ const T &first() const
+ {
+ BLI_assert(this->size() > 0);
+ return *begin_;
+ }
+ T &first()
+ {
+ BLI_assert(this->size() > 0);
+ return *begin_;
+ }
+
+ /**
* Return how many values are currently stored in the vector.
*/
int64_t size() const
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index f9b0aaa7de6..eae15f0300c 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -37,6 +37,7 @@
* see of the increased compile time and binary size is worth it.
*/
+#include "BLI_array.hh"
#include "BLI_span.hh"
namespace blender {
@@ -71,6 +72,11 @@ template<typename T> class VArray {
return size_ == 0;
}
+ IndexRange index_range() const
+ {
+ return IndexRange(size_);
+ }
+
/* Returns true when the virtual array is stored as a span internally. */
bool is_span() const
{
@@ -82,13 +88,13 @@ template<typename T> class VArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
- Span<T> get_span() const
+ Span<T> get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return {};
}
- return this->get_span_impl();
+ return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -102,20 +108,35 @@ template<typename T> class VArray {
/* Returns the value that is returned for every index. This invokes undefined behavior if the
* virtual array would not return the same value for every index. */
- T get_single() const
+ T get_internal_single() const
{
BLI_assert(this->is_single());
if (size_ == 1) {
return this->get(0);
}
- return this->get_single_impl();
+ return this->get_internal_single_impl();
}
+ /* Get the element at a specific index. Note that this operator cannot be used to assign values
+ * to an index, because the return value is not a reference. */
T operator[](const int64_t index) const
{
return this->get(index);
}
+ /* Copy the entire virtual array into a span. */
+ void materialize(MutableSpan<T> r_span) const
+ {
+ BLI_assert(size_ == r_span.size());
+ this->materialize_impl(r_span);
+ }
+
+ void materialize_to_uninitialized(MutableSpan<T> r_span) const
+ {
+ BLI_assert(size_ == r_span.size());
+ this->materialize_to_uninitialized_impl(r_span);
+ }
+
protected:
virtual T get_impl(const int64_t index) const = 0;
@@ -124,7 +145,7 @@ template<typename T> class VArray {
return false;
}
- virtual Span<T> get_span_impl() const
+ virtual Span<T> get_internal_span_impl() const
{
BLI_assert_unreachable();
return {};
@@ -135,56 +156,201 @@ template<typename T> class VArray {
return false;
}
- virtual T get_single_impl() const
+ virtual T get_internal_single_impl() const
{
/* Provide a default implementation, so that subclasses don't have to provide it. This method
* should never be called because `is_single_impl` returns false by default. */
BLI_assert_unreachable();
return T();
}
+
+ virtual void materialize_impl(MutableSpan<T> r_span) const
+ {
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span();
+ initialized_copy_n(span.data(), size_, r_span.data());
+ }
+ else if (this->is_single()) {
+ const T single = this->get_internal_single();
+ initialized_fill_n(r_span.data(), size_, single);
+ }
+ else {
+ const int64_t size = size_;
+ for (int64_t i = 0; i < size; i++) {
+ r_span[i] = this->get(i);
+ }
+ }
+ }
+
+ virtual void materialize_to_uninitialized_impl(MutableSpan<T> r_span) const
+ {
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span();
+ uninitialized_copy_n(span.data(), size_, r_span.data());
+ }
+ else if (this->is_single()) {
+ const T single = this->get_internal_single();
+ uninitialized_fill_n(r_span.data(), size_, single);
+ }
+ else {
+ const int64_t size = size_;
+ T *dst = r_span.data();
+ for (int64_t i = 0; i < size; i++) {
+ new (dst + i) T(this->get(i));
+ }
+ }
+ }
+};
+
+/* Similar to VArray, but the elements are mutable. */
+template<typename T> class VMutableArray : public VArray<T> {
+ public:
+ VMutableArray(const int64_t size) : VArray<T>(size)
+ {
+ }
+
+ void set(const int64_t index, T value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size_);
+ this->set_impl(index, std::move(value));
+ }
+
+ /* Copy the values from the source span to all elements in the virtual array. */
+ void set_all(Span<T> src)
+ {
+ BLI_assert(src.size() == this->size_);
+ this->set_all_impl(src);
+ }
+
+ MutableSpan<T> get_internal_span()
+ {
+ BLI_assert(this->is_span());
+ Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span();
+ return MutableSpan<T>(const_cast<T *>(span.data()), span.size());
+ }
+
+ protected:
+ virtual void set_impl(const int64_t index, T value) = 0;
+
+ virtual void set_all_impl(Span<T> src)
+ {
+ if (this->is_span()) {
+ const MutableSpan<T> span = this->get_internal_span();
+ initialized_copy_n(src.data(), this->size_, span.data());
+ }
+ else {
+ const int64_t size = this->size_;
+ for (int64_t i = 0; i < size; i++) {
+ this->set(i, src[i]);
+ }
+ }
+ }
};
+template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>;
+template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>;
+
/**
- * A virtual array implementation for a span. This class is final so that it can be devirtualized
- * by the compiler in some cases (e.g. when #devirtualize_varray is used).
+ * A virtual array implementation for a span. Methods in this class are final so that it can be
+ * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
*/
-template<typename T> class VArrayForSpan final : public VArray<T> {
- private:
- const T *data_;
+template<typename T> class VArray_For_Span : public VArray<T> {
+ protected:
+ const T *data_ = nullptr;
public:
- VArrayForSpan(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
+ VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
{
}
protected:
- T get_impl(const int64_t index) const override
+ VArray_For_Span(const int64_t size) : VArray<T>(size)
+ {
+ }
+
+ T get_impl(const int64_t index) const final
+ {
+ return data_[index];
+ }
+
+ bool is_span_impl() const final
+ {
+ return true;
+ }
+
+ Span<T> get_internal_span_impl() const final
+ {
+ return Span<T>(data_, this->size_);
+ }
+};
+
+template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> {
+ protected:
+ T *data_ = nullptr;
+
+ public:
+ VMutableArray_For_MutableSpan(const MutableSpan<T> data)
+ : VMutableArray<T>(data.size()), data_(data.data())
+ {
+ }
+
+ protected:
+ VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size)
+ {
+ }
+
+ T get_impl(const int64_t index) const final
{
return data_[index];
}
+ void set_impl(const int64_t index, T value) final
+ {
+ data_[index] = value;
+ }
+
bool is_span_impl() const override
{
return true;
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
return Span<T>(data_, this->size_);
}
};
/**
+ * A variant of `VArray_For_Span` that owns the underlying data.
+ * The `Container` type has to implement a `size()` and `data()` method.
+ * The `data()` method has to return a pointer to the first element in the continuous array of
+ * elements.
+ */
+template<typename Container, typename T = typename Container::value_type>
+class VArray_For_ArrayContainer : public VArray_For_Span<T> {
+ private:
+ Container container_;
+
+ public:
+ VArray_For_ArrayContainer(Container container)
+ : VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container))
+ {
+ this->data_ = container_.data();
+ }
+};
+
+/**
* A virtual array implementation that returns the same value for every index. This class is final
* so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is
* used).
*/
-template<typename T> class VArrayForSingle final : public VArray<T> {
+template<typename T> class VArray_For_Single final : public VArray<T> {
private:
T value_;
public:
- VArrayForSingle(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
+ VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
{
}
@@ -199,7 +365,7 @@ template<typename T> class VArrayForSingle final : public VArray<T> {
return this->size_ == 1;
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
return Span<T>(&value_, 1);
}
@@ -209,13 +375,171 @@ template<typename T> class VArrayForSingle final : public VArray<T> {
return true;
}
- T get_single_impl() const override
+ T get_internal_single_impl() const override
{
return value_;
}
};
/**
+ * In many cases a virtual array is a span internally. In those cases, access to individual could
+ * be much more efficient than calling a virtual method. When the underlying virtual array is not a
+ * span, this class allocates a new array and copies the values over.
+ *
+ * This should be used in those cases:
+ * - All elements in the virtual array are accessed multiple times.
+ * - In most cases, the underlying virtual array is a span, so no copy is necessary to benefit
+ * from faster access.
+ * - An API is called, that does not accept virtual arrays, but only spans.
+ */
+template<typename T> class VArray_Span final : public Span<T> {
+ private:
+ const VArray<T> &varray_;
+ Array<T> owned_data_;
+
+ public:
+ VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray)
+ {
+ this->size_ = varray_.size();
+ if (varray_.is_span()) {
+ this->data_ = varray_.get_internal_span().data();
+ }
+ else {
+ owned_data_.~Array();
+ new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
+ varray_.materialize_to_uninitialized(owned_data_);
+ this->data_ = owned_data_.data();
+ }
+ }
+};
+
+/**
+ * Same as VArray_Span, but for a mutable span.
+ * The important thing to note is that when changing this span, the results might not be
+ * immediately reflected in the underlying virtual array (only when the virtual array is a span
+ * internally). The #save method can be used to write all changes to the underlying virtual array,
+ * if necessary.
+ */
+template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
+ private:
+ VMutableArray<T> &varray_;
+ Array<T> owned_data_;
+ bool save_has_been_called_ = false;
+ bool show_not_saved_warning_ = true;
+
+ public:
+ /* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If
+ * not, a new array has to be allocated as a wrapper for the underlying virtual array. */
+ VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true)
+ : MutableSpan<T>(), varray_(varray)
+ {
+ this->size_ = varray_.size();
+ if (varray_.is_span()) {
+ this->data_ = varray_.get_internal_span().data();
+ }
+ else {
+ if (copy_values_to_span) {
+ owned_data_.~Array();
+ new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
+ varray_.materialize_to_uninitialized(owned_data_);
+ }
+ else {
+ owned_data_.reinitialize(varray_.size());
+ }
+ this->data_ = owned_data_.data();
+ }
+ }
+
+ ~VMutableArray_Span()
+ {
+ if (show_not_saved_warning_) {
+ if (!save_has_been_called_) {
+ std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
+ }
+ }
+ }
+
+ /* Write back all values from a temporary allocated array to the underlying virtual array. */
+ void save()
+ {
+ save_has_been_called_ = true;
+ if (this->data_ != owned_data_.data()) {
+ return;
+ }
+ varray_.set_all(owned_data_);
+ }
+
+ void disable_not_applied_warning()
+ {
+ show_not_saved_warning_ = false;
+ }
+};
+
+/**
+ * This class makes it easy to create a virtual array for an existing function or lambda. The
+ * `GetFunc` should take a single `index` argument and return the value at that index.
+ */
+template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> {
+ private:
+ GetFunc get_func_;
+
+ public:
+ VArray_For_Func(const int64_t size, GetFunc get_func)
+ : VArray<T>(size), get_func_(std::move(get_func))
+ {
+ }
+
+ private:
+ T get_impl(const int64_t index) const override
+ {
+ return get_func_(index);
+ }
+};
+
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class VArray_For_DerivedSpan : public VArray<ElemT> {
+ private:
+ const StructT *data_;
+
+ public:
+ VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data())
+ {
+ }
+
+ private:
+ ElemT get_impl(const int64_t index) const override
+ {
+ return GetFunc(data_[index]);
+ }
+};
+
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT)>
+class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> {
+ private:
+ StructT *data_;
+
+ public:
+ VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
+ : VMutableArray<ElemT>(data.size()), data_(data.data())
+ {
+ }
+
+ private:
+ ElemT get_impl(const int64_t index) const override
+ {
+ return GetFunc(data_[index]);
+ }
+
+ void set_impl(const int64_t index, ElemT value) override
+ {
+ SetFunc(data_[index], std::move(value));
+ }
+};
+
+/**
* Generate multiple versions of the given function optimized for different virtual arrays.
* One has to be careful with nesting multiple devirtualizations, because that results in an
* exponential number of function instantiations (increasing compile time and binary size).
@@ -229,14 +553,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
/* Support disabling the devirtualization to simplify benchmarking. */
if (enable) {
if (varray.is_single()) {
- /* `VArrayForSingle` can be used for devirtualization, because it is declared `final`. */
- const VArrayForSingle<T> varray_single{varray.get_single(), varray.size()};
+ /* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */
+ const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()};
func(varray_single);
return;
}
if (varray.is_span()) {
- /* `VArrayForSpan` can be used for devirtualization, because it is declared `final`. */
- const VArrayForSpan<T> varray_span{varray.get_span()};
+ /* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */
+ const VArray_For_Span<T> varray_span{varray.get_internal_span()};
func(varray_span);
return;
}
@@ -262,26 +586,26 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
const bool is_single1 = varray1.is_single();
const bool is_single2 = varray2.is_single();
if (is_span1 && is_span2) {
- const VArrayForSpan<T1> varray1_span{varray1.get_span()};
- const VArrayForSpan<T2> varray2_span{varray2.get_span()};
+ const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
+ const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
func(varray1_span, varray2_span);
return;
}
if (is_span1 && is_single2) {
- const VArrayForSpan<T1> varray1_span{varray1.get_span()};
- const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
+ const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
+ const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
func(varray1_span, varray2_single);
return;
}
if (is_single1 && is_span2) {
- const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
- const VArrayForSpan<T2> varray2_span{varray2.get_span()};
+ const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
+ const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
func(varray1_single, varray2_span);
return;
}
if (is_single1 && is_single2) {
- const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
- const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
+ const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
+ const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
func(varray1_single, varray2_single);
return;
}
diff --git a/source/blender/blenlib/tests/BLI_map_test.cc b/source/blender/blenlib/tests/BLI_map_test.cc
index f1ae8fb3921..bb15f7f0d8d 100644
--- a/source/blender/blenlib/tests/BLI_map_test.cc
+++ b/source/blender/blenlib/tests/BLI_map_test.cc
@@ -604,6 +604,15 @@ TEST(map, GenericAlgorithms)
EXPECT_EQ(std::count(map.keys().begin(), map.keys().end(), 7), 1);
}
+TEST(map, AddAsVariadic)
+{
+ Map<int, StringRef> map;
+ map.add_as(3, "hello", 2);
+ map.add_as(2, "test", 1);
+ EXPECT_EQ(map.lookup(3), "he");
+ EXPECT_EQ(map.lookup(2), "t");
+}
+
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/
diff --git a/source/blender/blenlib/tests/BLI_stack_cxx_test.cc b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
index f1fcdae3a52..b3108381d78 100644
--- a/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
+++ b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
@@ -93,6 +93,15 @@ TEST(stack, Push)
EXPECT_EQ(stack.size(), 2);
}
+TEST(stack, PushAs)
+{
+ Stack<StringRef> stack;
+ stack.push_as("hello", 3);
+ stack.push_as("world", 1);
+ EXPECT_EQ(stack.pop(), "w");
+ EXPECT_EQ(stack.pop(), "hel");
+}
+
TEST(stack, PushMultiple)
{
Stack<int> stack;
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index 462f13c15ab..e8636168308 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -248,6 +248,15 @@ TEST(vector, Append)
EXPECT_EQ(vec[2], 7);
}
+TEST(vector, AppendAs)
+{
+ Vector<StringRef> vec;
+ vec.append_as("hello", 2);
+ vec.append_as("world", 3);
+ EXPECT_EQ(vec[0], "he");
+ EXPECT_EQ(vec[1], "wor");
+}
+
TEST(vector, AppendAndGetIndex)
{
Vector<int> vec;
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
index ac25229cd69..a6d2ca10315 100644
--- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -1,26 +1,29 @@
/* Apache License, Version 2.0 */
+#include "BLI_array.hh"
#include "BLI_strict_flags.h"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "BLI_virtual_array.hh"
#include "testing/testing.h"
namespace blender::tests {
-TEST(virtual_array, ForSpan)
+TEST(virtual_array, Span)
{
std::array<int, 5> data = {3, 4, 5, 6, 7};
- VArrayForSpan<int> varray{data};
+ VArray_For_Span<int> varray{data};
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray.get(0), 3);
EXPECT_EQ(varray.get(4), 7);
EXPECT_TRUE(varray.is_span());
EXPECT_FALSE(varray.is_single());
- EXPECT_EQ(varray.get_span().data(), data.data());
+ EXPECT_EQ(varray.get_internal_span().data(), data.data());
}
-TEST(virtual_array, ForSingle)
+TEST(virtual_array, Single)
{
- VArrayForSingle<int> varray{10, 4};
+ VArray_For_Single<int> varray{10, 4};
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray.get(0), 10);
EXPECT_EQ(varray.get(3), 10);
@@ -28,4 +31,124 @@ TEST(virtual_array, ForSingle)
EXPECT_TRUE(varray.is_single());
}
+TEST(virtual_array, Array)
+{
+ Array<int> array = {1, 2, 3, 5, 8};
+ {
+ VArray_For_ArrayContainer varray{array};
+ EXPECT_EQ(varray.size(), 5);
+ EXPECT_EQ(varray[0], 1);
+ EXPECT_EQ(varray[2], 3);
+ EXPECT_EQ(varray[3], 5);
+ EXPECT_TRUE(varray.is_span());
+ }
+ {
+ VArray_For_ArrayContainer varray{std::move(array)};
+ EXPECT_EQ(varray.size(), 5);
+ EXPECT_EQ(varray[0], 1);
+ EXPECT_EQ(varray[2], 3);
+ EXPECT_EQ(varray[3], 5);
+ EXPECT_TRUE(varray.is_span());
+ }
+ {
+ VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */
+ EXPECT_TRUE(varray.is_empty());
+ }
+}
+
+TEST(virtual_array, Vector)
+{
+ Vector<int> vector = {9, 8, 7, 6};
+ VArray_For_ArrayContainer varray{std::move(vector)};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 9);
+ EXPECT_EQ(varray[3], 6);
+}
+
+TEST(virtual_array, StdVector)
+{
+ std::vector<int> vector = {5, 6, 7, 8};
+ VArray_For_ArrayContainer varray{std::move(vector)};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 5);
+ EXPECT_EQ(varray[1], 6);
+}
+
+TEST(virtual_array, StdArray)
+{
+ std::array<int, 4> array = {2, 3, 4, 5};
+ VArray_For_ArrayContainer varray{array};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 2);
+ EXPECT_EQ(varray[1], 3);
+}
+
+TEST(virtual_array, VectorSet)
+{
+ VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1};
+ VArray_For_ArrayContainer varray{std::move(vector_set)};
+ EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 5);
+ EXPECT_EQ(varray[1], 3);
+ EXPECT_EQ(varray[2], 7);
+ EXPECT_EQ(varray[3], 1);
+}
+
+TEST(virtual_array, Func)
+{
+ auto func = [](int64_t index) { return (int)(index * index); };
+ VArray_For_Func<int, decltype(func)> varray{10, func};
+ EXPECT_EQ(varray.size(), 10);
+ EXPECT_EQ(varray[0], 0);
+ EXPECT_EQ(varray[3], 9);
+ EXPECT_EQ(varray[9], 81);
+}
+
+TEST(virtual_array, AsSpan)
+{
+ auto func = [](int64_t index) { return (int)(10 * index); };
+ VArray_For_Func<int, decltype(func)> func_varray{10, func};
+ VArray_Span span_varray{func_varray};
+ EXPECT_EQ(span_varray.size(), 10);
+ Span<int> span = span_varray;
+ EXPECT_EQ(span.size(), 10);
+ EXPECT_EQ(span[0], 0);
+ EXPECT_EQ(span[3], 30);
+ EXPECT_EQ(span[6], 60);
+}
+
+static int get_x(const std::array<int, 3> &item)
+{
+ return item[0];
+}
+
+static void set_x(std::array<int, 3> &item, int value)
+{
+ item[0] = value;
+}
+
+TEST(virtual_array, DerivedSpan)
+{
+ Vector<std::array<int, 3>> vector;
+ vector.append({3, 4, 5});
+ vector.append({1, 1, 1});
+ {
+ VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector};
+ EXPECT_EQ(varray.size(), 2);
+ EXPECT_EQ(varray[0], 3);
+ EXPECT_EQ(varray[1], 1);
+ }
+ {
+ VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector};
+ EXPECT_EQ(varray.size(), 2);
+ EXPECT_EQ(varray[0], 3);
+ EXPECT_EQ(varray[1], 1);
+ varray.set(0, 10);
+ varray.set(1, 20);
+ EXPECT_EQ(vector[0][0], 10);
+ EXPECT_EQ(vector[1][0], 20);
+ }
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index ee9b9a49768..36802fc8842 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
intern/versioning_270.c
intern/versioning_280.c
intern/versioning_290.c
+ intern/versioning_300.c
intern/versioning_cycles.c
intern/versioning_defaults.c
intern/versioning_dna.c
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 85cf45bd868..b4623425582 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3868,6 +3868,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
blo_do_versions_270(fd, lib, main);
blo_do_versions_280(fd, lib, main);
blo_do_versions_290(fd, lib, main);
+ blo_do_versions_300(fd, lib, main);
blo_do_versions_cycles(fd, lib, main);
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
@@ -3891,6 +3892,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
do_versions_after_linking_270(main);
do_versions_after_linking_280(main, reports);
do_versions_after_linking_290(main, reports);
+ do_versions_after_linking_300(main, reports);
do_versions_after_linking_cycles(main);
main->is_locked_for_linking = false;
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 9682b5456d2..d1d4e0b3256 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -210,6 +210,7 @@ void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_290(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_300(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Main *bmain);
void do_versions_after_linking_250(struct Main *bmain);
@@ -217,6 +218,7 @@ void do_versions_after_linking_260(struct Main *bmain);
void do_versions_after_linking_270(struct Main *bmain);
void do_versions_after_linking_280(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_290(struct Main *bmain, struct ReportList *reports);
+void do_versions_after_linking_300(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
/* This is rather unfortunate to have to expose this here, but better use that nasty hack in
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index fe8e46e8928..916c4bf0cad 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -2059,19 +2059,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Set default value for the new bisect_threshold parameter in the mirror modifier. */
- if (!MAIN_VERSION_ATLEAST(bmain, 293, 19)) {
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
- if (md->type == eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
- /* This was the previous hard-coded value. */
- mmd->bisect_threshold = 0.001f;
- }
- }
- }
- }
-
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
new file mode 100644
index 00000000000..6b13b21f057
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -0,0 +1,80 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup blenloader
+ */
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_genfile.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_main.h"
+
+#include "BLO_readfile.h"
+#include "readfile.h"
+
+void do_versions_after_linking_300(Main *UNUSED(bmain), ReportList *UNUSED(reports))
+{
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #blo_do_versions_300 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
+}
+
+/* NOLINTNEXTLINE: readability-function-size */
+void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
+{
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+
+ /* Set default value for the new bisect_threshold parameter in the mirror modifier. */
+ if (!DNA_struct_elem_find(fd->filesdna, "MirrorModifierData", "float", "bisect_threshold")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ /* This was the previous hard-coded value. */
+ mmd->bisect_threshold = 0.001f;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index c07271a0d33..49b5e0fecd3 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -348,7 +348,14 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts,
}
/* Draw line to first point to complete the loop for cyclic strokes. */
if (is_cyclic) {
- gpencil_buffer_add_point(verts, cols, gps, &pts[0], v++, false);
+ gpencil_buffer_add_point(verts, cols, gps, &pts[0], v, false);
+ /* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the
+ * first point. It should be the factor of the last point plus the distance from the last point
+ * to the first.
+ */
+ gpStrokeVert *vert = &verts[v];
+ vert->u_stroke = verts[v - 1].u_stroke + len_v3v3(&pts[pts_len - 1].x, &pts[0].x);
+ v++;
}
/* Last adjacency point (not drawn). */
adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 767d822aa39..535ccaa06fd 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5576,7 +5576,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
- .use_object_edit_cage = false,
+ .edit_mode_type = SNAP_GEOM_FINAL,
},
mval,
NULL,
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 364444f99ae..68322ed56af 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -292,7 +292,7 @@ static int gizmo_move_modal(bContext *C,
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
.use_occlusion_test = true,
},
mval_fl,
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index cd7d0f5fb4c..ee344561b0e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -68,7 +68,9 @@ typedef struct SnapGizmo3D {
struct {
int x;
int y;
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
short shift, ctrl, alt, oskey;
+#endif
} last_eventstate;
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
@@ -99,28 +101,30 @@ static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManage
if (wm && wm->winactive) {
const wmEvent *event = wm->winactive->eventstate;
if ((event->x != snap_gizmo->last_eventstate.x) ||
- (event->y != snap_gizmo->last_eventstate.y) ||
- (event->ctrl != snap_gizmo->last_eventstate.ctrl) ||
- (event->shift != snap_gizmo->last_eventstate.shift) ||
- (event->alt != snap_gizmo->last_eventstate.alt) ||
- (event->oskey != snap_gizmo->last_eventstate.oskey)) {
+ (event->y != snap_gizmo->last_eventstate.y)) {
return true;
}
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
+ if ((event->ctrl != snap_gizmo->last_eventstate.ctrl) ||
+ (event->shift != snap_gizmo->last_eventstate.shift) ||
+ (event->alt != snap_gizmo->last_eventstate.alt) ||
+ (event->oskey != snap_gizmo->last_eventstate.oskey)) {
+ return true;
+ }
+ }
+#endif
}
return false;
}
/* Copies the current eventstate. */
-static void eventstate_save(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
+static void eventstate_save_xy(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
{
if (wm && wm->winactive) {
const wmEvent *event = wm->winactive->eventstate;
snap_gizmo->last_eventstate.x = event->x;
snap_gizmo->last_eventstate.y = event->y;
- snap_gizmo->last_eventstate.ctrl = event->ctrl;
- snap_gizmo->last_eventstate.shift = event->shift;
- snap_gizmo->last_eventstate.alt = event->alt;
- snap_gizmo->last_eventstate.oskey = event->oskey;
}
}
@@ -140,6 +144,12 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
return snap_gizmo->invert_snap;
}
+ /* Save new eventstate. */
+ snap_gizmo->last_eventstate.ctrl = event->ctrl;
+ snap_gizmo->last_eventstate.shift = event->shift;
+ snap_gizmo->last_eventstate.alt = event->alt;
+ snap_gizmo->last_eventstate.oskey = event->oskey;
+
const int snap_on = snap_gizmo->snap_on;
wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap);
@@ -328,23 +338,17 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
Scene *scene = DEG_get_input_scene(depsgraph);
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- if ((snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE) == 0) {
- bool invert_snap_toggle = invert_snap(snap_gizmo, wm);
- if (invert_snap_toggle != snap_gizmo->invert_snap) {
- snap_gizmo->invert_snap = invert_snap_toggle;
-
- /* Status has changed, be sure to save before early return. */
- eventstate_save(snap_gizmo, wm);
- }
+ if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
+ snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm);
const ToolSettings *ts = scene->toolsettings;
- if (invert_snap_toggle != !(ts->snap_flag & SCE_SNAP)) {
+ if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
snap_gizmo->snap_elem = 0;
return 0;
}
}
#endif
- eventstate_save(snap_gizmo, wm);
+ eventstate_save_xy(snap_gizmo, wm);
snap_gizmo->is_enabled = true;
@@ -364,25 +368,39 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
}
+ eSnapSelect snap_select = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_ONLY_ACTIVE) ?
+ SNAP_ONLY_ACTIVE :
+ SNAP_ALL;
+
+ eSnapEditType edit_mode_type = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL) ?
+ SNAP_GEOM_FINAL :
+ (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE) ?
+ SNAP_GEOM_CAGE :
+ SNAP_GEOM_EDIT;
+
+ bool use_occlusion_test = (snap_gizmo->flag & ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE) ? false :
+ true;
+
float dist_px = 12.0f * U.pixelsize;
ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz);
- snap_elem = ED_transform_snap_object_project_view3d_ex(snap_gizmo->snap_context_v3d,
- depsgraph,
- snap_elements,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
- .use_occlusion_test = true,
- },
- mval_fl,
- prev_co,
- &dist_px,
- co,
- no,
- &index,
- NULL,
- NULL);
+ snap_elem = ED_transform_snap_object_project_view3d_ex(
+ snap_gizmo->snap_context_v3d,
+ depsgraph,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_select = snap_select,
+ .edit_mode_type = edit_mode_type,
+ .use_occlusion_test = use_occlusion_test,
+ },
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ NULL);
}
if (snap_elem == 0) {
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index b269fd84d5f..c93fcb9eb8c 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -3745,3 +3745,51 @@ void GPENCIL_OT_layer_mask_remove(wmOperatorType *ot)
ot->exec = gpencil_layer_mask_remove_exec;
ot->poll = gpencil_active_layer_poll;
}
+
+static int gpencil_layer_mask_move_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ const int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl)) {
+ return OPERATOR_CANCELLED;
+ }
+ if (gpl->act_mask > 0) {
+ bGPDlayer_Mask *mask = BLI_findlink(&gpl->mask_layers, gpl->act_mask - 1);
+ if (mask != NULL) {
+ BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
+ if (BLI_listbase_link_move(&gpl->mask_layers, mask, direction)) {
+ gpl->act_mask += direction;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_mask_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Grease Pencil Layer Mask";
+ ot->idname = "GPENCIL_OT_layer_mask_move";
+ ot->description = "Move the active Grease Pencil mask layer up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gpencil_layer_mask_move_exec;
+ ot->poll = gpencil_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index d388e11dc8c..d90f74fbf4f 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1818,18 +1818,13 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
- Scene *scene = CTX_data_scene(C);
bGPDlayer *target_layer = NULL;
ListBase strokes = {NULL, NULL};
int layer_num = RNA_int_get(op->ptr, "layer");
const bool use_autolock = (bool)(gpd->flag & GP_DATA_AUTOLOCK_LAYERS);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
- BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
- return OPERATOR_CANCELLED;
- }
-
- /* if autolock enabled, disabled now */
+ /* If autolock enabled, disabled now. */
if (use_autolock) {
gpd->flag &= ~GP_DATA_AUTOLOCK_LAYERS;
}
@@ -1852,53 +1847,59 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* Extract all strokes to move to this layer
- * NOTE: We need to do this in a two-pass system to avoid conflicts with strokes
- * getting repeatedly moved
- */
- CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = gpl->actframe;
-
- /* skip if no frame with strokes, or if this is the layer we're moving strokes to */
- if ((gpl == target_layer) || (gpf == NULL)) {
+ /* Extract all strokes to move to this layer. */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl_src, editable_gpencil_layers) {
+ /* Skip if this is the layer we're moving strokes to. */
+ if (gpl_src == target_layer) {
continue;
}
+ bGPDframe *init_gpf = (is_multiedit) ? gpl_src->frames.first : gpl_src->actframe;
+ for (bGPDframe *gpf_src = init_gpf; gpf_src; gpf_src = gpf_src->next) {
+ if ((gpf_src == gpl_src->actframe) ||
+ ((gpf_src->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf_src == NULL) {
+ continue;
+ }
- /* make copies of selected strokes, and deselect these once we're done */
- LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ bGPDstroke *gpsn = NULL;
+ BLI_listbase_clear(&strokes);
+ for (bGPDstroke *gps = gpf_src->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ /* Skip strokes that are invalid for current view. */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_material_editable(ob, gpl_src, gps) == false) {
+ continue;
+ }
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
+ if (gps->flag & GP_STROKE_SELECT) {
+ BLI_remlink(&gpf_src->strokes, gps);
+ BLI_addtail(&strokes, gps);
+ }
+ }
+ /* Paste them all in one go. */
+ if (strokes.first) {
+ bGPDframe *gpf_dst = BKE_gpencil_layer_frame_get(
+ target_layer, gpf_src->framenum, GP_GETFRAME_ADD_NEW);
- /* Check if the color is editable. */
- if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
- continue;
+ BLI_movelisttolist(&gpf_dst->strokes, &strokes);
+ BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
+ }
}
-
- /* TODO: Don't just move entire strokes - instead, only copy the selected portions... */
- if (gps->flag & GP_STROKE_SELECT) {
- BLI_remlink(&gpf->strokes, gps);
- BLI_addtail(&strokes, gps);
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
}
}
-
- /* if new layer and autolock, lock old layer */
+ /* If new layer and autolock, lock old layer. */
if ((layer_num == -1) && (use_autolock)) {
- gpl->flag |= GP_LAYER_LOCKED;
+ gpl_src->flag |= GP_LAYER_LOCKED;
}
}
CTX_DATA_END;
- /* Paste them all in one go */
- if (strokes.first) {
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(target_layer, CFRA, GP_GETFRAME_ADD_NEW);
-
- BLI_movelisttolist(&gpf->strokes, &strokes);
- BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
- }
-
/* back autolock status */
if (use_autolock) {
gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
@@ -3762,6 +3763,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
const eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* Init snap context for geometry projection. */
SnapObjectContext *sctx = NULL;
@@ -3774,36 +3776,55 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
int cfra_prv = INT_MIN;
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- bool curve_select = false;
- if (is_curve_edit && gps->editcurve != NULL) {
- curve_select = gps->editcurve->flag & GP_CURVE_SELECT;
- }
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- if (gps->flag & GP_STROKE_SELECT || curve_select) {
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
+ continue;
+ }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ bool curve_select = false;
+ if (is_curve_edit && gps->editcurve != NULL) {
+ curve_select = gps->editcurve->flag & GP_CURVE_SELECT;
+ }
- /* update frame to get the new location of objects */
- if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf_->framenum)) {
- cfra_prv = gpf_->framenum;
- CFRA = gpf_->framenum;
- BKE_scene_graph_update_for_newframe(depsgraph);
- }
+ if (gps->flag & GP_STROKE_SELECT || curve_select) {
- ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf_, gps, mode, keep_original);
+ /* update frame to get the new location of objects */
+ if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf->framenum)) {
+ cfra_prv = gpf->framenum;
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ }
- if (is_curve_edit && gps->editcurve != NULL) {
- BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
- /* Update the selection from the stroke to the curve. */
- BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
+ ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf, gps, mode, keep_original);
- gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
- BKE_gpencil_stroke_geometry_update(gpd, gps);
- }
+ if (is_curve_edit && gps->editcurve != NULL) {
+ BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
+ /* Update the selection from the stroke to the curve. */
+ BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
- changed = true;
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+
+ changed = true;
+ }
+ }
+ }
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
+ }
}
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
+ CTX_DATA_END;
/* return frame state and DB to original state */
CFRA = oldframe;
@@ -3832,7 +3853,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
"VIEW",
0,
"View",
- "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
+ "Reproject the strokes to end up on the same plane, as if drawn from the current "
+ "viewpoint "
"using 'Cursor' Stroke Placement"},
{GP_REPROJECT_SURFACE,
"SURFACE",
@@ -3851,7 +3873,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
ot->name = "Reproject Strokes";
ot->idname = "GPENCIL_OT_reproject";
ot->description =
- "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
+ "Reproject the selected strokes from the current viewpoint as if they had been newly "
+ "drawn "
"(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
"or for matching deforming geometry)";
@@ -4208,7 +4231,8 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
ot->name = "Subdivide Stroke";
ot->idname = "GPENCIL_OT_stroke_subdivide";
ot->description =
- "Subdivide between continuous selected points of the stroke adding a point half way between "
+ "Subdivide between continuous selected points of the stroke adding a point half way "
+ "between "
"them";
/* api callbacks */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index c6f74c39beb..09200125cb7 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -421,6 +421,7 @@ void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot);
void GPENCIL_OT_layer_mask_add(struct wmOperatorType *ot);
void GPENCIL_OT_layer_mask_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_mask_move(struct wmOperatorType *ot);
void GPENCIL_OT_hide(struct wmOperatorType *ot);
void GPENCIL_OT_reveal(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 7ca53779522..0062e363cdf 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -1434,36 +1434,32 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayout *col, *row;
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
const eGP_Interpolate_Type type = RNA_enum_get(op->ptr, "type");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "step", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "step", 0, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "layers", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "layers", 0, NULL, ICON_NONE);
if (CTX_data_mode_enum(C) == CTX_MODE_EDIT_GPENCIL) {
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "interpolate_selected_only", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "interpolate_selected_only", 0, NULL, ICON_NONE);
}
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "flip", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "flip", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, &ptr, "smooth_factor", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "smooth_steps", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "smooth_factor", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "smooth_steps", 0, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "type", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "type", 0, NULL, ICON_NONE);
if (type == GP_IPO_CURVEMAP) {
/* Get an RNA pointer to ToolSettings to give to the custom curve. */
@@ -1477,16 +1473,16 @@ static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op)
}
else if (type != GP_IPO_LINEAR) {
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "easing", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "easing", 0, NULL, ICON_NONE);
if (type == GP_IPO_BACK) {
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "back", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "back", 0, NULL, ICON_NONE);
}
else if (type == GP_IPO_ELASTIC) {
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "amplitude", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "amplitude", 0, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "period", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "period", 0, NULL, ICON_NONE);
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 1a6cb5670c4..7d454eb3be1 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -601,6 +601,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_mask_add);
WM_operatortype_append(GPENCIL_OT_layer_mask_remove);
+ WM_operatortype_append(GPENCIL_OT_layer_mask_move);
WM_operatortype_append(GPENCIL_OT_hide);
WM_operatortype_append(GPENCIL_OT_reveal);
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 58b2cb80bbe..571519e52f7 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -263,6 +263,11 @@ struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *sce
typedef enum {
ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE = 1 << 0,
+ ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE = 1 << 1,
+ ED_SNAPGIZMO_OCCLUSION_ALWAYS_FALSE = 1 << 2, /* TODO. */
+ ED_SNAPGIZMO_SNAP_ONLY_ACTIVE = 1 << 3,
+ ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL = 1 << 4,
+ ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE = 1 << 5,
} eSnapGizmo;
void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, eSnapGizmo flag);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 12d6f1fce54..179c9d5b30d 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -511,6 +511,7 @@ bool ED_autokeyframe_property(struct bContext *C,
#define ANIM_KS_ROTATION_ID "Rotation"
#define ANIM_KS_SCALING_ID "Scaling"
#define ANIM_KS_LOC_ROT_SCALE_ID "LocRotScale"
+#define ANIM_KS_LOC_ROT_SCALE_CPROP_ID "LocRotScaleCProp"
#define ANIM_KS_AVAILABLE_ID "Available"
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index b3205acb8ee..169b25a1358 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -200,7 +200,7 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
/* screens */
void ED_screens_init(struct Main *bmain, struct wmWindowManager *wm);
void ED_screen_draw_edges(struct wmWindow *win);
-void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2);
+void ED_screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
void ED_screen_draw_split_preview(struct ScrArea *area, const int dir, const float fac);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index b7174964ef6..42e73bbf744 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -39,12 +39,19 @@ struct View3D;
/* ED_transform_snap_object_*** API */
-typedef enum eSnapSelect {
+typedef enum {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
SNAP_NOT_ACTIVE = 2,
+ SNAP_ONLY_ACTIVE = 3,
} eSnapSelect;
+typedef enum {
+ SNAP_GEOM_FINAL = 0,
+ SNAP_GEOM_CAGE = 1,
+ SNAP_GEOM_EDIT = 2, /* Bmesh for mesh-type. */
+} eSnapEditType;
+
/** used for storing multiple hits */
struct SnapObjectHitDepth {
struct SnapObjectHitDepth *next, *prev;
@@ -54,7 +61,7 @@ struct SnapObjectHitDepth {
float no[3];
int index;
- struct Object *ob;
+ struct Object *ob_eval;
float obmat[4][4];
/* needed to tell which ray-cast this was part of,
@@ -64,10 +71,10 @@ struct SnapObjectHitDepth {
/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
- /* special context sensitive handling for the active or selected object */
+ /* Special context sensitive handling for the active or selected object. */
char snap_select;
- /* use editmode cage */
- unsigned int use_object_edit_cage : 1;
+ /* Geometry for snapping in edit mode. */
+ char edit_mode_type;
/* snap to the closest element, use when using more than one snap type */
unsigned int use_occlusion_test : 1;
/* exclude back facing geometry from snapping */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 81872428038..e0d9971529f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -186,17 +186,17 @@ enum {
UI_RETURN_POPUP_OK = 1 << 5,
};
-/* but->flag - general state flags. */
+/** #uiBut.flag general state flags. */
enum {
- /** Warning, the first 6 flags are internal. */
- UI_BUT_ICON_SUBMENU = 1 << 6,
- UI_BUT_ICON_PREVIEW = 1 << 7,
+ /* WARNING: the first 7 flags are internal (see #UI_SELECT definition). */
+ UI_BUT_ICON_SUBMENU = 1 << 7,
+ UI_BUT_ICON_PREVIEW = 1 << 8,
- UI_BUT_NODE_LINK = 1 << 8,
- UI_BUT_NODE_ACTIVE = 1 << 9,
- UI_BUT_DRAG_LOCK = 1 << 10,
+ UI_BUT_NODE_LINK = 1 << 9,
+ UI_BUT_NODE_ACTIVE = 1 << 10,
+ UI_BUT_DRAG_LOCK = 1 << 11,
/** Grayed out and un-editable. */
- UI_BUT_DISABLED = 1 << 11,
+ UI_BUT_DISABLED = 1 << 12,
UI_BUT_ANIMATED = 1 << 13,
UI_BUT_ANIMATED_KEY = 1 << 14,
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index a5a5a69728e..5a254db0eec 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1114,6 +1114,13 @@ static void ui_apply_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (data->str) {
+ double value;
+ /* Check if the string value is a number and cancel if it's equal to the startvalue. */
+ if (ui_but_string_eval_number(C, but, data->str, &value) && (value == data->startvalue)) {
+ data->cancel = true;
+ return;
+ }
+
if (ui_but_string_set(C, but, data->str)) {
data->value = ui_but_value_get(but);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 4c96512b4f3..0e465be5bf6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -77,17 +77,20 @@ struct wmTimer;
/* popover width (multiplied by 'U.widget_unit') */
#define UI_POPOVER_WIDTH_UNITS 10
-/* uiBut->flag */
+/** #uiBut.flag */
enum {
- UI_SELECT = (1 << 0), /* use when the button is pressed */
- UI_SCROLLED = (1 << 1), /* temp hidden, scrolled away */
+ /** Use when the button is pressed. */
+ UI_SELECT = (1 << 0),
+ /** Temporarily hidden (scrolled out of the view). */
+ UI_SCROLLED = (1 << 1),
UI_ACTIVE = (1 << 2),
UI_HAS_ICON = (1 << 3),
UI_HIDDEN = (1 << 4),
- UI_SELECT_DRAW = (1 << 5), /* Display selected, doesn't impact interaction. */
+ /** Display selected, doesn't impact interaction. */
+ UI_SELECT_DRAW = (1 << 5),
/** Property search filter is active and the button does not match. */
- UI_SEARCH_FILTER_NO_MATCH = (1 << 12),
- /* warn: rest of uiBut->flag in UI_interface.h */
+ UI_SEARCH_FILTER_NO_MATCH = (1 << 6),
+ /* WARNING: rest of #uiBut.flag in UI_interface.h */
};
/* uiBut->dragflag */
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index b11a727b173..accfb78ab94 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -947,12 +947,13 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* button is disabled, we may be able to tell user why */
if (but->flag & UI_BUT_DISABLED) {
const char *disabled_msg = NULL;
+ bool disabled_msg_free = false;
/* if operator poll check failed, it can give pretty precise info why */
if (but->optype) {
- CTX_wm_operator_poll_msg_set(C, NULL);
+ CTX_wm_operator_poll_msg_clear(C);
WM_operator_poll_context(C, but->optype, but->opcontext);
- disabled_msg = CTX_wm_operator_poll_msg_get(C);
+ disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free);
}
/* alternatively, buttons can store some reasoning too */
else if (but->disabled_info) {
@@ -967,6 +968,9 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
});
field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg);
}
+ if (disabled_msg_free) {
+ MEM_freeN((void *)disabled_msg);
+ }
}
if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) {
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 1f1165a464b..592467c2a85 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -240,22 +240,17 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
static void wm_alembic_export_draw(bContext *C, wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
/* Conveniently set start and end frame to match the scene's frame range. */
Scene *scene = CTX_data_scene(C);
- if (scene != NULL && RNA_boolean_get(&ptr, "init_scene_frame_range")) {
- RNA_int_set(&ptr, "start", SFRA);
- RNA_int_set(&ptr, "end", EFRA);
+ if (scene != NULL && RNA_boolean_get(op->ptr, "init_scene_frame_range")) {
+ RNA_int_set(op->ptr, "start", SFRA);
+ RNA_int_set(op->ptr, "end", EFRA);
- RNA_boolean_set(&ptr, "init_scene_frame_range", false);
+ RNA_boolean_set(op->ptr, "init_scene_frame_range", false);
}
- ui_alembic_export_settings(op->layout, &ptr);
+ ui_alembic_export_settings(op->layout, op->ptr);
}
static bool wm_alembic_export_check(bContext *UNUSED(C), wmOperator *op)
@@ -594,13 +589,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
}
-static void wm_alembic_import_draw(bContext *C, wmOperator *op)
+static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- ui_alembic_import_settings(op->layout, &ptr);
+ ui_alembic_import_settings(op->layout, op->ptr);
}
/* op->invoke, opens fileselect if path property not set, otherwise executes */
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index c8e3e1814fc..859c12d7e52 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -400,13 +400,9 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
}
}
-static void wm_collada_export_draw(bContext *C, wmOperator *op)
+static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- uiCollada_exportSettings(op->layout, &ptr);
+ uiCollada_exportSettings(op->layout, op->ptr);
}
static bool wm_collada_export_check(bContext *UNUSED(C), wmOperator *op)
@@ -798,13 +794,9 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(box, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
}
-static void wm_collada_import_draw(bContext *C, wmOperator *op)
+static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- uiCollada_importSettings(op->layout, &ptr);
+ uiCollada_importSettings(op->layout, op->ptr);
}
void WM_OT_collada_import(wmOperatorType *ot)
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index 7b4b59902f9..b49be324372 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -215,14 +215,9 @@ static void ui_gpencil_export_svg_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "use_clip_camera", 0, NULL, ICON_NONE);
}
-static void wm_gpencil_export_svg_draw(bContext *C, wmOperator *op)
+static void wm_gpencil_export_svg_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- ui_gpencil_export_svg_settings(op->layout, &ptr);
+ ui_gpencil_export_svg_settings(op->layout, op->ptr);
}
static bool wm_gpencil_export_svg_poll(bContext *C)
@@ -378,14 +373,9 @@ static void ui_gpencil_export_pdf_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "use_normalized_thickness", 0, NULL, ICON_NONE);
}
-static void wm_gpencil_export_pdf_draw(bContext *C, wmOperator *op)
+static void wm_gpencil_export_pdf_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- ui_gpencil_export_pdf_settings(op->layout, &ptr);
+ ui_gpencil_export_pdf_settings(op->layout, op->ptr);
}
static bool wm_gpencil_export_pdf_poll(bContext *C)
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index e4fabc0c5de..a9911f1cef2 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -136,13 +136,9 @@ static void ui_gpencil_import_svg_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "scale", 0, NULL, ICON_NONE);
}
-static void wm_gpencil_import_svg_draw(bContext *C, wmOperator *op)
+static void wm_gpencil_import_svg_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- ui_gpencil_import_svg_settings(op->layout, &ptr);
+ ui_gpencil_import_svg_settings(op->layout, op->ptr);
}
static bool wm_gpencil_import_svg_poll(bContext *C)
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 51190268c4c..43492cd57af 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -911,76 +911,73 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void edbm_bevel_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayout *col, *row;
- PointerRNA ptr, toolsettings_ptr;
+ PointerRNA toolsettings_ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- int profile_type = RNA_enum_get(&ptr, "profile_type");
- int offset_type = RNA_enum_get(&ptr, "offset_type");
- bool affect_type = RNA_enum_get(&ptr, "affect");
+ int profile_type = RNA_enum_get(op->ptr, "profile_type");
+ int offset_type = RNA_enum_get(op->ptr, "offset_type");
+ bool affect_type = RNA_enum_get(op->ptr, "affect");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "affect", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "affect", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, &ptr, "offset_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset_type", 0, NULL, ICON_NONE);
if (offset_type == BEVEL_AMT_PERCENT) {
- uiItemR(layout, &ptr, "offset_pct", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset_pct", 0, NULL, ICON_NONE);
}
else {
- uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset", 0, NULL, ICON_NONE);
}
- uiItemR(layout, &ptr, "segments", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "segments", 0, NULL, ICON_NONE);
if (ELEM(profile_type, BEVEL_PROFILE_SUPERELLIPSE, BEVEL_PROFILE_CUSTOM)) {
uiItemR(layout,
- &ptr,
+ op->ptr,
"profile",
UI_ITEM_R_SLIDER,
(profile_type == BEVEL_PROFILE_SUPERELLIPSE) ? IFACE_("Shape") : IFACE_("Miter Shape"),
ICON_NONE);
}
- uiItemR(layout, &ptr, "material", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "material", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, &ptr, "harden_normals", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "clamp_overlap", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "loop_slide", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "harden_normals", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "clamp_overlap", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "loop_slide", 0, NULL, ICON_NONE);
col = uiLayoutColumnWithHeading(layout, true, IFACE_("Mark"));
uiLayoutSetActive(col, affect_type == BEVEL_AFFECT_EDGES);
- uiItemR(col, &ptr, "mark_seam", 0, IFACE_("Seams"), ICON_NONE);
- uiItemR(col, &ptr, "mark_sharp", 0, IFACE_("Sharp"), ICON_NONE);
+ uiItemR(col, op->ptr, "mark_seam", 0, IFACE_("Seams"), ICON_NONE);
+ uiItemR(col, op->ptr, "mark_sharp", 0, IFACE_("Sharp"), ICON_NONE);
uiItemS(layout);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, affect_type == BEVEL_AFFECT_EDGES);
- uiItemR(col, &ptr, "miter_outer", 0, IFACE_("Miter Outer"), ICON_NONE);
- uiItemR(col, &ptr, "miter_inner", 0, IFACE_("Inner"), ICON_NONE);
- if (RNA_enum_get(&ptr, "miter_inner") == BEVEL_MITER_ARC) {
- uiItemR(col, &ptr, "spread", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "miter_outer", 0, IFACE_("Miter Outer"), ICON_NONE);
+ uiItemR(col, op->ptr, "miter_inner", 0, IFACE_("Inner"), ICON_NONE);
+ if (RNA_enum_get(op->ptr, "miter_inner") == BEVEL_MITER_ARC) {
+ uiItemR(col, op->ptr, "spread", 0, NULL, ICON_NONE);
}
uiItemS(layout);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, affect_type == BEVEL_AFFECT_EDGES);
- uiItemR(col, &ptr, "vmesh_method", 0, IFACE_("Intersection Type"), ICON_NONE);
+ uiItemR(col, op->ptr, "vmesh_method", 0, IFACE_("Intersection Type"), ICON_NONE);
- uiItemR(layout, &ptr, "face_strength_mode", 0, IFACE_("Face Strength"), ICON_NONE);
+ uiItemR(layout, op->ptr, "face_strength_mode", 0, IFACE_("Face Strength"), ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
if (profile_type == BEVEL_PROFILE_CUSTOM) {
/* Get an RNA pointer to ToolSettings to give to the curve profile template code. */
Scene *scene = CTX_data_scene(C);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 141f120396a..d1f228e951a 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -251,32 +251,28 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void edbm_intersect_ui(bContext *C, wmOperator *op)
+static void edbm_intersect_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayout *row;
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- bool use_exact = RNA_enum_get(&ptr, "solver") == ISECT_SOLVER_EXACT;
+ bool use_exact = RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "separate_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "separate_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
if (!use_exact) {
- uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "threshold", 0, NULL, ICON_NONE);
}
}
@@ -418,32 +414,28 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void edbm_intersect_boolean_ui(bContext *C, wmOperator *op)
+static void edbm_intersect_boolean_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayout *row;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- bool use_exact = RNA_enum_get(&ptr, "solver") == ISECT_SOLVER_EXACT;
+ bool use_exact = RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "operation", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "operation", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, &ptr, "use_swap", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "use_self", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_swap", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_self", 0, NULL, ICON_NONE);
if (!use_exact) {
- uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "threshold", 0, NULL, ICON_NONE);
}
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 33e4691bfb5..bb332a4094c 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3694,21 +3694,18 @@ static const EnumPropertyItem *shape_itemf(bContext *C,
static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
Object *obedit = CTX_data_edit_object(C);
Mesh *me = obedit->data;
PointerRNA ptr_key;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
RNA_id_pointer_create((ID *)me->key, &ptr_key);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
- uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", NULL, ICON_SHAPEKEY_DATA);
- uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE);
+ uiItemPointerR(layout, op->ptr, "shape", &ptr_key, "key_blocks", NULL, ICON_SHAPEKEY_DATA);
+ uiItemR(layout, op->ptr, "blend", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "add", 0, NULL, ICON_NONE);
}
void MESH_OT_blend_from_shape(wmOperatorType *ot)
@@ -5612,29 +5609,25 @@ static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
return true;
}
-static void edbm_decimate_ui(bContext *C, wmOperator *op)
+static void edbm_decimate_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout, *row, *col, *sub;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiLayoutSetPropSep(layout, true);
- uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "ratio", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "use_vertex_group", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_vertex_group", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group"));
- uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
+ uiLayoutSetActive(col, RNA_boolean_get(op->ptr, "use_vertex_group"));
+ uiItemR(col, op->ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
row = uiLayoutRowWithHeading(layout, true, IFACE_("Symmetry"));
- uiItemR(row, &ptr, "use_symmetry", 0, "", ICON_NONE);
+ uiItemR(row, op->ptr, "use_symmetry", 0, "", ICON_NONE);
sub = uiLayoutRow(row, true);
- uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_symmetry"));
- uiItemR(sub, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "use_symmetry"));
+ uiItemR(sub, op->ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
void MESH_OT_decimate(wmOperatorType *ot)
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 2e98f0558f3..19c9909039c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1721,7 +1721,7 @@ void EDBM_project_snap_verts(
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_ACTIVE,
- .use_object_edit_cage = false,
+ .edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
mval,
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index bcddf3d585c..a0de1e0fa84 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -3110,24 +3110,21 @@ static int object_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void object_convert_ui(bContext *C, wmOperator *op)
+static void object_convert_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
uiLayoutSetPropSep(layout, true);
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- uiItemR(layout, &ptr, "target", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "keep_original", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "target", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "keep_original", 0, NULL, ICON_NONE);
- if (RNA_enum_get(&ptr, "target") == OB_GPENCIL) {
- uiItemR(layout, &ptr, "thickness", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "angle", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "seams", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "faces", 0, NULL, ICON_NONE);
+ if (RNA_enum_get(op->ptr, "target") == OB_GPENCIL) {
+ uiItemR(layout, op->ptr, "thickness", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "seams", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "faces", 0, NULL, ICON_NONE);
}
}
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 2ba7ef8f972..6d1409a9044 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -33,184 +33,11 @@
#include "WM_api.h"
+#include "UI_interface.h"
#include "UI_resources.h"
#include "screen_intern.h"
-/**
- * Draw horizontal shape visualizing future joining
- * (left as well right direction of future joining).
- */
-static void draw_horizontal_join_shape(ScrArea *area, char dir, uint pos)
-{
- const float width = screen_geom_area_width(area) - 1;
- const float height = screen_geom_area_height(area) - 1;
-
- float w, h;
- if (height < width) {
- h = height / 8;
- w = height / 4;
- }
- else {
- h = width / 8;
- w = width / 4;
- }
-
- vec2f points[10];
- points[0].x = area->v1->vec.x;
- points[0].y = area->v1->vec.y + height / 2;
-
- points[1].x = area->v1->vec.x;
- points[1].y = area->v1->vec.y;
-
- points[2].x = area->v4->vec.x - w;
- points[2].y = area->v4->vec.y;
-
- points[3].x = area->v4->vec.x - w;
- points[3].y = area->v4->vec.y + height / 2 - 2 * h;
-
- points[4].x = area->v4->vec.x - 2 * w;
- points[4].y = area->v4->vec.y + height / 2;
-
- points[5].x = area->v4->vec.x - w;
- points[5].y = area->v4->vec.y + height / 2 + 2 * h;
-
- points[6].x = area->v3->vec.x - w;
- points[6].y = area->v3->vec.y;
-
- points[7].x = area->v2->vec.x;
- points[7].y = area->v2->vec.y;
-
- points[8].x = area->v4->vec.x;
- points[8].y = area->v4->vec.y + height / 2 - h;
-
- points[9].x = area->v4->vec.x;
- points[9].y = area->v4->vec.y + height / 2 + h;
-
- if (dir == 'l') {
- /* when direction is left, then we flip direction of arrow */
- float cx = area->v1->vec.x + width;
- for (int i = 0; i < 10; i++) {
- points[i].x -= cx;
- points[i].x = -points[i].x;
- points[i].x += area->v1->vec.x;
- }
- }
-
- immBegin(GPU_PRIM_TRI_FAN, 5);
-
- for (int i = 0; i < 5; i++) {
- immVertex2f(pos, points[i].x, points[i].y);
- }
-
- immEnd();
-
- immBegin(GPU_PRIM_TRI_FAN, 5);
-
- for (int i = 4; i < 8; i++) {
- immVertex2f(pos, points[i].x, points[i].y);
- }
-
- immVertex2f(pos, points[0].x, points[0].y);
- immEnd();
-
- immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y);
- immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y);
-}
-
-/**
- * Draw vertical shape visualizing future joining (up/down direction).
- */
-static void draw_vertical_join_shape(ScrArea *area, char dir, uint pos)
-{
- const float width = screen_geom_area_width(area) - 1;
- const float height = screen_geom_area_height(area) - 1;
-
- float w, h;
- if (height < width) {
- h = height / 4;
- w = height / 8;
- }
- else {
- h = width / 4;
- w = width / 8;
- }
-
- vec2f points[10];
- points[0].x = area->v1->vec.x + width / 2;
- points[0].y = area->v3->vec.y;
-
- points[1].x = area->v2->vec.x;
- points[1].y = area->v2->vec.y;
-
- points[2].x = area->v1->vec.x;
- points[2].y = area->v1->vec.y + h;
-
- points[3].x = area->v1->vec.x + width / 2 - 2 * w;
- points[3].y = area->v1->vec.y + h;
-
- points[4].x = area->v1->vec.x + width / 2;
- points[4].y = area->v1->vec.y + 2 * h;
-
- points[5].x = area->v1->vec.x + width / 2 + 2 * w;
- points[5].y = area->v1->vec.y + h;
-
- points[6].x = area->v4->vec.x;
- points[6].y = area->v4->vec.y + h;
-
- points[7].x = area->v3->vec.x;
- points[7].y = area->v3->vec.y;
-
- points[8].x = area->v1->vec.x + width / 2 - w;
- points[8].y = area->v1->vec.y;
-
- points[9].x = area->v1->vec.x + width / 2 + w;
- points[9].y = area->v1->vec.y;
-
- if (dir == 'u') {
- /* when direction is up, then we flip direction of arrow */
- float cy = area->v1->vec.y + height;
- for (int i = 0; i < 10; i++) {
- points[i].y -= cy;
- points[i].y = -points[i].y;
- points[i].y += area->v1->vec.y;
- }
- }
-
- immBegin(GPU_PRIM_TRI_FAN, 5);
-
- for (int i = 0; i < 5; i++) {
- immVertex2f(pos, points[i].x, points[i].y);
- }
-
- immEnd();
-
- immBegin(GPU_PRIM_TRI_FAN, 5);
-
- for (int i = 4; i < 8; i++) {
- immVertex2f(pos, points[i].x, points[i].y);
- }
-
- immVertex2f(pos, points[0].x, points[0].y);
- immEnd();
-
- immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y);
- immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y);
-}
-
-/**
- * Draw join shape due to direction of joining.
- */
-static void draw_join_shape(ScrArea *area, char dir, uint pos)
-{
- if (ELEM(dir, 'u', 'd')) {
- draw_vertical_join_shape(area, dir, pos);
- }
- else {
- draw_horizontal_join_shape(area, dir, pos);
- }
-}
-
#define CORNER_RESOLUTION 3
static void do_vert_pair(GPUVertBuf *vbo, uint pos, uint *vidx, int corner, int i)
@@ -290,28 +117,6 @@ static GPUBatch *batch_screen_edges_get(int *corner_len)
#undef CORNER_RESOLUTION
-/**
- * Draw screen area darker with arrow (visualization of future joining).
- */
-static void scrarea_draw_shape_dark(ScrArea *area, char dir, uint pos)
-{
- GPU_blend(GPU_BLEND_ALPHA);
- immUniformColor4ub(0, 0, 0, 50);
-
- draw_join_shape(area, dir, pos);
-}
-
-/**
- * Draw screen area lighter with arrow shape ("eraser" of previous dark shape).
- */
-static void scrarea_draw_shape_light(ScrArea *area, char UNUSED(dir), uint pos)
-{
- GPU_blend(GPU_BLEND_ALPHA);
- immUniformColor4ub(255, 255, 255, 25);
-
- immRectf(pos, area->v1->vec.x, area->v1->vec.y, area->v3->vec.x, area->v3->vec.y);
-}
-
static void drawscredge_area_draw(
int sizex, int sizey, short x1, short y1, short x2, short y2, float edge_thickness)
{
@@ -427,50 +232,92 @@ void ED_screen_draw_edges(wmWindow *win)
}
/**
- * The blended join arrows.
+ * Visual indication of the two areas involved in a proposed join.
*
* \param sa1: Area from which the resultant originates.
* \param sa2: Target area that will be replaced.
*/
-void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2)
+void ED_screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
{
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- GPU_line_width(1);
-
- /* blended join arrow */
int dir = area_getorientation(sa1, sa2);
- int dira = -1;
- if (dir != -1) {
- switch (dir) {
- case 0: /* W */
- dir = 'r';
- dira = 'l';
- break;
- case 1: /* N */
- dir = 'd';
- dira = 'u';
- break;
- case 2: /* E */
- dir = 'l';
- dira = 'r';
- break;
- case 3: /* S */
- dir = 'u';
- dira = 'd';
- break;
- }
+ if (dir == -1) {
+ return;
+ }
- GPU_blend(GPU_BLEND_ALPHA);
+ /* Rect of the combined areas.*/
+ bool vertical = ELEM(dir, 1, 3);
+ rctf combined = {.xmin = vertical ? MAX2(sa1->totrct.xmin, sa2->totrct.xmin) :
+ MIN2(sa1->totrct.xmin, sa2->totrct.xmin),
+ .xmax = vertical ? MIN2(sa1->totrct.xmax, sa2->totrct.xmax) :
+ MAX2(sa1->totrct.xmax, sa2->totrct.xmax),
+ .ymin = vertical ? MIN2(sa1->totrct.ymin, sa2->totrct.ymin) :
+ MAX2(sa1->totrct.ymin, sa2->totrct.ymin),
+ .ymax = vertical ? MAX2(sa1->totrct.ymax, sa2->totrct.ymax) :
+ MIN2(sa1->totrct.ymax, sa2->totrct.ymax)};
- scrarea_draw_shape_dark(sa2, dir, pos);
- scrarea_draw_shape_light(sa1, dira, pos);
+ uint pos_id = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(GPU_BLEND_ALPHA);
- GPU_blend(GPU_BLEND_NONE);
+ /* Highlight source (sa1) within combined area. */
+ immUniformColor4fv((const float[4]){1.0f, 1.0f, 1.0f, 0.10f});
+ immRectf(pos_id,
+ MAX2(sa1->totrct.xmin, combined.xmin),
+ MAX2(sa1->totrct.ymin, combined.ymin),
+ MIN2(sa1->totrct.xmax, combined.xmax),
+ MIN2(sa1->totrct.ymax, combined.ymax));
+
+ /* Highlight destination (sa2) within combined area. */
+ immUniformColor4fv((const float[4]){0.0f, 0.0f, 0.0f, 0.25f});
+ immRectf(pos_id,
+ MAX2(sa2->totrct.xmin, combined.xmin),
+ MAX2(sa2->totrct.ymin, combined.ymin),
+ MIN2(sa2->totrct.xmax, combined.xmax),
+ MIN2(sa2->totrct.ymax, combined.ymax));
+
+ int offset1;
+ int offset2;
+ area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
+ if (offset1 < 0 || offset2 > 0) {
+ /* Show partial areas that will be closed. */
+ immUniformColor4fv((const float[4]){0.0f, 0.0f, 0.0f, 0.8f});
+ if (vertical) {
+ if (sa1->totrct.xmin < combined.xmin) {
+ immRectf(pos_id, sa1->totrct.xmin, sa1->totrct.ymin, combined.xmin, sa1->totrct.ymax);
+ }
+ if (sa2->totrct.xmin < combined.xmin) {
+ immRectf(pos_id, sa2->totrct.xmin, sa2->totrct.ymin, combined.xmin, sa2->totrct.ymax);
+ }
+ if (sa1->totrct.xmax > combined.xmax) {
+ immRectf(pos_id, combined.xmax, sa1->totrct.ymin, sa1->totrct.xmax, sa1->totrct.ymax);
+ }
+ if (sa2->totrct.xmax > combined.xmax) {
+ immRectf(pos_id, combined.xmax, sa2->totrct.ymin, sa2->totrct.xmax, sa2->totrct.ymax);
+ }
+ }
+ else {
+ if (sa1->totrct.ymin < combined.ymin) {
+ immRectf(pos_id, sa1->totrct.xmin, combined.ymin, sa1->totrct.xmax, sa1->totrct.ymin);
+ }
+ if (sa2->totrct.ymin < combined.ymin) {
+ immRectf(pos_id, sa2->totrct.xmin, combined.ymin, sa2->totrct.xmax, sa2->totrct.ymin);
+ }
+ if (sa1->totrct.ymax > combined.ymax) {
+ immRectf(pos_id, sa1->totrct.xmin, sa1->totrct.ymax, sa1->totrct.xmax, combined.ymax);
+ }
+ if (sa2->totrct.ymax > combined.ymax) {
+ immRectf(pos_id, sa2->totrct.xmin, sa2->totrct.ymax, sa2->totrct.xmax, combined.ymax);
+ }
+ }
}
immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
+
+ /* Outline the combined area. */
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&combined, false, 7 * U.pixelsize, (float[4]){1.0f, 1.0f, 1.0f, 0.8f});
}
void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac)
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 7ad8eada3b9..8e51772d801 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -284,42 +284,37 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
/* used with join operator */
int area_getorientation(ScrArea *area, ScrArea *sb)
{
- if (area == NULL || sb == NULL) {
+ if (area == NULL || sb == NULL || area == sb) {
return -1;
}
- ScrVert *saBL = area->v1;
- ScrVert *saTL = area->v2;
- ScrVert *saTR = area->v3;
- ScrVert *saBR = area->v4;
+ vec2s saBL = area->v1->vec;
+ vec2s saTL = area->v2->vec;
+ vec2s saTR = area->v3->vec;
+ vec2s saBR = area->v4->vec;
- ScrVert *sbBL = sb->v1;
- ScrVert *sbTL = sb->v2;
- ScrVert *sbTR = sb->v3;
- ScrVert *sbBR = sb->v4;
+ vec2s sbBL = sb->v1->vec;
+ vec2s sbTL = sb->v2->vec;
+ vec2s sbTR = sb->v3->vec;
+ vec2s sbBR = sb->v4->vec;
- if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */
- if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) &&
- (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) {
+ if (saBL.x == sbBR.x && saTL.x == sbTR.x) { /* area to right of sb = W */
+ if ((MIN2(saTL.y, sbTR.y) - MAX2(saBL.y, sbBR.y)) > AREAJOINTOLERANCEY) {
return 0;
}
}
- else if (saTL->vec.y == sbBL->vec.y &&
- saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */
- if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) &&
- (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) {
+ else if (saTL.y == sbBL.y && saTR.y == sbBR.y) { /* area to bottom of sb = N */
+ if ((MIN2(saTR.x, sbBR.x) - MAX2(saTL.x, sbBL.x)) > AREAJOINTOLERANCEX) {
return 1;
}
}
- else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */
- if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) &&
- (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) {
+ else if (saTR.x == sbTL.x && saBR.x == sbBL.x) { /* area to left of sb = E */
+ if ((MIN2(saTR.y, sbTL.y) - MAX2(saBR.y, sbBL.y)) > AREAJOINTOLERANCEY) {
return 2;
}
}
- else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/
- if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) &&
- (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) {
+ else if (saBL.y == sbTL.y && saBR.y == sbTR.y) { /* area on top of sb = S */
+ if ((MIN2(saBR.x, sbTR.x) - MAX2(saBL.x, sbTL.x)) > AREAJOINTOLERANCEX) {
return 3;
}
}
@@ -327,6 +322,35 @@ int area_getorientation(ScrArea *area, ScrArea *sb)
return -1;
}
+/* Get alignment offset of adjacent areas. 'dir' value is like area_getorientation(). */
+void area_getoffsets(ScrArea *area, ScrArea *sb, const int dir, int *offset1, int *offset2)
+{
+ if (area == NULL || sb == NULL) {
+ *offset1 = INT_MAX;
+ *offset2 = INT_MAX;
+ }
+ else if (dir == 0) { /* West: sa on right and sb to the left. */
+ *offset1 = sb->v3->vec.y - area->v2->vec.y;
+ *offset2 = sb->v4->vec.y - area->v1->vec.y;
+ }
+ else if (dir == 1) { /* North: sa below and sb above. */
+ *offset1 = area->v2->vec.x - sb->v1->vec.x;
+ *offset2 = area->v3->vec.x - sb->v4->vec.x;
+ }
+ else if (dir == 2) { /* East: sa on left and sb to the right. */
+ *offset1 = sb->v2->vec.y - area->v3->vec.y;
+ *offset2 = sb->v1->vec.y - area->v4->vec.y;
+ }
+ else if (dir == 3) { /* South: sa above and sb below. */
+ *offset1 = area->v1->vec.x - sb->v2->vec.x;
+ *offset2 = area->v4->vec.x - sb->v3->vec.x;
+ }
+ else {
+ *offset1 = INT_MAX;
+ *offset2 = INT_MAX;
+ }
+}
+
/* Screen verts with horizontal position equal to from_x are moved to to_x. */
static void screen_verts_halign(const wmWindow *win,
const bScreen *screen,
@@ -390,18 +414,24 @@ static void screen_areas_align(
}
}
-/* Helper function to join 2 areas, it has a return value, 0=failed 1=success
- * used by the split, join operators
- */
-int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
+/* Simple join of two areas without any splitting. Will return false if not possible. */
+static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
int dir = area_getorientation(sa1, sa2);
-
if (dir == -1) {
- return 0;
+ return false;
+ }
+
+ int offset1;
+ int offset2;
+ area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
+
+ int tolerance = ELEM(dir, 0, 2) ? AREAJOINTOLERANCEY : AREAJOINTOLERANCEX;
+ if ((abs(offset1) >= tolerance) || (abs(offset2) >= tolerance)) {
+ return false;
}
- /* Align areas if they are not. Do sanity checking before getting here. */
+ /* Align areas if they are not. */
screen_areas_align(C, screen, sa1, sa2, dir);
if (dir == 0) { /* sa1 to right of sa2 = W */
@@ -434,7 +464,107 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
/* Update preview thumbnail */
BKE_icon_changed(screen->id.icon_id);
- return 1;
+ return true;
+}
+
+/* Slice off and return new area. "Reverse" gives right/bottom, rather than left/top. */
+static ScrArea *screen_area_trim(
+ bContext *C, bScreen *screen, ScrArea **area, int size, int dir, bool reverse)
+{
+ bool vertical = ELEM(dir, 1, 3);
+ if (abs(size) < (vertical ? AREAJOINTOLERANCEX : AREAJOINTOLERANCEY)) {
+ return NULL;
+ }
+
+ /* Measurement with ScrVerts because winx and winy might not be correct at this time. */
+ float fac = abs(size) / (float)(vertical ? ((*area)->v3->vec.x - (*area)->v1->vec.x) :
+ ((*area)->v3->vec.y - (*area)->v1->vec.y));
+ fac = (reverse == vertical) ? 1.0f - fac : fac;
+ ScrArea *newsa = area_split(CTX_wm_window(C), screen, *area, vertical ? 'v' : 'h', fac, 1);
+
+ /* area_split always returns smallest of the two areas, so might have to swap. */
+ if (((fac > 0.5f) == vertical) != reverse) {
+ ScrArea *temp = *area;
+ *area = newsa;
+ newsa = temp;
+ }
+
+ return newsa;
+}
+
+/* Join any two neighboring areas. Might create new areas, kept if over min_remainder. */
+static bool screen_area_join_ex(
+ bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, bool close_all_remainders)
+{
+ int dir = area_getorientation(sa1, sa2);
+ if (dir == -1) {
+ return false;
+ }
+
+ int offset1;
+ int offset2;
+ area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
+
+ /* Split Left/Top into new area if overhanging. */
+ ScrArea *side1 = screen_area_trim(C, screen, (offset1 > 0) ? &sa2 : &sa1, offset1, dir, false);
+
+ /* Split Right/Bottom into new area if overhanging. */
+ ScrArea *side2 = screen_area_trim(C, screen, (offset2 > 0) ? &sa1 : &sa2, offset2, dir, true);
+
+ /* The two areas now line up, so join them. */
+ screen_area_join_aligned(C, screen, sa1, sa2);
+
+ if (close_all_remainders || offset1 < 0 || offset2 > 0) {
+ /* Close both if trimiming sa1. */
+ screen_area_close(C, screen, side1);
+ screen_area_close(C, screen, side2);
+ }
+
+ BKE_icon_changed(screen->id.icon_id);
+ return true;
+}
+
+/* Join any two neighboring areas. Might involve complex changes. */
+int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
+{
+ return screen_area_join_ex(C, screen, sa1, sa2, false);
+}
+
+/* Close a screen area, allowing any neighbor to take its place. */
+bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
+{
+ if (area == NULL) {
+ return false;
+ }
+
+ ScrArea *sa2 = NULL;
+
+ /* Find the most-aligned joinable area. Larger size breaks ties. */
+ int min_alignment = INT_MAX;
+ int max_size = 0;
+ LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) {
+ int dir = area_getorientation(area, ar);
+ if (dir != -1) {
+ int offset1;
+ int offset2;
+ area_getoffsets(area, ar, dir, &offset1, &offset2);
+ int area_alignment = abs(offset1) + abs(offset2);
+ if (area_alignment < min_alignment) {
+ min_alignment = area_alignment;
+ max_size = ar->winx * ar->winy;
+ sa2 = ar;
+ }
+ else if (area_alignment == min_alignment) {
+ int area_size = ar->winx * ar->winy;
+ if (area_size > max_size) {
+ max_size = area_size;
+ sa2 = ar;
+ }
+ }
+ }
+ }
+
+ return screen_area_join_ex(C, screen, sa2, area, true);
}
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index c51ff559786..cda7ba6a4a9 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -34,7 +34,9 @@ struct bContextDataResult;
#define AZONEFADEIN (5.0f * U.widget_unit) /* when #AZone is totally visible */
#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the #AZone */
-#define AREAJOINTOLERANCE (1.0f * U.widget_unit) /* Edges must be close to allow joining. */
+/* Edges must be within these to allow joining. */
+#define AREAJOINTOLERANCEX (AREAMINX * U.dpi_fac)
+#define AREAJOINTOLERANCEY (HEADERY * U.dpi_fac)
/* Expanded interaction influence of area borders. */
#define BORDERPADDING (U.dpi_fac + U.pixelsize)
@@ -58,7 +60,8 @@ ScrArea *area_split(
const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge);
int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
int area_getorientation(ScrArea *area, ScrArea *sb);
-
+void area_getoffsets(ScrArea *area, ScrArea *sb, const int dir, int *offset1, int *offset2);
+bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area);
struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
/* screen_geometry.c */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 5cd4e8c353b..5b371ed2caa 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1387,6 +1387,58 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Area Close Operator
+ *
+ * Close selected area, replace by expanding a neighbor
+ * \{ */
+
+/* operator callback */
+static int area_close_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ ScrArea *area = CTX_wm_area(C);
+ if ((area != NULL) && screen_area_close(C, CTX_wm_screen(C), area)) {
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+static bool area_close_poll(bContext *C)
+{
+ if (!ED_operator_areaactive(C)) {
+ return false;
+ }
+
+ ScrArea *area = CTX_wm_area(C);
+
+ if (ED_area_is_global(area)) {
+ return false;
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+
+ /* Can this area join with ANY other area? */
+ LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) {
+ if (area_getorientation(ar, area) != -1) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void SCREEN_OT_area_close(wmOperatorType *ot)
+{
+ ot->name = "Close Area";
+ ot->description = "Close selected area";
+ ot->idname = "SCREEN_OT_area_close";
+ ot->invoke = area_close_invoke;
+ ot->poll = area_close_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Move Area Edge Operator
* \{ */
@@ -3210,9 +3262,10 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
*/
typedef struct sAreaJoinData {
- ScrArea *sa1; /* first area to be considered */
- ScrArea *sa2; /* second area to be considered */
- void *draw_callback; /* call `ED_screen_draw_join_shape` */
+ ScrArea *sa1; /* Potential source area (kept). */
+ ScrArea *sa2; /* Potential target area (removed or reduced). */
+ int dir; /* Direction of potential join. */
+ void *draw_callback; /* call 'ED_screen_draw_join_highlight' */
} sAreaJoinData;
@@ -3221,8 +3274,8 @@ static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata
const wmOperator *op = userdata;
sAreaJoinData *sd = op->customdata;
- if (sd->sa1 && sd->sa2) {
- ED_screen_draw_join_shape(sd->sa1, sd->sa2);
+ if (sd->sa1 && sd->sa2 && (sd->dir != -1)) {
+ ED_screen_draw_join_highlight(sd->sa1, sd->sa2);
}
}
@@ -3244,6 +3297,7 @@ static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *s
jd->sa1 = sa1;
jd->sa2 = sa2;
+ jd->dir = -1;
op->customdata = jd;
@@ -3256,7 +3310,7 @@ static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *s
static bool area_join_apply(bContext *C, wmOperator *op)
{
sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
- if (!jd) {
+ if (!jd || (jd->dir == -1)) {
return false;
}
@@ -3358,61 +3412,30 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE: {
ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
- int dir = -1;
+ jd->dir = area_getorientation(jd->sa1, jd->sa2);
- if (area) {
- if (jd->sa1 != area) {
- dir = area_getorientation(jd->sa1, area);
- if (dir != -1) {
- jd->sa2 = area;
- }
- else {
- /* we are not bordering on the previously selected area
- * we check if area has common border with the one marked for removal
- * in this case we can swap areas.
- */
- dir = area_getorientation(area, jd->sa2);
- if (dir != -1) {
- jd->sa1 = jd->sa2;
- jd->sa2 = area;
- }
- else {
- jd->sa2 = NULL;
- }
- }
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- }
- else {
- /* we are back in the area previously selected for keeping
- * we swap the areas if possible to allow user to choose */
- if (jd->sa2 != NULL) {
- jd->sa1 = jd->sa2;
- jd->sa2 = area;
- dir = area_getorientation(jd->sa1, jd->sa2);
- if (dir == -1) {
- printf("oops, didn't expect that!\n");
- }
- }
- else {
- dir = area_getorientation(jd->sa1, area);
- if (dir != -1) {
- jd->sa2 = area;
- }
- }
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- }
+ if (area == jd->sa1) {
+ /* Hovering current source, so change direction. */
+ jd->sa1 = jd->sa2;
+ jd->sa2 = area;
+ jd->dir = area_getorientation(jd->sa1, jd->sa2);
+ }
+ else if (area != jd->sa2) {
+ jd->dir = -1;
}
- if (dir == 1) {
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ if (jd->dir == 1) {
WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
- else if (dir == 3) {
+ else if (jd->dir == 3) {
WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
- else if (dir == 2) {
+ else if (jd->dir == 2) {
WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
- else if (dir == 0) {
+ else if (jd->dir == 0) {
WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
else {
@@ -3423,6 +3446,10 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
+ if (jd->dir == -1) {
+ area_join_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
ED_area_tag_redraw(jd->sa1);
ED_area_tag_redraw(jd->sa2);
@@ -4069,6 +4096,69 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
/** \name Region Context Menu Operator (Header/Footer/Navbar)
* \{ */
+static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
+{
+ if (ED_area_is_global(area)) {
+ return;
+ }
+
+ PointerRNA ptr;
+
+ /* Mouse position as if in middle of area. */
+ const int loc[2] = {BLI_rcti_cent_x(&area->totrct), BLI_rcti_cent_y(&area->totrct)};
+
+ /* Vertical Split */
+ uiItemFullO(layout,
+ "SCREEN_OT_area_split",
+ IFACE_("Vertical Split"),
+ ICON_NONE,
+ NULL,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &ptr);
+
+ RNA_int_set_array(&ptr, "cursor", loc);
+ RNA_enum_set(&ptr, "direction", 'v');
+
+ /* Horizontal Split */
+ uiItemFullO(layout,
+ "SCREEN_OT_area_split",
+ IFACE_("Horizontal Split"),
+ ICON_NONE,
+ NULL,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &ptr);
+
+ RNA_int_set_array(&ptr, "cursor", &loc[0]);
+ RNA_enum_set(&ptr, "direction", 'h');
+
+ uiItemS(layout);
+
+ if (area->spacetype != SPACE_FILE) {
+ uiItemO(layout,
+ area->full ? IFACE_("Restore Areas") : IFACE_("Maximize Area"),
+ ICON_NONE,
+ "SCREEN_OT_screen_full_area");
+
+ if (!area->full) {
+ uiItemFullO(layout,
+ "SCREEN_OT_screen_full_area",
+ IFACE_("Full Screen Area"),
+ ICON_NONE,
+ NULL,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &ptr);
+ RNA_boolean_set(&ptr, "use_hide_panels", true);
+ }
+ }
+
+ uiItemO(layout, NULL, ICON_NONE, "SCREEN_OT_area_dupli");
+ uiItemS(layout);
+ uiItemO(layout, NULL, ICON_NONE, "SCREEN_OT_area_close");
+}
+
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
ScrArea *area = CTX_wm_area(C);
@@ -4102,17 +4192,9 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
uiItemS(layout);
-
uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
- }
-
- /* File browser should be fullscreen all the time, top-bar should
- * never be. But other regions can be maximized/restored. */
- if (!ELEM(area->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
uiItemS(layout);
-
- const char *but_str = area->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
- uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
+ screen_area_menu_items(area, layout);
}
}
@@ -4134,14 +4216,8 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
- /* File browser should be fullscreen all the time, top-bar should
- * never be. But other regions can be maximized/restored... */
- if (!ELEM(area->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
- uiItemS(layout);
-
- const char *but_str = area->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
- uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
- }
+ uiItemS(layout);
+ screen_area_menu_items(area, layout);
}
void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
@@ -5461,6 +5537,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_area_move);
WM_operatortype_append(SCREEN_OT_area_split);
WM_operatortype_append(SCREEN_OT_area_join);
+ WM_operatortype_append(SCREEN_OT_area_close);
WM_operatortype_append(SCREEN_OT_area_options);
WM_operatortype_append(SCREEN_OT_area_dupli);
WM_operatortype_append(SCREEN_OT_area_swap);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 3df63d423e2..6df96b1e30f 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -199,10 +199,9 @@ static bool screenshot_draw_check_prop(PointerRNA *UNUSED(ptr),
return !(STREQ(prop_id, "filepath"));
}
-static void screenshot_draw(bContext *C, wmOperator *op)
+static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
ScreenshotData *scd = op->customdata;
uiLayoutSetPropSep(layout, true);
@@ -214,9 +213,8 @@ static void screenshot_draw(bContext *C, wmOperator *op)
uiTemplateImageSettings(layout, &ptr, false);
/* main draw call */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, screenshot_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, screenshot_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
}
static bool screenshot_poll(bContext *C)
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 83dd5098a30..6053253790a 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1479,18 +1479,16 @@ static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr),
return !(STR_ELEM(prop_id, "filepath", "directory", "filename"));
}
-static void image_open_draw(bContext *C, wmOperator *op)
+static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
ImageOpenData *iod = op->customdata;
ImageFormatData *imf = &iod->im_format;
- PointerRNA imf_ptr, ptr;
+ PointerRNA imf_ptr;
/* main draw call */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
@@ -2001,12 +1999,11 @@ static bool image_save_as_draw_check_prop(PointerRNA *ptr,
((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy")));
}
-static void image_save_as_draw(bContext *C, wmOperator *op)
+static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
ImageSaveData *isd = op->customdata;
- PointerRNA imf_ptr, ptr;
+ PointerRNA imf_ptr;
const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
/* image template */
@@ -2014,9 +2011,8 @@ static void image_save_as_draw(bContext *C, wmOperator *op)
uiTemplateImageSettings(layout, &imf_ptr, false);
/* main draw call */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* multiview template */
if (is_multiview) {
@@ -2614,38 +2610,34 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 300);
}
-static void image_new_draw(bContext *C, wmOperator *op)
+static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *col;
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
#if 0
Scene *scene = CTX_data_scene(C);
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
#endif
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
/* copy of WM_operator_props_dialog_popup() layout */
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
col = uiLayoutColumn(layout, false);
- uiItemR(col, &ptr, "name", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "width", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "height", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "color", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "alpha", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "generated_type", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "float", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "tiled", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "name", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "width", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "height", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "color", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "generated_type", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "float", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "tiled", 0, NULL, ICON_NONE);
#if 0
if (is_multiview) {
uiItemL(col[0], "", ICON_NONE);
- uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
+ uiItemR(col[1], op->ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
}
#endif
}
@@ -3991,26 +3983,22 @@ static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev
return WM_operator_props_dialog_popup(C, op, 300);
}
-static void tile_add_draw(bContext *C, wmOperator *op)
+static void tile_add_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *col;
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
col = uiLayoutColumn(layout, false);
- uiItemR(col, &ptr, "number", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "count", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "label", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "fill", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "number", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "count", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "label", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "fill", 0, NULL, ICON_NONE);
- if (RNA_boolean_get(&ptr, "fill")) {
- draw_fill_tile(&ptr, layout);
+ if (RNA_boolean_get(op->ptr, "fill")) {
+ draw_fill_tile(op->ptr, layout);
}
}
@@ -4128,13 +4116,9 @@ static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 300);
}
-static void tile_fill_draw(bContext *C, wmOperator *op)
+static void tile_fill_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- draw_fill_tile(&ptr, op->layout);
+ draw_fill_tile(op->ptr, op->layout);
}
void IMAGE_OT_tile_fill(wmOperatorType *ot)
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index ffac5c982d6..0bdfceb36b6 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -697,7 +697,8 @@ void ED_info_draw_stats(
UI_FontThemeColor(font_id, TH_TEXT_HI);
BLF_enable(font_id, BLF_SHADOW);
- BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ const float shadow_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ BLF_shadow(font_id, 5, shadow_color);
BLF_shadow_offset(font_id, 1, -1);
/* Translated labels for each stat row. */
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index dfc0abee704..e56bb44b1e6 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -255,11 +255,10 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP
struct wmMsgBus *mbus = params->message_bus;
ARegion *region = params->region;
- wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
- .owner = region,
- .user_data = region,
- .notify = ED_region_do_msg_notify_tag_redraw,
- };
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {NULL};
+ msg_sub_value_region_tag_redraw.owner = region;
+ msg_sub_value_region_tag_redraw.user_data = region;
+ msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 0b0c43d3417..c4fd0dd5d73 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -729,18 +729,16 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-static void sequencer_add_draw(bContext *C, wmOperator *op)
+static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
SequencerAddData *sad = op->customdata;
ImageFormatData *imf = &sad->im_format;
- PointerRNA imf_ptr, ptr;
+ PointerRNA imf_ptr;
/* Main draw call. */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, sequencer_add_draw_check_fn, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, sequencer_add_draw_check_fn, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* Image template. */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 5d616969a4f..7279fdd2da2 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1485,26 +1485,22 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
return sequencer_split_exec(C, op);
}
-static void sequencer_split_ui(bContext *C, wmOperator *op)
+static void sequencer_split_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
uiLayout *row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "frame", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "side", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "frame", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "side", 0, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, &ptr, "use_cursor_position", 0, NULL, ICON_NONE);
- if (RNA_boolean_get(&ptr, "use_cursor_position")) {
- uiItemR(layout, &ptr, "channel", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_cursor_position", 0, NULL, ICON_NONE);
+ if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
+ uiItemR(layout, op->ptr, "channel", 0, NULL, ICON_NONE);
}
}
@@ -2278,43 +2274,45 @@ void SEQUENCER_OT_swap(wmOperatorType *ot)
static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
{
- int retval = OPERATOR_CANCELLED;
Scene *scene = CTX_data_scene(C);
Sequence *active_seq = SEQ_select_active_get(scene);
StripElem *se = NULL;
- if (active_seq == NULL) {
+ if (active_seq == NULL || active_seq->strip == NULL) {
return OPERATOR_CANCELLED;
}
- if (active_seq->strip) {
- switch (active_seq->type) {
- case SEQ_TYPE_IMAGE:
- se = SEQ_render_give_stripelem(active_seq, scene->r.cfra);
- break;
- case SEQ_TYPE_MOVIE:
- se = active_seq->strip->stripdata;
- break;
- case SEQ_TYPE_SCENE:
- case SEQ_TYPE_META:
- case SEQ_TYPE_SOUND_RAM:
- case SEQ_TYPE_SOUND_HD:
- default:
- break;
- }
+ switch (active_seq->type) {
+ case SEQ_TYPE_IMAGE:
+ se = SEQ_render_give_stripelem(active_seq, scene->r.cfra);
+ break;
+ case SEQ_TYPE_MOVIE:
+ se = active_seq->strip->stripdata;
+ break;
+ default:
+ return OPERATOR_CANCELLED;
}
- if (se) {
- /* Prevent setting the render size if sequence values aren't initialized. */
- if ((se->orig_width > 0) && (se->orig_height > 0)) {
- scene->r.xsch = se->orig_width;
- scene->r.ysch = se->orig_height;
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
- retval = OPERATOR_FINISHED;
- }
+ if (se == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Prevent setting the render size if sequence values aren't initialized. */
+ if (se->orig_width <= 0 || se->orig_height <= 0) {
+ return OPERATOR_CANCELLED;
}
- return retval;
+ scene->r.xsch = se->orig_width;
+ scene->r.ysch = se->orig_height;
+
+ active_seq->strip->transform->scale_x = active_seq->strip->transform->scale_y = 1.0f;
+ active_seq->strip->transform->xofs = active_seq->strip->transform->yofs = 0.0f;
+
+ SEQ_relations_invalidate_cache_preprocessed(scene, active_seq);
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ return OPERATOR_FINISHED;
}
void SEQUENCER_OT_rendersize(wmOperatorType *ot)
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 190f50ed443..26f89a0700e 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -256,7 +256,7 @@ static std::unique_ptr<DataSource> get_data_source(const bContext *C)
return {};
}
Object *object_orig = (Object *)used_id;
- if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD)) {
+ if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD, OB_VOLUME)) {
return {};
}
Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 520d29ce306..405f0cd9455 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -78,24 +78,25 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
{
std::lock_guard lock{mutex_};
- bke::ReadAttributePtr attribute_ptr = component_->attribute_try_get_for_read(column_id.name);
- if (!attribute_ptr) {
+ bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
+ if (!attribute) {
return {};
}
- const bke::ReadAttribute *attribute = scope_.add(std::move(attribute_ptr), __func__);
- if (attribute->domain() != domain_) {
+ const fn::GVArray *varray = scope_.add(std::move(attribute.varray), __func__);
+ if (attribute.domain != domain_) {
return {};
}
- int domain_size = attribute->size();
- switch (attribute->custom_data_type()) {
+ int domain_size = varray->size();
+ const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type());
+ switch (type) {
case CD_PROP_FLOAT:
if (column_id.index != -1) {
return {};
}
return column_values_from_function(
- column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
float value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value;
});
case CD_PROP_INT32:
@@ -103,9 +104,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
return column_values_from_function(
- column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
int value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_int = value;
});
case CD_PROP_BOOL:
@@ -113,9 +114,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
return column_values_from_function(
- column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
bool value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_bool = value;
});
case CD_PROP_FLOAT2: {
@@ -125,11 +126,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 2> suffixes = {" X", " Y"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
- name,
- domain_size,
- [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
float2 value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
@@ -140,11 +139,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 3> suffixes = {" X", " Y", " Z"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
- name,
- domain_size,
- [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
float3 value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
@@ -155,11 +152,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 4> suffixes = {" R", " G", " B", " A"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
- name,
- domain_size,
- [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
Color4f value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 5f3d71cc190..358373ea4d1 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -5065,7 +5065,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = false,
+ .edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
mval_fl,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index e202276831c..3134553c159 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -338,7 +338,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_CAGE,
},
mval_fl,
NULL,
@@ -352,7 +352,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_CAGE,
},
ray_start,
ray_normal,
@@ -1124,12 +1124,13 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
const wmGizmoType *gzt_snap;
gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+
RNA_enum_set(gizmo->ptr,
"snap_elements_force",
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
/* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
-
+ ED_gizmotypes_snap_3d_flag_set(gizmo, ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE);
WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index 7347e528edc..00e30f8afae 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -323,7 +323,7 @@ static bool idp_poject_surface_normal(SnapObjectContext *snap_context,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
},
mval_fl,
NULL,
@@ -941,7 +941,7 @@ static void view3d_interactive_add_calc_plane(bContext *C,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
},
mval_fl,
NULL,
@@ -2061,7 +2061,7 @@ static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
GPU_matrix_projection_set(rv3d->winmat);
GPU_matrix_set(rv3d->viewmat);
- const float scale_mod = U.gizmo_size * 2 * U.dpi_fac;
+ const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize;
float final_scale = (scale_mod * pixel_size);
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index cbd65e3175d..ab4cf0c2135 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -407,7 +407,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
},
ray_start,
ray_normal,
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index f2d5800abb7..090b8b83dcc 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -88,12 +88,11 @@ typedef enum {
CTX_TEXTURE_SPACE = (1 << 9),
CTX_NO_PET = (1 << 10),
- CTX_NO_MIRROR = (1 << 11),
- CTX_AUTOCONFIRM = (1 << 12),
+ CTX_AUTOCONFIRM = (1 << 11),
/** When transforming object's, adjust the object data so it stays in the same place. */
- CTX_OBMODE_XFORM_OBDATA = (1 << 13),
+ CTX_OBMODE_XFORM_OBDATA = (1 << 12),
/** Transform object parents without moving their children. */
- CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 14),
+ CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 13),
} eTContext;
/** #TransInfo.flag */
@@ -105,51 +104,50 @@ typedef enum {
/** restrictions flags */
T_NO_CONSTRAINT = 1 << 2,
T_NULL_ONE = 1 << 3,
- T_NO_ZERO = 1 << 4,
- T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE | T_NO_ZERO,
+ T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE,
- T_PROP_EDIT = 1 << 5,
- T_PROP_CONNECTED = 1 << 6,
- T_PROP_PROJECTED = 1 << 7,
+ T_PROP_EDIT = 1 << 4,
+ T_PROP_CONNECTED = 1 << 5,
+ T_PROP_PROJECTED = 1 << 6,
T_PROP_EDIT_ALL = T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED,
- T_V3D_ALIGN = 1 << 8,
+ T_V3D_ALIGN = 1 << 7,
/** For 2D views such as UV or f-curve. */
- T_2D_EDIT = 1 << 9,
- T_CLIP_UV = 1 << 10,
+ T_2D_EDIT = 1 << 8,
+ T_CLIP_UV = 1 << 9,
/** Auto-IK is on. */
- T_AUTOIK = 1 << 11,
+ T_AUTOIK = 1 << 10,
/** Don't use mirror even if the data-block option is set. */
- T_NO_MIRROR = 1 << 12,
+ T_NO_MIRROR = 1 << 11,
/** To indicate that the value set in the `value` parameter is the final
* value of the transformation, modified only by the constrain. */
- T_INPUT_IS_VALUES_FINAL = 1 << 13,
+ T_INPUT_IS_VALUES_FINAL = 1 << 12,
/** To specify if we save back settings at the end. */
- T_MODAL = 1 << 14,
+ T_MODAL = 1 << 13,
/** No re-topology (projection). */
- T_NO_PROJECT = 1 << 15,
+ T_NO_PROJECT = 1 << 14,
- T_RELEASE_CONFIRM = 1 << 16,
+ T_RELEASE_CONFIRM = 1 << 15,
/** Alternative transformation. used to add offset to tracking markers. */
- T_ALT_TRANSFORM = 1 << 17,
+ T_ALT_TRANSFORM = 1 << 16,
/** #TransInfo.center has been set, don't change it. */
- T_OVERRIDE_CENTER = 1 << 18,
+ T_OVERRIDE_CENTER = 1 << 17,
- T_MODAL_CURSOR_SET = 1 << 19,
+ T_MODAL_CURSOR_SET = 1 << 18,
- T_CLNOR_REBUILD = 1 << 20,
+ T_CLNOR_REBUILD = 1 << 19,
/** Merges unselected into selected after transforming (runs after transforming). */
- T_AUTOMERGE = 1 << 21,
+ T_AUTOMERGE = 1 << 20,
/** Runs auto-merge & splits. */
- T_AUTOSPLIT = 1 << 22,
+ T_AUTOSPLIT = 1 << 21,
} eTFlag;
/** #TransInfo.modifiers */
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index c021c084a23..98db27c83f7 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -1122,8 +1122,7 @@ static void init_TransDataContainers(TransInfo *t,
for (int i = 0; i < objects_len; i++) {
TransDataContainer *tc = &t->data_container[i];
- if (((t->flag & T_NO_MIRROR) == 0) && ((t->options & CTX_NO_MIRROR) == 0) &&
- (objects[i]->type == OB_MESH)) {
+ if (!(t->flag & T_NO_MIRROR) && (objects[i]->type == OB_MESH)) {
tc->use_mirror_axis_x = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_X) != 0;
tc->use_mirror_axis_y = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_Y) != 0;
tc->use_mirror_axis_z = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_Z) != 0;
@@ -1472,91 +1471,89 @@ void createTransData(bContext *C, TransInfo *t)
/** \name Transform Data Recalc/Flush
* \{ */
-void clipMirrorModifier(TransInfo *t)
+void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Object *ob = tc->obedit;
- ModifierData *md = ob->modifiers.first;
- float tolerance[3] = {0.0f, 0.0f, 0.0f};
- int axis = 0;
-
- for (; md; md = md->next) {
- if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
-
- if (mmd->flag & MOD_MIR_CLIPPING) {
- axis = 0;
- if (mmd->flag & MOD_MIR_AXIS_X) {
- axis |= 1;
- tolerance[0] = mmd->tolerance;
- }
- if (mmd->flag & MOD_MIR_AXIS_Y) {
- axis |= 2;
- tolerance[1] = mmd->tolerance;
- }
- if (mmd->flag & MOD_MIR_AXIS_Z) {
- axis |= 4;
- tolerance[2] = mmd->tolerance;
- }
- if (axis) {
- float mtx[4][4], imtx[4][4];
- int i;
+ Object *ob = tc->obedit;
+ ModifierData *md = ob->modifiers.first;
+ float tolerance[3] = {0.0f, 0.0f, 0.0f};
+ int axis = 0;
+
+ for (; md; md = md->next) {
+ if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ axis = 0;
+ if (mmd->flag & MOD_MIR_AXIS_X) {
+ axis |= 1;
+ tolerance[0] = mmd->tolerance;
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Y) {
+ axis |= 2;
+ tolerance[1] = mmd->tolerance;
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Z) {
+ axis |= 4;
+ tolerance[2] = mmd->tolerance;
+ }
+ if (axis) {
+ float mtx[4][4], imtx[4][4];
+ int i;
- if (mmd->mirror_ob) {
- float obinv[4][4];
+ if (mmd->mirror_ob) {
+ float obinv[4][4];
- invert_m4_m4(obinv, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obinv, ob->obmat);
- invert_m4_m4(imtx, mtx);
- }
+ invert_m4_m4(obinv, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, obinv, ob->obmat);
+ invert_m4_m4(imtx, mtx);
+ }
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- int clip;
- float loc[3], iloc[3];
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ int clip;
+ float loc[3], iloc[3];
- if (td->loc == NULL) {
- break;
- }
+ if (td->loc == NULL) {
+ break;
+ }
- if (td->flag & TD_SKIP) {
- continue;
- }
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
- copy_v3_v3(loc, td->loc);
- copy_v3_v3(iloc, td->iloc);
+ copy_v3_v3(loc, td->loc);
+ copy_v3_v3(iloc, td->iloc);
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, loc);
- mul_m4_v3(mtx, iloc);
- }
+ if (mmd->mirror_ob) {
+ mul_m4_v3(mtx, loc);
+ mul_m4_v3(mtx, iloc);
+ }
- clip = 0;
- if (axis & 1) {
- if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) {
- loc[0] = 0.0f;
- clip = 1;
- }
+ clip = 0;
+ if (axis & 1) {
+ if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) {
+ loc[0] = 0.0f;
+ clip = 1;
}
+ }
- if (axis & 2) {
- if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) {
- loc[1] = 0.0f;
- clip = 1;
- }
+ if (axis & 2) {
+ if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) {
+ loc[1] = 0.0f;
+ clip = 1;
}
- if (axis & 4) {
- if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) {
- loc[2] = 0.0f;
- clip = 1;
- }
+ }
+ if (axis & 4) {
+ if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) {
+ loc[2] = 0.0f;
+ clip = 1;
}
- if (clip) {
- if (mmd->mirror_ob) {
- mul_m4_v3(imtx, loc);
- }
- copy_v3_v3(td->loc, loc);
+ }
+ if (clip) {
+ if (mmd->mirror_ob) {
+ mul_m4_v3(imtx, loc);
}
+ copy_v3_v3(td->loc, loc);
}
}
}
@@ -1644,38 +1641,6 @@ void animrecord_check_state(TransInfo *t, struct Object *ob)
}
}
-static void recalcData_cursor_image(TransInfo *t)
-{
- TransDataContainer *tc = t->data_container;
- TransData *td = tc->data;
- float aspect_inv[2];
-
- aspect_inv[0] = 1.0f / t->aspect[0];
- aspect_inv[1] = 1.0f / t->aspect[1];
-
- td->loc[0] = td->loc[0] * aspect_inv[0];
- td->loc[1] = td->loc[1] * aspect_inv[1];
-
- DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-static void recalcData_cursor(TransInfo *t)
-{
- DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-static void recalcData_obedit(TransInfo *t)
-{
- if (t->state != TRANS_CANCEL) {
- applyProject(t);
- }
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len) {
- DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
- }
- }
-}
-
/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
@@ -1742,7 +1707,7 @@ void recalcData(TransInfo *t)
recalcData_tracking(t);
break;
case TC_MBALL_VERTS:
- recalcData_obedit(t);
+ recalcData_mball(t);
break;
case TC_LATTICE_VERTS:
recalcData_lattice(t);
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 36a51d57f64..11550ec8803 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -45,7 +45,7 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
void clipUVData(TransInfo *t);
/* transform_convert_mesh.c */
-void mesh_customdatacorrect_init(TransInfo *t);
+void transform_convert_mesh_customdatacorrect_init(TransInfo *t);
/* transform_convert_sequencer.c */
int transform_convert_sequencer_get_snap_bound(TransInfo *t);
@@ -62,7 +62,7 @@ void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic);
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
bool FrameOnMouseSide(char side, float frame, float cframe);
-void clipMirrorModifier(TransInfo *t);
+void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
void animrecord_check_state(TransInfo *t, struct Object *ob);
/* transform_convert_action.c */
@@ -84,6 +84,8 @@ void special_aftertrans_update__pose(bContext *C, TransInfo *t);
/* transform_convert_cursor.c */
void createTransCursor_image(TransInfo *t);
void createTransCursor_view3d(TransInfo *t);
+void recalcData_cursor_image(TransInfo *t);
+void recalcData_cursor(TransInfo *t);
/* transform_convert_curve.c */
void createTransCurveVerts(TransInfo *t);
@@ -109,6 +111,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t);
/* transform_convert_mball.c */
void createTransMBallVerts(TransInfo *t);
+void recalcData_mball(TransInfo *t);
/* transform_convert_mesh.c */
struct TransIslandData {
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
index 67d85f9610b..1f3eff31205 100644
--- a/source/blender/editors/transform/transform_convert_cursor.c
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -134,3 +134,29 @@ void createTransCursor_view3d(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Cursor
+ * \{ */
+
+void recalcData_cursor_image(TransInfo *t)
+{
+ TransDataContainer *tc = t->data_container;
+ TransData *td = tc->data;
+ float aspect_inv[2];
+
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
+
+ td->loc[0] = td->loc[0] * aspect_inv[0];
+ td->loc[1] = td->loc[1] * aspect_inv[1];
+
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void recalcData_cursor(TransInfo *t)
+{
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 3ff83e00f43..f294bbbf0aa 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -441,7 +441,6 @@ void createTransCurveVerts(TransInfo *t)
void recalcData_curve(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- clipMirrorModifier(t);
applyProject(t);
}
@@ -460,7 +459,10 @@ void recalcData_curve(TransInfo *t)
}
}
else {
- /* Normal updating */
+ /* Apply clipping after so we never project past the clip plane T25423. */
+ transform_convert_clip_mirror_modifier_apply(tc);
+
+ /* Normal updating. */
BKE_curve_dimension_update(cu);
}
}
diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c
index 6f5c0318054..e47cf4edc4a 100644
--- a/source/blender/editors/transform/transform_convert_mball.c
+++ b/source/blender/editors/transform/transform_convert_mball.c
@@ -30,6 +30,8 @@
#include "BKE_context.h"
#include "transform.h"
+#include "transform_snap.h"
+
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
@@ -128,3 +130,21 @@ void createTransMBallVerts(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Meta Ball
+ * \{ */
+
+void recalcData_mball(TransInfo *t)
+{
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 93c36645873..872f3e1385a 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -727,10 +727,10 @@ void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_cr
/** \name Edit Mesh Verts Transform Creation
* \{ */
-static void transdata_center_get(const struct TransIslandData *island_data,
- const int island_index,
- const float iloc[3],
- float r_center[3])
+static void tc_mesh_transdata_center_copy(const struct TransIslandData *island_data,
+ const int island_index,
+ const float iloc[3],
+ float r_center[3])
{
if (island_data->center && island_index != -1) {
copy_v3_v3(r_center, island_data->center[island_index]);
@@ -769,7 +769,7 @@ static void VertsToTransData(TransInfo *t,
no = eve->no;
}
- transdata_center_get(island_data, island_index, td->iloc, td->center);
+ tc_mesh_transdata_center_copy(island_data, island_index, td->iloc, td->center);
if ((island_index != -1) && island_data->axismtx) {
copy_m3_m3(td->axismtx, island_data->axismtx[island_index]);
@@ -959,7 +959,8 @@ void createTransEditVerts(TransInfo *t)
copy_v3_v3(td_mirror->iloc, eve->co);
td_mirror->flag = mirror_data.vert_map[a].flag;
td_mirror->loc_src = v_src->co;
- transdata_center_get(&island_data, island_index, td_mirror->iloc, td_mirror->center);
+ tc_mesh_transdata_center_copy(
+ &island_data, island_index, td_mirror->iloc, td_mirror->center);
td_mirror++;
}
@@ -1065,9 +1066,9 @@ struct TransCustomDataLayer {
bool use_merge_group;
};
-static void mesh_customdatacorrect_free_cb(struct TransInfo *UNUSED(t),
- struct TransDataContainer *UNUSED(tc),
- struct TransCustomData *custom_data)
+static void tc_mesh_customdatacorrect_free_fn(struct TransInfo *UNUSED(t),
+ struct TransDataContainer *UNUSED(tc),
+ struct TransCustomData *custom_data)
{
struct TransCustomDataLayer *tcld = custom_data->data;
bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
@@ -1157,7 +1158,7 @@ static void mesh_customdatacorrect_face_substitute_set(struct TransCustomDataLay
}
}
-static BMFace *mesh_customdatacorrect_face_substitute_get(BMFace *f_copy)
+static BMFace *tc_mesh_customdatacorrect_face_substitute_get(BMFace *f_copy)
{
BLI_assert(BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX);
return *((BMFace **)&f_copy->no[0]);
@@ -1165,9 +1166,9 @@ static BMFace *mesh_customdatacorrect_face_substitute_get(BMFace *f_copy)
#endif /* USE_FACE_SUBSTITUTE */
-static void mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld,
- struct TransDataBasic *td,
- const int index)
+static void tc_mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld,
+ struct TransDataBasic *td,
+ const int index)
{
BMesh *bm = tcld->bm;
BMVert *v = td->extra;
@@ -1226,8 +1227,8 @@ static void mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld,
}
}
-static void mesh_customdatacorrect_init_container_generic(TransDataContainer *UNUSED(tc),
- struct TransCustomDataLayer *tcld)
+static void tc_mesh_customdatacorrect_init_container_generic(TransDataContainer *UNUSED(tc),
+ struct TransCustomDataLayer *tcld)
{
BMesh *bm = tcld->bm;
@@ -1247,8 +1248,8 @@ static void mesh_customdatacorrect_init_container_generic(TransDataContainer *UN
tcld->cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
}
-static void mesh_customdatacorrect_init_container_merge_group(TransDataContainer *tc,
- struct TransCustomDataLayer *tcld)
+static void tc_mesh_customdatacorrect_init_container_merge_group(TransDataContainer *tc,
+ struct TransCustomDataLayer *tcld)
{
BMesh *bm = tcld->bm;
BLI_assert(CustomData_has_math(&bm->ldata));
@@ -1274,13 +1275,13 @@ static void mesh_customdatacorrect_init_container_merge_group(TransDataContainer
tcld->arena, tcld->merge_group.data_len * sizeof(*tcld->merge_group.data));
}
-static void mesh_customdatacorrect_init_container(TransDataContainer *tc,
- const bool use_merge_group)
+static void tc_mesh_customdatacorrect_init_container(TransDataContainer *tc,
+ const bool use_merge_group)
{
if (tc->custom.type.data) {
/* The custom-data correction has been initiated before.
* Free since some modes have different settings. */
- mesh_customdatacorrect_free_cb(NULL, tc, &tc->custom.type);
+ tc_mesh_customdatacorrect_free_fn(NULL, tc, &tc->custom.type);
}
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1305,10 +1306,10 @@ static void mesh_customdatacorrect_init_container(TransDataContainer *tc,
tcld->cd_loop_mdisp_offset = -1;
tcld->use_merge_group = use_merge_group;
- mesh_customdatacorrect_init_container_generic(tc, tcld);
+ tc_mesh_customdatacorrect_init_container_generic(tc, tcld);
if (tcld->use_merge_group) {
- mesh_customdatacorrect_init_container_merge_group(tc, tcld);
+ tc_mesh_customdatacorrect_init_container_merge_group(tc, tcld);
}
{
@@ -1317,20 +1318,20 @@ static void mesh_customdatacorrect_init_container(TransDataContainer *tc,
TransData *tob = tc->data;
for (int j = tc->data_len; j--; tob++, i++) {
- mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)tob, i);
+ tc_mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)tob, i);
}
TransDataMirror *td_mirror = tc->data_mirror;
for (int j = tc->data_mirror_len; j--; td_mirror++, i++) {
- mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)td_mirror, i);
+ tc_mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)td_mirror, i);
}
}
tc->custom.type.data = tcld;
- tc->custom.type.free_cb = mesh_customdatacorrect_free_cb;
+ tc->custom.type.free_cb = tc_mesh_customdatacorrect_free_fn;
}
-void mesh_customdatacorrect_init(TransInfo *t)
+void transform_convert_mesh_customdatacorrect_init(TransInfo *t)
{
bool use_merge_group = false;
if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
@@ -1364,23 +1365,23 @@ void mesh_customdatacorrect_init(TransInfo *t)
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- mesh_customdatacorrect_init_container(tc, use_merge_group);
+ tc_mesh_customdatacorrect_init_container(tc, use_merge_group);
}
}
/**
* If we're sliding the vert, return its original location, if not, the current location is good.
*/
-static const float *trans_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v)
+static const float *tc_mesh_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v)
{
TransDataBasic *td = BLI_ghash_lookup(tcld->merge_group.origverts, v);
return td ? td->iloc : v->co;
}
-static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
- struct TransDataBasic *td,
- struct TransCustomDataMergeGroup *merge_data,
- bool do_loop_mdisps)
+static void tc_mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
+ struct TransDataBasic *td,
+ struct TransCustomDataMergeGroup *merge_data,
+ bool do_loop_mdisps)
{
BMesh *bm = tcld->bm;
BMVert *v = td->extra;
@@ -1413,7 +1414,7 @@ static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
/* In some faces it is not possible to calculate interpolation,
* so we use a substitute. */
if (BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX) {
- f_copy = mesh_customdatacorrect_face_substitute_get(f_copy);
+ f_copy = tc_mesh_customdatacorrect_face_substitute_get(f_copy);
}
#endif
@@ -1426,8 +1427,8 @@ static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
const float eps = 1.0e-8f;
const BMLoop *l_prev = l->prev;
const BMLoop *l_next = l->next;
- const float *co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
- const float *co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ const float *co_prev = tc_mesh_vert_orig_co_get(tcld, l_prev->v);
+ const float *co_next = tc_mesh_vert_orig_co_get(tcld, l_next->v);
bool co_prev_ok;
bool co_next_ok;
@@ -1440,13 +1441,13 @@ static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
((l_prev = l_prev->prev) != l->next))) {
- co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ co_prev = tc_mesh_vert_orig_co_get(tcld, l_prev->v);
project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
}
project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
((l_next = l_next->next) != l->prev))) {
- co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ co_next = tc_mesh_vert_orig_co_get(tcld, l_next->v);
project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
}
@@ -1518,37 +1519,35 @@ static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld,
}
}
-static void mesh_customdatacorrect_apply(TransInfo *t, bool is_final)
+static void tc_mesh_customdatacorrect_apply(TransDataContainer *tc, bool is_final)
{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (!tc->custom.type.data) {
- continue;
- }
- struct TransCustomDataLayer *tcld = tc->custom.type.data;
- const bool use_merge_group = tcld->use_merge_group;
+ if (!tc->custom.type.data) {
+ return;
+ }
+ struct TransCustomDataLayer *tcld = tc->custom.type.data;
+ const bool use_merge_group = tcld->use_merge_group;
- struct TransCustomDataMergeGroup *merge_data = tcld->merge_group.data;
- TransData *tob = tc->data;
- for (int i = tc->data_len; i--; tob++) {
- mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)tob, merge_data, is_final);
+ struct TransCustomDataMergeGroup *merge_data = tcld->merge_group.data;
+ TransData *tob = tc->data;
+ for (int i = tc->data_len; i--; tob++) {
+ tc_mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)tob, merge_data, is_final);
- if (use_merge_group) {
- merge_data++;
- }
+ if (use_merge_group) {
+ merge_data++;
}
+ }
- TransDataMirror *td_mirror = tc->data_mirror;
- for (int i = tc->data_mirror_len; i--; td_mirror++) {
- mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)td_mirror, merge_data, is_final);
+ TransDataMirror *td_mirror = tc->data_mirror;
+ for (int i = tc->data_mirror_len; i--; td_mirror++) {
+ tc_mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)td_mirror, merge_data, is_final);
- if (use_merge_group) {
- merge_data++;
- }
+ if (use_merge_group) {
+ merge_data++;
}
}
}
-static void mesh_customdatacorrect_restore(struct TransInfo *t)
+static void tc_mesh_customdatacorrect_restore(struct TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
struct TransCustomDataLayer *tcld = tc->custom.type.data;
@@ -1583,60 +1582,62 @@ static void mesh_customdatacorrect_restore(struct TransInfo *t)
/** \name Recalc Mesh Data
* \{ */
-static void mesh_apply_to_mirror(TransInfo *t)
+static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc)
{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->use_mirror_axis_any) {
- int i;
- TransData *td;
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
- if (td->flag & TD_MIRROR_EDGE_X) {
- td->loc[0] = 0.0f;
- }
- if (td->flag & TD_MIRROR_EDGE_Y) {
- td->loc[1] = 0.0f;
- }
- if (td->flag & TD_MIRROR_EDGE_Z) {
- td->loc[2] = 0.0f;
- }
- }
- }
-
- TransDataMirror *td_mirror = tc->data_mirror;
- for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
- copy_v3_v3(td_mirror->loc, td_mirror->loc_src);
- if (td_mirror->flag & TD_MIRROR_X) {
- td_mirror->loc[0] *= -1;
+ if (tc->use_mirror_axis_any) {
+ int i;
+ TransData *td;
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
+ if (td->flag & TD_MIRROR_EDGE_X) {
+ td->loc[0] = 0.0f;
}
- if (td_mirror->flag & TD_MIRROR_Y) {
- td_mirror->loc[1] *= -1;
+ if (td->flag & TD_MIRROR_EDGE_Y) {
+ td->loc[1] = 0.0f;
}
- if (td_mirror->flag & TD_MIRROR_Z) {
- td_mirror->loc[2] *= -1;
+ if (td->flag & TD_MIRROR_EDGE_Z) {
+ td->loc[2] = 0.0f;
}
}
}
+
+ TransDataMirror *td_mirror = tc->data_mirror;
+ for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
+ copy_v3_v3(td_mirror->loc, td_mirror->loc_src);
+ if (td_mirror->flag & TD_MIRROR_X) {
+ td_mirror->loc[0] *= -1;
+ }
+ if (td_mirror->flag & TD_MIRROR_Y) {
+ td_mirror->loc[1] *= -1;
+ }
+ if (td_mirror->flag & TD_MIRROR_Z) {
+ td_mirror->loc[2] *= -1;
+ }
+ }
}
}
void recalcData_mesh(TransInfo *t)
{
bool is_canceling = t->state == TRANS_CANCEL;
- /* mirror modifier clipping? */
+ /* Apply corrections. */
if (!is_canceling) {
- /* apply clipping after so we never project past the clip plane T25423. */
applyProject(t);
- clipMirrorModifier(t);
- if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
- mesh_apply_to_mirror(t);
- }
+ bool do_mirror = !(t->flag & T_NO_MIRROR);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ /* Apply clipping after so we never project past the clip plane T25423. */
+ transform_convert_clip_mirror_modifier_apply(tc);
+
+ if (do_mirror) {
+ tc_mesh_transdata_mirror_apply(tc);
+ }
- mesh_customdatacorrect_apply(t, false);
+ tc_mesh_customdatacorrect_apply(tc, false);
+ }
}
else {
- mesh_customdatacorrect_restore(t);
+ tc_mesh_customdatacorrect_restore(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -1660,7 +1661,9 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
if (!is_canceling && ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
/* NOTE(joeedh): Handle multi-res re-projection,
* done on transform completion since it's really slow. */
- mesh_customdatacorrect_apply(t, true);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc_mesh_customdatacorrect_apply(tc, true);
+ }
}
if (use_automerge) {
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index 5dbb1947773..68305c45280 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -47,9 +47,9 @@
/** \name Edit Mesh #CD_MVERT_SKIN Transform Creation
* \{ */
-static float *mesh_skin_transdata_center(const struct TransIslandData *island_data,
- const int island_index,
- BMVert *eve)
+static float *tc_mesh_skin_transdata_center(const struct TransIslandData *island_data,
+ const int island_index,
+ BMVert *eve)
{
if (island_data->center && island_index != -1) {
return island_data->center[island_index];
@@ -57,11 +57,11 @@ static float *mesh_skin_transdata_center(const struct TransIslandData *island_da
return eve->co;
}
-static void mesh_skin_transdata_create(TransDataBasic *td,
- BMEditMesh *em,
- BMVert *eve,
- const struct TransIslandData *island_data,
- const int island_index)
+static void tc_mesh_skin_transdata_create(TransDataBasic *td,
+ BMEditMesh *em,
+ BMVert *eve,
+ const struct TransIslandData *island_data,
+ const int island_index)
{
BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN);
@@ -78,7 +78,7 @@ static void mesh_skin_transdata_create(TransDataBasic *td,
td->flag |= TD_SELECTED;
}
- copy_v3_v3(td->center, mesh_skin_transdata_center(island_data, island_index, eve));
+ copy_v3_v3(td->center, tc_mesh_skin_transdata_center(island_data, island_index, eve));
td->extra = eve;
}
@@ -209,7 +209,7 @@ void createTransMeshSkin(TransInfo *t)
}
if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) {
- mesh_skin_transdata_create(
+ tc_mesh_skin_transdata_create(
(TransDataBasic *)td_mirror, em, eve, &island_data, island_index);
int elem_index = mirror_data.vert_map[a].index;
@@ -221,7 +221,7 @@ void createTransMeshSkin(TransInfo *t)
td_mirror++;
}
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- mesh_skin_transdata_create((TransDataBasic *)td, em, eve, &island_data, island_index);
+ tc_mesh_skin_transdata_create((TransDataBasic *)td, em, eve, &island_data, island_index);
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
createSpaceNormal(td->axismtx, eve->no);
@@ -275,7 +275,7 @@ void createTransMeshSkin(TransInfo *t)
/** \name Recalc Mesh Data
* \{ */
-static void mesh_skin_apply_to_mirror(TransInfo *t)
+static void tc_mesh_skin_apply_to_mirror(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->use_mirror_axis_any) {
@@ -292,8 +292,8 @@ void recalcData_mesh_skin(TransInfo *t)
bool is_canceling = t->state == TRANS_CANCEL;
/* mirror modifier clipping? */
if (!is_canceling) {
- if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
- mesh_skin_apply_to_mirror(t);
+ if (!(t->flag & T_NO_MIRROR)) {
+ tc_mesh_skin_apply_to_mirror(t);
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index c0c4b22da98..c9b6bef5904 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -538,7 +538,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else {
/* Avoid mirroring for unsupported contexts. */
- t->options |= CTX_NO_MIRROR;
+ t->flag |= T_NO_MIRROR;
}
/* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index d14f693da9c..867a6cc4291 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -1263,7 +1263,7 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
if (t->data_type == TC_MESH_VERTS) {
/* Init Custom Data correction.
* Ideally this should be called when creating the TransData. */
- mesh_customdatacorrect_init(t);
+ transform_convert_mesh_customdatacorrect_init(t);
}
/* TODO(germano): Some of these operations change the `t->mode`.
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index ee63bf4be6f..68416c780ef 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -107,7 +107,6 @@ void initCurveShrinkFatten(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
- t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
#endif
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index e67c6c03481..7c496d271ef 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -117,7 +117,6 @@ void initGPOpacity(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
- t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
#endif
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index 95e3d89d2b7..608a49f38b1 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -119,7 +119,6 @@ void initGPShrinkFatten(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
- t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
#endif
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 3019984d70b..857ee37f0ad 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -133,7 +133,6 @@ void initMaskShrinkFatten(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
- t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
#endif
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 9891af8b9a4..f225f1a7c06 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -235,8 +235,5 @@ void initMirror(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_NONE);
t->flag |= T_NULL_ONE;
- if ((t->flag & T_EDIT) == 0) {
- t->flag |= T_NO_ZERO;
- }
}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 4d0bb7fbe9c..fcdc57a98e2 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -176,7 +176,6 @@ void initResize(TransInfo *t)
t->num.val_flag[2] |= NUM_NULL_ONE;
t->num.flag |= NUM_AFFECT_ALL;
if ((t->flag & T_EDIT) == 0) {
- t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
t->num.val_flag[1] |= NUM_NO_ZERO;
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 8beacb844b9..77e57484bef 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -111,7 +111,6 @@ void initSkinResize(TransInfo *t)
t->num.val_flag[2] |= NUM_NULL_ONE;
t->num.flag |= NUM_AFFECT_ALL;
if ((t->flag & T_EDIT) == 0) {
- t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
t->num.val_flag[1] |= NUM_NO_ZERO;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index d0f91802fff..193954fffb6 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -345,7 +345,7 @@ void applyProject(TransInfo *t)
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
.use_occlusion_test = false,
.use_backface_culling = t->tsnap.use_backface_culling,
},
@@ -1167,7 +1167,7 @@ short snapObjectsTransform(
t->settings->snap_mode,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
.use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
.use_backface_culling = t->tsnap.use_backface_culling,
},
@@ -1201,7 +1201,7 @@ bool peelObjectsTransform(TransInfo *t,
t->depsgraph,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
},
mval,
-1.0f,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index e5f6f207e3c..512f912a532 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -44,6 +44,7 @@
#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_geometry_set.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
@@ -145,9 +146,37 @@ struct SnapObjectContext {
/** \name Utilities
* \{ */
-static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em)
+/* Mesh used for snapping.
+ * If NULL the BMesh should be used. */
+static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
- return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH);
+ Mesh *me_eval = ob_eval->data;
+ bool use_hide = false;
+ if (BKE_object_is_in_editmode(ob_eval)) {
+ if (edit_mode_type == SNAP_GEOM_EDIT) {
+ return NULL;
+ }
+
+ BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
+ if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) {
+ if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ return NULL;
+ }
+ me_eval = em_eval->mesh_eval_final;
+ use_hide = true;
+ }
+ else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) {
+ if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ return NULL;
+ }
+ me_eval = em_eval->mesh_eval_cage;
+ use_hide = true;
+ }
+ }
+ if (r_use_hide) {
+ *r_use_hide = use_hide;
+ }
+ return me_eval;
}
/** \} */
@@ -209,30 +238,69 @@ static void snap_object_data_clear(SnapObjectData *sod)
memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type));
}
-static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob)
+static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob_eval)
{
- SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval);
if (sod == NULL) {
if (sctx->cache.data_to_object_map != NULL) {
- ob = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob->data);
+ ob_eval = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob_eval->data);
/* Could be NULl when mixing edit-mode and non edit-mode objects. */
- if (ob != NULL) {
- sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ if (ob_eval != NULL) {
+ sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval);
}
}
}
return sod;
}
-static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
+static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ Mesh *me_eval,
+ bool use_hide)
{
SnapObjectData *sod;
void **sod_p;
bool init = false;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) {
sod = *sod_p;
+ bool is_dirty = false;
if (sod->type != SNAP_MESH) {
+ is_dirty = true;
+ }
+ else if (sod->treedata_mesh.tree && sod->treedata_mesh.cached &&
+ !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) {
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ is_dirty = true;
+ }
+ else if (sod->bvhtree[0] && sod->cached[0] &&
+ !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) {
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ is_dirty = true;
+ }
+ else if (sod->bvhtree[1] && sod->cached[1] &&
+ !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) {
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.looptri_allocated &&
+ sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) {
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.vert_allocated && sod->treedata_mesh.vert != me_eval->mvert) {
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.loop_allocated && sod->treedata_mesh.loop != me_eval->mloop) {
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.edge_allocated && sod->treedata_mesh.edge != me_eval->medge) {
+ is_dirty = true;
+ }
+ else if (sod->poly != me_eval->mpoly) {
+ is_dirty = true;
+ }
+
+ if (is_dirty) {
snap_object_data_clear(sod);
init = true;
}
@@ -244,8 +312,32 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
if (init) {
sod->type = SNAP_MESH;
- /* start assuming that it has each of these element types */
- sod->has_looptris = true;
+
+ /* The BVHTree from looptris is always required. */
+ BLI_assert(sod->treedata_mesh.tree == NULL);
+ BKE_bvhtree_from_mesh_get(&sod->treedata_mesh,
+ me_eval,
+ use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI,
+ 4);
+
+ if (sod->treedata_mesh.tree == NULL) {
+ sod->treedata_mesh.vert = me_eval->mvert;
+ sod->treedata_mesh.loop = me_eval->mloop;
+ sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval);
+ BLI_assert(sod->has_looptris == false);
+ }
+ else {
+ BLI_assert(sod->treedata_mesh.vert != NULL);
+ BLI_assert(sod->treedata_mesh.loop != NULL);
+ BLI_assert(sod->treedata_mesh.looptri != NULL);
+ sod->has_looptris = true;
+ }
+
+ /* Required for snapping with occlusion. */
+ sod->treedata_mesh.edge = me_eval->medge;
+ sod->poly = me_eval->mpoly;
+
+ /* Start assuming that it has each of these element types. */
sod->has_loose_edge = true;
sod->has_loose_vert = true;
}
@@ -253,26 +345,26 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
return sod;
}
-static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob)
+static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- if (em->mesh_eval_final) {
- return &em->mesh_eval_final->runtime;
+ BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
+ if (em_eval->mesh_eval_final) {
+ return &em_eval->mesh_eval_final->runtime;
}
- if (em->mesh_eval_cage) {
- return &em->mesh_eval_cage->runtime;
+ if (em_eval->mesh_eval_cage) {
+ return &em_eval->mesh_eval_cage->runtime;
}
- return &((Mesh *)ob->data)->runtime;
+ return &((Mesh *)ob_eval->data)->runtime;
}
static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
BMEditMesh *em)
{
SnapObjectData *sod;
void **sod_p;
- bool init = false, init_min_max = true, clear_cache = false;
+ bool init = false;
{
/* Use object-data as the key in ghash since the editmesh
@@ -281,48 +373,53 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__);
}
void **ob_p;
- if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob->data, &ob_p)) {
- ob = *ob_p;
+ if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob_eval->data, &ob_p)) {
+ ob_eval = *ob_p;
}
else {
- *ob_p = ob;
+ *ob_p = ob_eval;
}
}
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) {
sod = *sod_p;
- bool clear = false;
+ bool is_dirty = false;
/* Check if the geometry has changed. */
if (sod->type != SNAP_EDIT_MESH) {
- clear = true;
+ is_dirty = true;
}
else if (sod->treedata_editmesh.em != em) {
- clear_cache = true;
- init = true;
+ is_dirty = true;
}
else if (sod->mesh_runtime) {
- if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) {
- clear_cache = true;
- init = true;
+ if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) {
+ if (G.moving) {
+ /* Hack to avoid updating while transforming. */
+ BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]);
+ sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
+ }
+ else {
+ is_dirty = true;
+ }
}
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
- clear = true;
+ is_dirty = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
- clear = true;
+ is_dirty = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
- clear = true;
+ is_dirty = true;
}
}
- if (clear) {
+ if (is_dirty) {
snap_object_data_clear(sod);
init = true;
}
@@ -335,27 +432,8 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
if (init) {
sod->type = SNAP_EDIT_MESH;
sod->treedata_editmesh.em = em;
-
- if (clear_cache) {
- /* Only init min and max when you have a non-custom bvhtree pending. */
- init_min_max = false;
- if (sod->treedata_editmesh.cached) {
- sod->treedata_editmesh.tree = NULL;
- init_min_max = true;
- }
- for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
- if (sod->cached[i]) {
- sod->bvhtree[i] = NULL;
- init_min_max = true;
- }
- }
- }
-
- if (init_min_max) {
- bm_mesh_minmax(em->bm, sod->min, sod->max);
- }
-
- sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob);
+ sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
+ bm_mesh_minmax(em->bm, sod->min, sod->max);
}
return sod;
@@ -368,9 +446,9 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
float obmat[4][4],
- bool use_obedit,
+ eSnapEditType edit_mode_type,
bool use_backface_culling,
bool is_object_active,
void *data);
@@ -387,10 +465,17 @@ static void iter_snap_objects(SnapObjectContext *sctx,
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
const View3D *v3d = sctx->v3d_data.v3d;
const eSnapSelect snap_select = params->snap_select;
- const bool use_object_edit_cage = params->use_object_edit_cage;
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
const bool use_backface_culling = params->use_backface_culling;
Base *base_act = view_layer->basact;
+ if (snap_select == SNAP_ONLY_ACTIVE) {
+ Object *obj_eval = DEG_get_evaluated_object(depsgraph, base_act->object);
+ sob_callback(
+ sctx, obj_eval, obj_eval->obmat, edit_mode_type, use_backface_culling, true, data);
+ return;
+ }
+
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
if (!BASE_VISIBLE(v3d, base)) {
continue;
@@ -425,7 +510,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
sob_callback(sctx,
dupli_ob->ob,
dupli_ob->mat,
- use_object_edit_cage,
+ edit_mode_type,
use_backface_culling,
is_object_active,
data);
@@ -436,7 +521,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
sob_callback(sctx,
obj_eval,
obj_eval->obmat,
- use_object_edit_cage,
+ edit_mode_type,
use_backface_culling,
is_object_active,
data);
@@ -464,7 +549,7 @@ struct RayCastAll_Data {
float len_diff;
float local_scale;
- Object *ob;
+ Object *ob_eval;
uint ob_uuid;
/* output data */
@@ -476,7 +561,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
const float co[3],
const float no[3],
int index,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
uint ob_uuid)
{
@@ -487,7 +572,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
copy_v3_v3(hit->no, no);
hit->index = index;
- hit->ob = ob;
+ hit->ob_eval = ob_eval;
copy_m4_m4(hit->obmat, (float(*)[4])obmat);
hit->ob_uuid = ob_uuid;
@@ -529,7 +614,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
normalize_v3(normal);
struct SnapObjectHitDepth *hit_item = hit_depth_create(
- depth, location, normal, hit->index, data->ob, data->obmat, data->ob_uuid);
+ depth, location, normal, hit->index, data->ob_eval, data->obmat, data->ob_uuid);
BLI_addtail(data->hit_list, hit_item);
}
}
@@ -601,8 +686,8 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
static bool raycastMesh(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
- Object *ob,
- Mesh *me,
+ Object *ob_eval,
+ Mesh *me_eval,
const float obmat[4][4],
const uint ob_index,
bool use_hide,
@@ -617,7 +702,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
{
bool retval = false;
- if (me->totpoly == 0) {
+ if (me_eval->totpoly == 0) {
return retval;
}
@@ -641,7 +726,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob);
+ BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
if (bb) {
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!isect_ray_aabb_v3_simple(
@@ -661,53 +746,18 @@ static bool raycastMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
+ SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
- /* The tree is owned by the Mesh and may have been freed since we last used. */
- if (treedata->tree) {
- BLI_assert(treedata->cached);
- if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
- else {
- /* Update Pointers. */
- if (treedata->vert && treedata->vert_allocated == false) {
- treedata->vert = me->mvert;
- }
- if (treedata->loop && treedata->loop_allocated == false) {
- treedata->loop = me->mloop;
- }
- if (treedata->looptri && treedata->looptri_allocated == false) {
- treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
- }
- /* required for snapping with occlusion. */
- treedata->edge = me->medge;
- sod->poly = me->mpoly;
- }
- }
-
if (treedata->tree == NULL) {
- if (use_hide) {
- BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI_NO_HIDDEN, 4);
- }
- else {
- BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
- }
-
- /* required for snapping with occlusion. */
- treedata->edge = me->medge;
- sod->poly = me->mpoly;
-
- if (treedata->tree == NULL) {
- return retval;
- }
+ return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
transpose_m3_m4(timat, imat);
+ BLI_assert(treedata->raycast_callback != NULL);
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -717,7 +767,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
data.timat = timat;
data.len_diff = len_diff;
data.local_scale = local_scale;
- data.ob = ob;
+ data.ob_eval = ob_eval;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -776,7 +826,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
static bool raycastEditMesh(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
- Object *ob,
+ Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
const uint ob_index,
@@ -813,7 +863,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
local_depth *= local_scale;
}
- SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
+ SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
/* Test BoundBox */
@@ -839,7 +889,8 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
if (treedata->tree == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
- BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob)));
+ BLI_assert(sod->treedata_editmesh.em ==
+ BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
em = sod->treedata_editmesh.em;
if (sctx->callbacks.edit_mesh.test_face_fn) {
@@ -886,7 +937,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
data.timat = timat;
data.len_diff = len_diff;
data.local_scale = local_scale;
- data.ob = ob;
+ data.ob_eval = ob_eval;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -967,9 +1018,9 @@ struct RaycastObjUserData {
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void raycast_obj_fn(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
float obmat[4][4],
- bool use_obedit,
+ eSnapEditType edit_mode_type,
bool use_backface_culling,
bool is_object_active,
void *data)
@@ -982,53 +1033,46 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
bool retval = false;
if (use_occlusion_test) {
- if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
+ if ((edit_mode_type == SNAP_GEOM_EDIT) && sctx->use_v3d &&
+ XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
/* Use of occlude geometry in editing mode disabled. */
return;
}
- if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) {
+ if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) {
/* Do not hit objects that are in wire or bounding box
* display mode. */
return;
}
}
- switch (ob->type) {
+ switch (ob_eval->type) {
case OB_MESH: {
- Mesh *me = ob->data;
bool use_hide = false;
- if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
- /* Operators only update the editmesh looptris of the original mesh. */
- BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
- retval = raycastEditMesh(sctx,
- dt->ray_start,
- dt->ray_dir,
- ob,
- em_orig,
- obmat,
- ob_index,
- use_backface_culling,
- ray_depth,
- dt->r_loc,
- dt->r_no,
- dt->r_index,
- dt->r_hit_list);
- break;
- }
-
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- if (em->mesh_eval_final) {
- me = em->mesh_eval_final;
- use_hide = true;
- }
+ Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval == NULL) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
+ retval = raycastEditMesh(sctx,
+ dt->ray_start,
+ dt->ray_dir,
+ ob_eval,
+ em_orig,
+ obmat,
+ ob_index,
+ use_backface_culling,
+ ray_depth,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
+ break;
}
retval = raycastMesh(sctx,
dt->ray_start,
dt->ray_dir,
- ob,
- me,
+ ob_eval,
+ me_eval,
obmat,
ob_index,
use_hide,
@@ -1044,12 +1088,12 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
case OB_SURF:
case OB_FONT: {
if (!is_object_active) {
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval = raycastMesh(sctx,
dt->ray_start,
dt->ray_dir,
- ob,
+ ob_eval,
mesh_eval,
obmat,
ob_index,
@@ -1068,7 +1112,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
if (retval) {
if (dt->r_ob) {
- *dt->r_ob = ob;
+ *dt->r_ob = ob_eval;
}
if (dt->r_obmat) {
copy_m4_m4(dt->r_obmat, obmat);
@@ -1323,6 +1367,33 @@ typedef struct Nearest2dUserData {
bool use_backface_culling;
} Nearest2dUserData;
+static void nearest2d_data_init(SnapObjectData *sod,
+ bool is_persp,
+ bool use_backface_culling,
+ Nearest2dUserData *r_nearest2d)
+{
+ if (sod->type == SNAP_MESH) {
+ r_nearest2d->userdata = &sod->treedata_mesh;
+ r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
+ r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
+ r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
+ r_nearest2d->get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get;
+ r_nearest2d->get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ r_nearest2d->userdata = sod->treedata_editmesh.em;
+ r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
+ r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
+ r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ r_nearest2d->get_tri_verts_index = NULL;
+ r_nearest2d->get_tri_edges_index = NULL;
+ }
+
+ r_nearest2d->is_persp = is_persp;
+ r_nearest2d->use_backface_culling = use_backface_culling;
+}
+
static void cb_snap_vert(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -1470,7 +1541,7 @@ static void cb_snap_tri_verts(void *userdata,
static short snap_mesh_polygon(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
bool use_backface_culling,
/* read/write args */
@@ -1495,28 +1566,21 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- .use_backface_culling = use_backface_culling,
- };
-
BVHTreeNearest nearest = {
.index = -1,
.dist_sq = square_f(*dist_px),
};
- SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
-
+ SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval);
BLI_assert(sod != NULL);
+ Nearest2dUserData nearest2d;
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
+
if (sod->type == SNAP_MESH) {
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
- nearest2d.userdata = treedata;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
-
const MPoly *mp = &sod->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
@@ -1547,11 +1611,6 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BLI_assert(sod->type == SNAP_EDIT_MESH);
BMEditMesh *em = sod->treedata_editmesh.em;
- nearest2d.userdata = em;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
-
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
BMFace *f = BM_face_at_index(em->bm, *r_index);
BMLoop *l_iter, *l_first;
@@ -1608,7 +1667,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
@@ -1622,32 +1681,16 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
{
short elem = SCE_SNAP_MODE_EDGE;
- if (ob->type != OB_MESH) {
+ if (ob_eval->type != OB_MESH) {
return elem;
}
- SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
-
+ SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval);
BLI_assert(sod != NULL);
Nearest2dUserData nearest2d;
- {
- nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- nearest2d.use_backface_culling = use_backface_culling;
- if (sod->type == SNAP_MESH) {
- nearest2d.userdata = &sod->treedata_mesh;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- nearest2d.userdata = sod->treedata_editmesh.em;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
- }
- }
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
int vindex[2];
nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata);
@@ -1772,9 +1815,8 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
static short snapArmature(SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
- bool use_obedit,
/* read/write args */
float *dist_px,
/* return args */
@@ -1795,11 +1837,11 @@ static short snapArmature(SnapData *snapdata,
dist_squared_to_projected_aabb_precalc(
&neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
- use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
+ bool use_obedit = ((bArmature *)ob_eval->data)->edbo != NULL;
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_armature_boundbox_get(ob);
+ BoundBox *bb = BKE_armature_boundbox_get(ob_eval);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return retval;
@@ -1814,7 +1856,7 @@ static short snapArmature(SnapData *snapdata,
bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- bArmature *arm = ob->data;
+ bArmature *arm = ob_eval->data;
if (arm->edbo) {
LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
if (eBone->layer & arm->layer) {
@@ -1858,8 +1900,8 @@ static short snapArmature(SnapData *snapdata,
}
}
}
- else if (ob->pose && ob->pose->chanbase.first) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ else if (ob_eval->pose && ob_eval->pose->chanbase.first) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) {
Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
@@ -1917,7 +1959,7 @@ static short snapArmature(SnapData *snapdata,
}
static short snapCurve(SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
bool use_obedit,
/* read/write args */
@@ -1934,7 +1976,7 @@ static short snapCurve(SnapData *snapdata,
return 0;
}
- Curve *cu = ob->data;
+ Curve *cu = ob_eval->data;
float dist_px_sq = square_f(*dist_px);
float lpmat[4][4];
@@ -1944,11 +1986,11 @@ static short snapCurve(SnapData *snapdata,
dist_squared_to_projected_aabb_precalc(
&neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
- use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
+ use_obedit = use_obedit && BKE_object_is_in_editmode(ob_eval);
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_curve_boundbox_get(ob);
+ BoundBox *bb = BKE_curve_boundbox_get(ob_eval);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
@@ -2068,7 +2110,7 @@ static short snapCurve(SnapData *snapdata,
/* may extend later (for now just snaps to empty center) */
static short snap_object_center(SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
/* read/write args */
float *dist_px,
@@ -2079,7 +2121,7 @@ static short snap_object_center(SnapData *snapdata,
{
short retval = 0;
- if (ob->transflag & OB_DUPLI) {
+ if (ob_eval->transflag & OB_DUPLI) {
return retval;
}
@@ -2222,9 +2264,10 @@ static short snapCamera(const SnapObjectContext *sctx,
static short snapMesh(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
- Mesh *me,
+ Object *ob_eval,
+ Mesh *me_eval,
const float obmat[4][4],
+ bool use_hide,
bool use_backface_culling,
/* read/write args */
float *dist_px,
@@ -2234,10 +2277,10 @@ static short snapMesh(SnapObjectContext *sctx,
int *r_index)
{
BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
- if (me->totvert == 0) {
+ if (me_eval->totvert == 0) {
return 0;
}
- if (me->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
return 0;
}
@@ -2247,65 +2290,46 @@ static short snapMesh(SnapObjectContext *sctx,
float dist_px_sq = square_f(*dist_px);
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob);
+ BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
}
- SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
+ SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
- BVHTreeFromMesh *treedata, dummy_treedata;
+ BVHTreeFromMesh *treedata, treedata_tmp;
treedata = &sod->treedata_mesh;
- /* The tree is owned by the Mesh and may have been freed since we last used! */
- if (treedata->cached && treedata->tree &&
- !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
- if (sod->cached[0] && sod->bvhtree[0] &&
- !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) {
- sod->bvhtree[0] = NULL;
- }
- if (sod->cached[1] && sod->bvhtree[1] &&
- !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) {
- sod->bvhtree[1] = NULL;
- }
-
- if (sod->has_looptris && treedata->tree == NULL) {
- BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
- sod->has_looptris = (treedata->tree != NULL);
- if (sod->has_looptris) {
- /* Make sure that the array of edges is referenced in the callbacks. */
- treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
- }
- }
if (sod->has_loose_edge && sod->bvhtree[0] == NULL) {
- sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2);
- sod->has_loose_edge = sod->bvhtree[0] != NULL;
- sod->cached[0] = dummy_treedata.cached;
-
- if (sod->has_loose_edge) {
- BLI_assert(treedata->vert_allocated == false);
- treedata->vert = dummy_treedata.vert;
- treedata->vert_allocated = dummy_treedata.vert_allocated;
-
- BLI_assert(treedata->edge_allocated == false);
- treedata->edge = dummy_treedata.edge;
- treedata->edge_allocated = dummy_treedata.edge_allocated;
+ sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(
+ &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
+ if (sod->bvhtree[0] == NULL) {
+ sod->has_loose_edge = false;
}
+ sod->cached[0] = treedata_tmp.cached;
+ BLI_assert(!ELEM(true,
+ treedata_tmp.vert_allocated,
+ treedata_tmp.edge_allocated,
+ treedata_tmp.face_allocated,
+ treedata_tmp.loop_allocated,
+ treedata_tmp.looptri_allocated));
}
+
if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
if (sod->has_loose_vert && sod->bvhtree[1] == NULL) {
- sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2);
- sod->has_loose_vert = sod->bvhtree[1] != NULL;
- sod->cached[1] = dummy_treedata.cached;
-
- if (sod->has_loose_vert) {
- BLI_assert(treedata->vert_allocated == false);
- treedata->vert = dummy_treedata.vert;
- treedata->vert_allocated = dummy_treedata.vert_allocated;
+ sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(
+ &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
+ if (sod->bvhtree[1] == NULL) {
+ sod->has_loose_vert = false;
}
+ sod->cached[1] = treedata_tmp.cached;
+ BLI_assert(!ELEM(true,
+ treedata_tmp.vert_allocated,
+ treedata_tmp.edge_allocated,
+ treedata_tmp.face_allocated,
+ treedata_tmp.loop_allocated,
+ treedata_tmp.looptri_allocated));
}
}
else {
@@ -2313,33 +2337,9 @@ static short snapMesh(SnapObjectContext *sctx,
sod->has_loose_vert = false;
}
- /* Update pointers. */
- if (treedata->vert_allocated == false) {
- treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */
- }
- if (treedata->tree || sod->bvhtree[0]) {
- if (treedata->edge_allocated == false) {
- /* If raycast has been executed before, `treedata->edge` can be NULL. */
- treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
- }
- if (treedata->loop && treedata->loop_allocated == false) {
- treedata->loop = me->mloop; /* CustomData_get_layer(&me->edata, CD_MLOOP);? */
- }
- if (treedata->looptri && treedata->looptri_allocated == false) {
- treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
- }
- }
-
- Nearest2dUserData nearest2d = {
- .userdata = treedata,
- .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get,
- .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get,
- .get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get,
- .get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get,
- .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy,
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- .use_backface_culling = use_backface_culling,
- };
+ Nearest2dUserData nearest2d;
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2455,7 +2455,7 @@ static short snapMesh(SnapObjectContext *sctx,
static short snapEditMesh(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
bool use_backface_culling,
@@ -2484,7 +2484,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
float dist_px_sq = square_f(*dist_px);
- SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
+ SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
/* Test BoundBox */
@@ -2558,14 +2558,9 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
}
- Nearest2dUserData nearest2d = {
- .userdata = em,
- .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get,
- .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get,
- .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy,
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- .use_backface_culling = use_backface_culling,
- };
+ Nearest2dUserData nearest2d;
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2659,9 +2654,9 @@ struct SnapObjUserData {
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void snap_obj_fn(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
float obmat[4][4],
- bool use_obedit,
+ eSnapEditType edit_mode_type,
bool use_backface_culling,
bool UNUSED(is_object_active),
void *data)
@@ -2669,41 +2664,36 @@ static void snap_obj_fn(SnapObjectContext *sctx,
struct SnapObjUserData *dt = data;
short retval = 0;
- switch (ob->type) {
+ switch (ob_eval->type) {
case OB_MESH: {
- Mesh *me = ob->data;
- if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
- /* Operators only update the editmesh looptris of the original mesh. */
- BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
- retval = snapEditMesh(sctx,
- dt->snapdata,
- ob,
- em_orig,
- obmat,
- use_backface_culling,
- dt->dist_px,
- dt->r_loc,
- dt->r_no,
- dt->r_index);
- break;
- }
-
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- if (em->mesh_eval_final) {
- me = em->mesh_eval_final;
- }
+ bool use_hide;
+ Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval == NULL) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
+ retval = snapEditMesh(sctx,
+ dt->snapdata,
+ ob_eval,
+ em_orig,
+ obmat,
+ use_backface_culling,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ break;
}
- else if (ob->dt == OB_BOUNDBOX) {
+ if (ob_eval->dt == OB_BOUNDBOX) {
/* Do not snap to objects that are in bounding box display mode */
return;
}
retval = snapMesh(sctx,
dt->snapdata,
- ob,
- me,
+ ob_eval,
+ me_eval,
obmat,
+ use_hide,
use_backface_culling,
dt->dist_px,
dt->r_loc,
@@ -2713,21 +2703,28 @@ static void snap_obj_fn(SnapObjectContext *sctx,
}
case OB_ARMATURE:
retval = snapArmature(
- dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(
- dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapCurve(dt->snapdata,
+ ob_eval,
+ obmat,
+ edit_mode_type == SNAP_GEOM_EDIT,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval |= snapMesh(sctx,
dt->snapdata,
- ob,
+ ob_eval,
mesh_eval,
obmat,
+ false,
use_backface_culling,
dt->dist_px,
dt->r_loc,
@@ -2740,17 +2737,17 @@ static void snap_obj_fn(SnapObjectContext *sctx,
case OB_GPENCIL:
case OB_LAMP:
retval = snap_object_center(
- dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CAMERA:
retval = snapCamera(
- sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ sctx, dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (retval) {
if (dt->r_ob) {
- *dt->r_ob = ob;
+ *dt->r_ob = ob_eval;
}
if (dt->r_obmat) {
copy_m4_m4(dt->r_obmat, obmat);
@@ -3023,7 +3020,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
short retval = 0;
bool has_hit = false;
- Object *ob = NULL;
+ Object *ob_eval = NULL;
float loc[3];
/* Not all snapping callbacks set the normal,
* initialize this since any hit copies both the `loc` and `no`. */
@@ -3060,7 +3057,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
loc,
no,
&index,
- &ob,
+ &ob_eval,
obmat,
NULL);
@@ -3072,7 +3069,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
copy_v3_v3(r_no, no);
}
if (r_ob) {
- *r_ob = ob;
+ *r_ob = ob_eval;
}
if (r_obmat) {
copy_m4_m4(r_obmat, obmat);
@@ -3108,9 +3105,10 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.has_occlusion_plane = false;
/* By convention we only snap to the original elements of a curve. */
- if (has_hit && ob->type != OB_CURVE) {
+ if (has_hit && ob_eval->type != OB_CURVE) {
/* Compute the new clip_pane but do not add it yet. */
float new_clipplane[4];
+ BLI_ASSERT_UNIT_V3(no);
plane_from_point_normal_v3(new_clipplane, loc, no);
if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) {
/* The plane is facing the wrong direction. */
@@ -3121,8 +3119,15 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(
- sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index);
+ elem_test = snap_mesh_polygon(sctx,
+ &snapdata,
+ ob_eval,
+ obmat,
+ params->use_backface_culling,
+ &dist_px_tmp,
+ loc,
+ no,
+ &index);
if (elem_test) {
elem = elem_test;
}
@@ -3137,7 +3142,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
}
elem_test = snapObjectsRay(
- sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
+ sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
if (elem_test) {
elem = elem_test;
}
@@ -3148,7 +3153,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.snap_to_flag = snap_to_flag;
elem = snap_mesh_edge_verts_mixed(sctx,
&snapdata,
- ob,
+ ob_eval,
obmat,
*dist_px,
prev_co,
@@ -3167,7 +3172,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
copy_v3_v3(r_no, no);
}
if (r_ob) {
- *r_ob = ob;
+ *r_ob = ob_eval;
}
if (r_obmat) {
copy_m4_m4(r_obmat, obmat);
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh
index 31b67dd3d70..e2c49697ba9 100644
--- a/source/blender/functions/FN_generic_span.hh
+++ b/source/blender/functions/FN_generic_span.hh
@@ -30,7 +30,7 @@ namespace blender::fn {
* A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time.
*/
class GSpan {
- private:
+ protected:
const CPPType *type_;
const void *data_;
int64_t size_;
@@ -85,6 +85,14 @@ class GSpan {
BLI_assert(type_->is<T>());
return Span<T>(static_cast<const T *>(data_), size_);
}
+
+ GSpan slice(const int64_t start, int64_t size) const
+ {
+ BLI_assert(start >= 0);
+ BLI_assert(size >= 0);
+ const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
+ return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
+ }
};
/**
@@ -92,7 +100,7 @@ class GSpan {
* known at run-time.
*/
class GMutableSpan {
- private:
+ protected:
const CPPType *type_;
void *data_;
int64_t size_;
@@ -153,6 +161,14 @@ class GMutableSpan {
BLI_assert(type_->is<T>());
return MutableSpan<T>(static_cast<T *>(data_), size_);
}
+
+ GMutableSpan slice(const int64_t start, int64_t size) const
+ {
+ BLI_assert(start >= 0);
+ BLI_assert(size >= 0);
+ const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
+ return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
+ }
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh
index ae6eb8a614f..b02ed471875 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/functions/FN_generic_vector_array.hh
@@ -123,7 +123,7 @@ template<typename T> class GVectorArray_TypedMutableRef {
void extend(const int64_t index, const VArray<T> &values)
{
- GVArrayForVArray<T> array{values};
+ GVArray_For_VArray<T> array{values};
this->extend(index, array);
}
@@ -134,12 +134,12 @@ template<typename T> class GVectorArray_TypedMutableRef {
};
/* A generic virtual vector array implementation for a `GVectorArray`. */
-class GVVectorArrayForGVectorArray : public GVVectorArray {
+class GVVectorArray_For_GVectorArray : public GVVectorArray {
private:
const GVectorArray &vector_array_;
public:
- GVVectorArrayForGVectorArray(const GVectorArray &vector_array)
+ GVVectorArray_For_GVectorArray(const GVectorArray &vector_array)
: GVVectorArray(vector_array.type(), vector_array.size()), vector_array_(vector_array)
{
}
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index c6230730a8d..c1af00fd4cd 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -23,12 +23,17 @@
* the data type is only known at runtime.
*/
+#include <optional>
+
#include "BLI_virtual_array.hh"
#include "FN_generic_span.hh"
namespace blender::fn {
+template<typename T> class GVArray_Typed;
+template<typename T> class GVMutableArray_Typed;
+
/* A generically typed version of `VArray<T>`. */
class GVArray {
protected:
@@ -86,13 +91,13 @@ class GVArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
- GSpan get_span() const
+ GSpan get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return GSpan(*type_);
}
- return this->get_span_impl();
+ return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -107,57 +112,136 @@ class GVArray {
/* Copies the value that is used for every element into `r_value`, which is expected to point to
* initialized memory. This invokes undefined behavior if the virtual array would not return the
* same value for every index. */
- void get_single(void *r_value) const
+ void get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
if (size_ == 1) {
this->get(0, r_value);
}
- this->get_single_impl(r_value);
+ this->get_internal_single_impl(r_value);
}
- /* Same as `get_single`, but `r_value` points to initialized memory. */
+ /* Same as `get_internal_single`, but `r_value` points to initialized memory. */
void get_single_to_uninitialized(void *r_value) const
{
type_->construct_default(r_value);
- this->get_single(r_value);
+ this->get_internal_single(r_value);
}
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+ template<typename T> const VArray<T> *try_get_internal_varray() const
+ {
+ BLI_assert(type_->is<T>());
+ return (const VArray<T> *)this->try_get_internal_varray_impl();
+ }
+
+ /* Create a typed virtual array for this generic virtual array. */
+ template<typename T> GVArray_Typed<T> typed() const
+ {
+ return GVArray_Typed<T>(*this);
+ }
+
protected:
virtual void get_impl(const int64_t index, void *r_value) const;
virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
virtual bool is_span_impl() const;
- virtual GSpan get_span_impl() const;
+ virtual GSpan get_internal_span_impl() const;
virtual bool is_single_impl() const;
- virtual void get_single_impl(void *UNUSED(r_value)) const;
+ virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
+
+ virtual const void *try_get_internal_varray_impl() const;
+};
+
+/* Similar to GVArray, but supports changing the elements in the virtual array. */
+class GVMutableArray : public GVArray {
+ public:
+ GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size)
+ {
+ }
+
+ void set_by_copy(const int64_t index, const void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_copy_impl(index, value);
+ }
+
+ void set_by_move(const int64_t index, void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_move_impl(index, value);
+ }
+
+ void set_by_relocate(const int64_t index, void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_relocate_impl(index, value);
+ }
+
+ GMutableSpan get_internal_span()
+ {
+ BLI_assert(this->is_span());
+ GSpan span = static_cast<const GVArray *>(this)->get_internal_span();
+ return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
+ }
+
+ template<typename T> VMutableArray<T> *try_get_internal_mutable_varray()
+ {
+ BLI_assert(type_->is<T>());
+ return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl();
+ }
+
+ /* Create a typed virtual array for this generic virtual array. */
+ template<typename T> GVMutableArray_Typed<T> typed()
+ {
+ return GVMutableArray_Typed<T>(*this);
+ }
+
+ void fill(const void *value);
+
+ protected:
+ virtual void set_by_copy_impl(const int64_t index, const void *value);
+ virtual void set_by_relocate_impl(const int64_t index, void *value);
+ virtual void set_by_move_impl(const int64_t index, void *value) = 0;
+
+ virtual void *try_get_internal_mutable_varray_impl();
};
-class GVArrayForGSpan : public GVArray {
+using GVArrayPtr = std::unique_ptr<GVArray>;
+using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>;
+
+class GVArray_For_GSpan : public GVArray {
protected:
- const void *data_;
+ const void *data_ = nullptr;
const int64_t element_size_;
public:
- GVArrayForGSpan(const GSpan span)
+ GVArray_For_GSpan(const GSpan span)
: GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
{
}
protected:
+ GVArray_For_GSpan(const CPPType &type, const int64_t size)
+ : GVArray(type, size), element_size_(type.size())
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
- GSpan get_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
};
-class GVArrayForEmpty : public GVArray {
+class GVArray_For_Empty : public GVArray {
public:
- GVArrayForEmpty(const CPPType &type) : GVArray(type, 0)
+ GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
{
}
@@ -168,108 +252,617 @@ class GVArrayForEmpty : public GVArray {
}
};
-class GVArrayForSingleValueRef : public GVArray {
- private:
- const void *value_;
+class GVMutableArray_For_GMutableSpan : public GVMutableArray {
+ protected:
+ void *data_ = nullptr;
+ const int64_t element_size_;
+
+ public:
+ GVMutableArray_For_GMutableSpan(const GMutableSpan span)
+ : GVMutableArray(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
+ {
+ }
+
+ protected:
+ GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
+ : GVMutableArray(type, size), element_size_(type.size())
+ {
+ }
+
+ void get_impl(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+
+ void set_by_copy_impl(const int64_t index, const void *value) override;
+ void set_by_move_impl(const int64_t index, void *value) override;
+ void set_by_relocate_impl(const int64_t index, void *value) override;
+
+ bool is_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
+};
+
+/* Generic virtual array where each element has the same value. The value is not owned. */
+class GVArray_For_SingleValueRef : public GVArray {
+ protected:
+ const void *value_ = nullptr;
public:
- GVArrayForSingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
: GVArray(type, size), value_(value)
{
}
protected:
+ GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
- GSpan get_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
bool is_single_impl() const override;
- void get_single_impl(void *r_value) const override;
+ void get_internal_single_impl(void *r_value) const override;
};
-template<typename T> class GVArrayForVArray : public GVArray {
- private:
- const VArray<T> &array_;
+/* Same as GVArray_For_SingleValueRef, but the value is owned. */
+class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
+ public:
+ GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
+ ~GVArray_For_SingleValue();
+};
+
+/* Used to convert a typed virtual array into a generic one. */
+template<typename T> class GVArray_For_VArray : public GVArray {
+ protected:
+ const VArray<T> *varray_ = nullptr;
public:
- GVArrayForVArray(const VArray<T> &array)
- : GVArray(CPPType::get<T>(), array.size()), array_(array)
+ GVArray_For_VArray(const VArray<T> &varray)
+ : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
{
}
protected:
+ GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override
{
- *(T *)r_value = array_.get(index);
+ *(T *)r_value = varray_->get(index);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
- new (r_value) T(array_.get(index));
+ new (r_value) T(varray_->get(index));
}
bool is_span_impl() const override
{
- return array_.is_span();
+ return varray_->is_span();
}
- GSpan get_span_impl() const override
+ GSpan get_internal_span_impl() const override
{
- return GSpan(array_.get_span());
+ return GSpan(varray_->get_internal_span());
}
bool is_single_impl() const override
{
- return array_.is_single();
+ return varray_->is_single();
+ }
+
+ void get_internal_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = varray_->get_internal_single();
}
- void get_single_impl(void *r_value) const override
+ const void *try_get_internal_varray_impl() const override
{
- *(T *)r_value = array_.get_single();
+ return varray_;
}
};
-template<typename T> class VArrayForGVArray : public VArray<T> {
- private:
- const GVArray &array_;
+/* Used to convert any generic virtual array into a typed one. */
+template<typename T> class VArray_For_GVArray : public VArray<T> {
+ protected:
+ const GVArray *varray_ = nullptr;
public:
- VArrayForGVArray(const GVArray &array) : VArray<T>(array.size()), array_(array)
+ VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
+ {
+ BLI_assert(varray_->type().template is<T>());
+ }
+
+ protected:
+ VArray_For_GVArray(const int64_t size) : VArray<T>(size)
+ {
+ }
+
+ T get_impl(const int64_t index) const override
+ {
+ T value;
+ varray_->get(index, &value);
+ return value;
+ }
+
+ bool is_span_impl() const override
+ {
+ return varray_->is_span();
+ }
+
+ Span<T> get_internal_span_impl() const override
{
- BLI_assert(array_.type().template is<T>());
+ return varray_->get_internal_span().template typed<T>();
}
+ bool is_single_impl() const override
+ {
+ return varray_->is_single();
+ }
+
+ T get_internal_single_impl() const override
+ {
+ T value;
+ varray_->get_internal_single(&value);
+ return value;
+ }
+};
+
+/* Used to convert an generic mutable virtual array into a typed one. */
+template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
protected:
+ GVMutableArray *varray_ = nullptr;
+
+ public:
+ VMutableArray_For_GVMutableArray(GVMutableArray &varray)
+ : VMutableArray<T>(varray.size()), varray_(&varray)
+ {
+ BLI_assert(varray.type().template is<T>());
+ }
+
+ VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
+ {
+ }
+
+ private:
T get_impl(const int64_t index) const override
{
T value;
- array_.get(index, &value);
+ varray_->get(index, &value);
return value;
}
+ void set_impl(const int64_t index, T value) override
+ {
+ varray_->set_by_relocate(index, &value);
+ }
+
bool is_span_impl() const override
{
- return array_.is_span();
+ return varray_->is_span();
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
- return array_.get_span().template typed<T>();
+ return varray_->get_internal_span().template typed<T>();
}
bool is_single_impl() const override
{
- return array_.is_single();
+ return varray_->is_single();
}
- T get_single_impl() const override
+ T get_internal_single_impl() const override
{
T value;
- array_.get_single(&value);
+ varray_->get_internal_single(&value);
return value;
}
};
+/* Used to convert any typed virtual mutable array into a generic one. */
+template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
+ protected:
+ VMutableArray<T> *varray_ = nullptr;
+
+ public:
+ GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
+ : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ {
+ }
+
+ protected:
+ GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
+ {
+ }
+
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ *(T *)r_value = varray_->get(index);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(varray_->get(index));
+ }
+
+ bool is_span_impl() const override
+ {
+ return varray_->is_span();
+ }
+
+ GSpan get_internal_span_impl() const override
+ {
+ Span<T> span = varray_->get_internal_span();
+ return span;
+ }
+
+ bool is_single_impl() const override
+ {
+ return varray_->is_single();
+ }
+
+ void get_internal_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = varray_->get_internal_single();
+ }
+
+ void set_by_copy_impl(const int64_t index, const void *value) override
+ {
+ const T &value_ = *(const T *)value;
+ varray_->set(index, value_);
+ }
+
+ void set_by_relocate_impl(const int64_t index, void *value) override
+ {
+ T &value_ = *(T *)value;
+ varray_->set(index, std::move(value_));
+ value_.~T();
+ }
+
+ void set_by_move_impl(const int64_t index, void *value) override
+ {
+ T &value_ = *(T *)value;
+ varray_->set(index, std::move(value_));
+ }
+
+ const void *try_get_internal_varray_impl() const override
+ {
+ return (const VArray<T> *)varray_;
+ }
+
+ void *try_get_internal_mutable_varray_impl() override
+ {
+ return varray_;
+ }
+};
+
+/* A generic version of VArray_Span. */
+class GVArray_GSpan : public GSpan {
+ private:
+ const GVArray &varray_;
+ void *owned_data_ = nullptr;
+
+ public:
+ GVArray_GSpan(const GVArray &varray);
+ ~GVArray_GSpan();
+};
+
+/* A generic version of VMutableArray_Span. */
+class GVMutableArray_GSpan : public GMutableSpan {
+ private:
+ GVMutableArray &varray_;
+ void *owned_data_ = nullptr;
+ bool save_has_been_called_ = false;
+ bool show_not_saved_warning_ = true;
+
+ public:
+ GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true);
+ ~GVMutableArray_GSpan();
+
+ void save();
+ void disable_not_applied_warning();
+};
+
+/* Similar to GVArray_GSpan, but the resulting span is typed. */
+template<typename T> class GVArray_Span : public Span<T> {
+ private:
+ GVArray_GSpan varray_gspan_;
+
+ public:
+ GVArray_Span(const GVArray &varray) : varray_gspan_(varray)
+ {
+ BLI_assert(varray.type().is<T>());
+ this->data_ = (const T *)varray_gspan_.data();
+ this->size_ = varray_gspan_.size();
+ }
+};
+
+template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
+ private:
+ VArrayPtr<T> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ GVArray_For_OwnedVArray(VArrayPtr<T> varray)
+ : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
+ private:
+ GVArrayPtr owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ VArray_For_OwnedGVArray(GVArrayPtr varray)
+ : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T>
+class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
+ private:
+ VMutableArrayPtr<T> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray)
+ : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T>
+class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
+ private:
+ GVMutableArrayPtr owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray)
+ : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
+ * the compiler more opportunity to optimize the generic virtual array. */
+template<typename T, typename VArrayT>
+class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
+ private:
+ VArrayT embedded_varray_;
+
+ public:
+ template<typename... Args>
+ GVArray_For_EmbeddedVArray(const int64_t size, Args &&... args)
+ : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ {
+ this->varray_ = &embedded_varray_;
+ }
+};
+
+/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */
+template<typename T, typename VMutableArrayT>
+class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
+ private:
+ VMutableArrayT embedded_varray_;
+
+ public:
+ template<typename... Args>
+ GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&... args)
+ : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ {
+ this->varray_ = &embedded_varray_;
+ }
+};
+
+/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */
+template<typename Container, typename T = typename Container::value_type>
+class GVArray_For_ArrayContainer
+ : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> {
+ public:
+ GVArray_For_ArrayContainer(Container container)
+ : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>(
+ container.size(), std::move(container))
+ {
+ }
+};
+
+/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class GVArray_For_DerivedSpan
+ : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> {
+ public:
+ GVArray_For_DerivedSpan(const Span<StructT> data)
+ : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
+ data.size(), data)
+ {
+ }
+};
+
+/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT)>
+class GVMutableArray_For_DerivedSpan
+ : public GVMutableArray_For_EmbeddedVMutableArray<
+ ElemT,
+ VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> {
+ public:
+ GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
+ : GVMutableArray_For_EmbeddedVMutableArray<
+ ElemT,
+ VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data)
+ {
+ }
+};
+
+/* Same as VArray_For_Span, but for a generic virtual array. */
+template<typename T>
+class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> {
+ public:
+ GVArray_For_Span(const Span<T> data)
+ : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data)
+ {
+ }
+};
+
+/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */
+template<typename T>
+class GVMutableArray_For_MutableSpan
+ : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> {
+ public:
+ GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
+ : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
+ data)
+ {
+ }
+};
+
+/**
+ * Utility class to create the "best" typed virtual array for a given generic virtual array.
+ * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional
+ * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is
+ * just a span or single value).
+ *
+ * This is not a virtual array itself, but is used to get a virtual array.
+ */
+template<typename T> class GVArray_Typed {
+ private:
+ const VArray<T> *varray_;
+ /* Of these optional virtual arrays, at most one is constructed at any time. */
+ std::optional<VArray_For_Span<T>> varray_span_;
+ std::optional<VArray_For_Single<T>> varray_single_;
+ std::optional<VArray_For_GVArray<T>> varray_any_;
+ GVArrayPtr owned_gvarray_;
+
+ public:
+ explicit GVArray_Typed(const GVArray &gvarray)
+ {
+ BLI_assert(gvarray.type().is<T>());
+ if (gvarray.is_span()) {
+ const GSpan span = gvarray.get_internal_span();
+ varray_span_.emplace(span.typed<T>());
+ varray_ = &*varray_span_;
+ }
+ else if (gvarray.is_single()) {
+ T single_value;
+ gvarray.get_internal_single(&single_value);
+ varray_single_.emplace(single_value, gvarray.size());
+ varray_ = &*varray_single_;
+ }
+ else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) {
+ varray_ = internal_varray;
+ }
+ else {
+ varray_any_.emplace(gvarray);
+ varray_ = &*varray_any_;
+ }
+ }
+
+ /* Same as the constructor above, but also takes ownership of the passed in virtual array. */
+ explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray)
+ {
+ owned_gvarray_ = std::move(gvarray);
+ }
+
+ const VArray<T> &operator*() const
+ {
+ return *varray_;
+ }
+
+ const VArray<T> *operator->() const
+ {
+ return varray_;
+ }
+
+ /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is
+ * used within an expression. */
+ operator const VArray<T> &() const
+ {
+ return *varray_;
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return varray_->get(index);
+ }
+
+ int64_t size() const
+ {
+ return varray_->size();
+ }
+
+ IndexRange index_range() const
+ {
+ return IndexRange(this->size());
+ }
+};
+
+/* Same as GVArray_Typed, but for mutable virtual arrays. */
+template<typename T> class GVMutableArray_Typed {
+ private:
+ VMutableArray<T> *varray_;
+ std::optional<VMutableArray_For_MutableSpan<T>> varray_span_;
+ std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_;
+ GVMutableArrayPtr owned_gvarray_;
+
+ public:
+ explicit GVMutableArray_Typed(GVMutableArray &gvarray)
+ {
+ BLI_assert(gvarray.type().is<T>());
+ if (gvarray.is_span()) {
+ const GMutableSpan span = gvarray.get_internal_span();
+ varray_span_.emplace(span.typed<T>());
+ varray_ = &*varray_span_;
+ }
+ else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
+ varray_ = internal_varray;
+ }
+ else {
+ varray_any_.emplace(gvarray);
+ varray_ = &*varray_any_;
+ }
+ }
+
+ explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray)
+ {
+ owned_gvarray_ = std::move(gvarray);
+ }
+
+ VMutableArray<T> &operator*()
+ {
+ return *varray_;
+ }
+
+ VMutableArray<T> *operator->()
+ {
+ return varray_;
+ }
+
+ operator VMutableArray<T> &()
+ {
+ return *varray_;
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return varray_->get(index);
+ }
+
+ int64_t size() const
+ {
+ return varray_->size();
+ }
+};
+
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh
index ef3f53b5c25..4155a55a801 100644
--- a/source/blender/functions/FN_generic_virtual_vector_array.hh
+++ b/source/blender/functions/FN_generic_virtual_vector_array.hh
@@ -100,13 +100,13 @@ class GVVectorArray {
}
};
-class GVArrayForGVVectorArrayIndex : public GVArray {
+class GVArray_For_GVVectorArrayIndex : public GVArray {
private:
const GVVectorArray &vector_array_;
const int64_t index_;
public:
- GVArrayForGVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
+ GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
: GVArray(vector_array.type(), vector_array.get_vector_size(index)),
vector_array_(vector_array),
index_(index)
@@ -118,12 +118,12 @@ class GVArrayForGVVectorArrayIndex : public GVArray {
void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override;
};
-class GVVectorArrayForSingleGVArray : public GVVectorArray {
+class GVVectorArray_For_SingleGVArray : public GVVectorArray {
private:
const GVArray &array_;
public:
- GVVectorArrayForSingleGVArray(const GVArray &array, const int64_t size)
+ GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size)
: GVVectorArray(array.type(), size), array_(array)
{
}
@@ -137,12 +137,12 @@ class GVVectorArrayForSingleGVArray : public GVVectorArray {
bool is_single_vector_impl() const override;
};
-class GVVectorArrayForSingleGSpan : public GVVectorArray {
+class GVVectorArray_For_SingleGSpan : public GVVectorArray {
private:
const GSpan span_;
public:
- GVVectorArrayForSingleGSpan(const GSpan span, const int64_t size)
+ GVVectorArray_For_SingleGSpan(const GSpan span, const int64_t size)
: GVVectorArray(span.type(), size), span_(span)
{
}
@@ -156,12 +156,12 @@ class GVVectorArrayForSingleGSpan : public GVVectorArray {
bool is_single_vector_impl() const override;
};
-template<typename T> class VVectorArrayForGVVectorArray : public VVectorArray<T> {
+template<typename T> class VVectorArray_For_GVVectorArray : public VVectorArray<T> {
private:
const GVVectorArray &vector_array_;
public:
- VVectorArrayForGVVectorArray(const GVVectorArray &vector_array)
+ VVectorArray_For_GVVectorArray(const GVVectorArray &vector_array)
: VVectorArray<T>(vector_array.size()), vector_array_(vector_array)
{
}
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 72ebc0d9b94..3b15f0278f3 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -55,13 +55,13 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
- this->add_readonly_single_input(scope_.construct<GVArrayForSingleValueRef>(
+ this->add_readonly_single_input(scope_.construct<GVArray_For_SingleValueRef>(
__func__, CPPType::get<T>(), min_array_size_, value),
expected_name);
}
void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
{
- this->add_readonly_single_input(scope_.construct<GVArrayForGSpan>(__func__, span),
+ this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(__func__, span),
expected_name);
}
void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
@@ -74,7 +74,7 @@ class MFParamsBuilder {
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
{
this->add_readonly_vector_input(
- scope_.construct<GVVectorArrayForGVectorArray>(__func__, vector_array), expected_name);
+ scope_.construct<GVVectorArray_For_GVectorArray>(__func__, vector_array), expected_name);
}
void add_readonly_vector_input(const GVVectorArray &ref, StringRef expected_name = "")
{
@@ -177,7 +177,7 @@ class MFParams {
template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "")
{
const GVArray &array = this->readonly_single_input(param_index, name);
- return builder_->scope_.construct<VArrayForGVArray<T>>(__func__, array);
+ return builder_->scope_.construct<VArray_For_GVArray<T>>(__func__, array);
}
const GVArray &readonly_single_input(int param_index, StringRef name = "")
{
@@ -202,7 +202,7 @@ class MFParams {
const VVectorArray<T> &readonly_vector_input(int param_index, StringRef name = "")
{
const GVVectorArray &vector_array = this->readonly_vector_input(param_index, name);
- return builder_->scope_.construct<VVectorArrayForGVVectorArray<T>>(__func__, vector_array);
+ return builder_->scope_.construct<VVectorArray_For_GVVectorArray<T>>(__func__, vector_array);
}
const GVVectorArray &readonly_vector_input(int param_index, StringRef name = "")
{
diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc
index b3c5517cc43..3335b07e559 100644
--- a/source/blender/functions/intern/generic_vector_array.cc
+++ b/source/blender/functions/intern/generic_vector_array.cc
@@ -60,21 +60,21 @@ void GVectorArray::extend(const int64_t index, const GVArray &values)
void GVectorArray::extend(const int64_t index, const GSpan values)
{
- GVArrayForGSpan varray{values};
+ GVArray_For_GSpan varray{values};
this->extend(index, varray);
}
void GVectorArray::extend(IndexMask mask, const GVVectorArray &values)
{
for (const int i : mask) {
- GVArrayForGVVectorArrayIndex array{values, i};
+ GVArray_For_GVVectorArrayIndex array{values, i};
this->extend(i, array);
}
}
void GVectorArray::extend(IndexMask mask, const GVectorArray &values)
{
- GVVectorArrayForGVectorArray virtual_values{values};
+ GVVectorArray_For_GVectorArray virtual_values{values};
this->extend(mask, virtual_values);
}
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index 9380eb257b2..e11501828f8 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -18,6 +18,10 @@
namespace blender::fn {
+/* --------------------------------------------------------------------
+ * GVArray.
+ */
+
void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
@@ -37,7 +41,7 @@ bool GVArray::is_span_impl() const
return false;
}
-GSpan GVArray::get_span_impl() const
+GSpan GVArray::get_internal_span_impl() const
{
BLI_assert(false);
return GSpan(*type_);
@@ -48,60 +52,246 @@ bool GVArray::is_single_impl() const
return false;
}
-void GVArray::get_single_impl(void *UNUSED(r_value)) const
+void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const
{
BLI_assert(false);
}
-void GVArrayForGSpan::get_impl(const int64_t index, void *r_value) const
+const void *GVArray::try_get_internal_varray_impl() const
+{
+ return nullptr;
+}
+
+/* --------------------------------------------------------------------
+ * GVMutableArray.
+ */
+
+void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value)
+{
+ BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
+ type_->copy_to_uninitialized(value, buffer);
+ this->set_by_move_impl(index, buffer);
+ type_->destruct(buffer);
+}
+
+void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value)
+{
+ this->set_by_move_impl(index, value);
+ type_->destruct(value);
+}
+
+void *GVMutableArray::try_get_internal_mutable_varray_impl()
+{
+ return nullptr;
+}
+
+void GVMutableArray::fill(const void *value)
+{
+ if (this->is_span()) {
+ const GMutableSpan span = this->get_internal_span();
+ type_->fill_initialized(value, span.data(), size_);
+ }
+ else {
+ for (int64_t i : IndexRange(size_)) {
+ this->set_by_copy(i, value);
+ }
+ }
+}
+
+/* --------------------------------------------------------------------
+ * GVArray_For_GSpan.
+ */
+
+void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const
{
type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVArrayForGSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
+void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
{
type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-bool GVArrayForGSpan::is_span_impl() const
+bool GVArray_For_GSpan::is_span_impl() const
{
return true;
}
-GSpan GVArrayForGSpan::get_span_impl() const
+GSpan GVArray_For_GSpan::get_internal_span_impl() const
{
return GSpan(*type_, data_, size_);
}
-void GVArrayForSingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
+/* --------------------------------------------------------------------
+ * GVMutableArray_For_GMutableSpan.
+ */
+
+void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const
+{
+ type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
+}
+
+void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index,
+ void *r_value) const
+{
+ type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
+}
+
+void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value)
+{
+ type_->copy_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
+}
+
+void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value)
+{
+ type_->move_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
+}
+
+void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value)
+{
+ type_->relocate_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
+}
+
+bool GVMutableArray_For_GMutableSpan::is_span_impl() const
+{
+ return true;
+}
+
+GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const
+{
+ return GSpan(*type_, data_, size_);
+}
+
+/* --------------------------------------------------------------------
+ * GVArray_For_SingleValueRef.
+ */
+
+void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
}
-void GVArrayForSingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
- void *r_value) const
+void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
+ void *r_value) const
{
type_->copy_to_uninitialized(value_, r_value);
}
-bool GVArrayForSingleValueRef::is_span_impl() const
+bool GVArray_For_SingleValueRef::is_span_impl() const
{
return size_ == 1;
}
-GSpan GVArrayForSingleValueRef::get_span_impl() const
+GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const
{
return GSpan{*type_, value_, 1};
}
-bool GVArrayForSingleValueRef::is_single_impl() const
+bool GVArray_For_SingleValueRef::is_single_impl() const
{
return true;
}
-void GVArrayForSingleValueRef::get_single_impl(void *r_value) const
+void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
}
+/* --------------------------------------------------------------------
+ * GVArray_For_SingleValue.
+ */
+
+GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type,
+ const int64_t size,
+ const void *value)
+ : GVArray_For_SingleValueRef(type, size)
+{
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_to_uninitialized(value, (void *)value_);
+}
+
+GVArray_For_SingleValue::~GVArray_For_SingleValue()
+{
+ type_->destruct((void *)value_);
+ MEM_freeN((void *)value_);
+}
+
+/* --------------------------------------------------------------------
+ * GVArray_GSpan.
+ */
+
+GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray)
+{
+ size_ = varray_.size();
+ if (varray_.is_span()) {
+ data_ = varray_.get_internal_span().data();
+ }
+ else {
+ owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
+ varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
+ data_ = owned_data_;
+ }
+}
+
+GVArray_GSpan::~GVArray_GSpan()
+{
+ if (owned_data_ != nullptr) {
+ type_->destruct_n(owned_data_, size_);
+ MEM_freeN(owned_data_);
+ }
+}
+
+/* --------------------------------------------------------------------
+ * GVMutableArray_GSpan.
+ */
+
+GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span)
+ : GMutableSpan(varray.type()), varray_(varray)
+{
+ size_ = varray_.size();
+ if (varray_.is_span()) {
+ data_ = varray_.get_internal_span().data();
+ }
+ else {
+ owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
+ if (copy_values_to_span) {
+ varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
+ }
+ else {
+ type_->construct_default_n(owned_data_, size_);
+ }
+ data_ = owned_data_;
+ }
+}
+
+GVMutableArray_GSpan::~GVMutableArray_GSpan()
+{
+ if (show_not_saved_warning_) {
+ if (!save_has_been_called_) {
+ std::cout << "Warning: Call `apply()` to make sure that changes persist in all cases.\n";
+ }
+ }
+ if (owned_data_ != nullptr) {
+ type_->destruct_n(owned_data_, size_);
+ MEM_freeN(owned_data_);
+ }
+}
+
+void GVMutableArray_GSpan::save()
+{
+ save_has_been_called_ = true;
+ if (data_ != owned_data_) {
+ return;
+ }
+ const int64_t element_size = type_->size();
+ for (int64_t i : IndexRange(size_)) {
+ varray_.set_by_copy(i, POINTER_OFFSET(owned_data_, element_size * i));
+ }
+}
+
+void GVMutableArray_GSpan::disable_not_applied_warning()
+{
+ show_not_saved_warning_ = false;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc
index f6504cee41e..aa3d90883c6 100644
--- a/source/blender/functions/intern/generic_virtual_vector_array.cc
+++ b/source/blender/functions/intern/generic_virtual_vector_array.cc
@@ -18,48 +18,48 @@
namespace blender::fn {
-void GVArrayForGVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
{
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
-void GVArrayForGVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
- void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
+ void *r_value) const
{
type_->construct_default(r_value);
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
-int64_t GVVectorArrayForSingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
+int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
{
return array_.size();
}
-void GVVectorArrayForSingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
- const int64_t index_in_vector,
- void *r_value) const
+void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const
{
array_.get(index_in_vector, r_value);
}
-bool GVVectorArrayForSingleGVArray::is_single_vector_impl() const
+bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const
{
return true;
}
-int64_t GVVectorArrayForSingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
+int64_t GVVectorArray_For_SingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
{
return span_.size();
}
-void GVVectorArrayForSingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
- const int64_t index_in_vector,
- void *r_value) const
+void GVVectorArray_For_SingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const
{
type_->copy_to_initialized(span_[index_in_vector], r_value);
}
-bool GVVectorArrayForSingleGSpan::is_single_vector_impl() const
+bool GVVectorArray_For_SingleGSpan::is_single_vector_impl() const
{
return true;
}
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index 86ac4f6a179..9a0cb0c35ce 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -974,11 +974,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
if (value->is_single_allocated) {
- return scope.construct<GVArrayForSingleValueRef>(
+ return scope.construct<GVArray_For_SingleValueRef>(
__func__, value->span.type(), min_array_size_, value->span.data());
}
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
@@ -987,11 +987,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS
if (any_value->type == ValueType::OutputSingle) {
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
BLI_assert(false);
- return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
+ return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
}
const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket,
@@ -1004,7 +1004,7 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
BLI_assert(value->span.size() == 1);
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
@@ -1015,11 +1015,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
BLI_assert(value->span.size() == 1);
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
BLI_assert(false);
- return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
+ return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
}
const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
@@ -1033,10 +1033,10 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
if (value->vector_array->size() == 1) {
GSpan span = (*value->vector_array)[0];
- return scope.construct<GVVectorArrayForSingleGSpan>(__func__, span, min_array_size_);
+ return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, span, min_array_size_);
}
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
@@ -1044,11 +1044,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
}
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
- return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
+ return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
}
const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
@@ -1061,7 +1061,7 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
if (any_value->type == ValueType::OwnVector) {
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
@@ -1071,11 +1071,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
- return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
+ return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
}
/** \} */
diff --git a/source/blender/functions/tests/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc
index 51e116b5983..7b9738e5ca4 100644
--- a/source/blender/functions/tests/FN_multi_function_network_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_network_test.cc
@@ -223,7 +223,7 @@ TEST(multi_function_network, Test2)
Array<int> output_value_2(5, -1);
MFParamsBuilder params(network_fn, 5);
- GVVectorArrayForSingleGSpan inputs_1{input_value_1.as_span(), 5};
+ GVVectorArray_For_SingleGSpan inputs_1{input_value_1.as_span(), 5};
params.add_readonly_vector_input(inputs_1);
params.add_readonly_single_input(&input_value_2);
params.add_vector_output(output_value_1);
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 8facdca2f9c..bf7b9d70fb6 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -47,7 +47,7 @@ struct Curve;
#define GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE M_PI_2
#define GPENCIL_MIN_FILL_FAC 0.05f
-#define GPENCIL_MAX_FILL_FAC 5.0f
+#define GPENCIL_MAX_FILL_FAC 8.0f
/* ***************************************** */
/* GP Stroke Points */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 282d71f6a87..f57515c0e93 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1308,6 +1308,11 @@ typedef struct NodeGeometryMeshLine {
uint8_t count_mode;
} NodeGeometryMeshLine;
+typedef struct NodeSwitch {
+ /* NodeSwitch. */
+ uint8_t input_type;
+} NodeSwitch;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index ab74282eb64..cf3e31f7d9a 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1911,7 +1911,7 @@ typedef struct SpaceSpreadsheet {
/**
* List of #SpreadsheetContext.
* This is a path to the data that is displayed in the spreadsheet.
- * It can be set explicitely by an action of the user (e.g. clicking the preview icon in a
+ * It can be set explicitly by an action of the user (e.g. clicking the preview icon in a
* geometry node) or it can be derived from context automatically based on some heuristic.
*/
ListBase context_path;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 657af98f5fe..4fe19493614 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -148,6 +148,8 @@ static const EnumPropertyItem rna_enum_override_library_property_operation_items
# include "DEG_depsgraph_build.h"
# include "DEG_depsgraph_query.h"
+# include "ED_asset.h"
+
# include "WM_api.h"
void rna_ID_override_library_property_operation_refname_get(PointerRNA *ptr, char *value)
@@ -575,6 +577,22 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return newid;
}
+static void rna_ID_asset_mark(ID *id, bContext *C)
+{
+ if (ED_asset_mark_id(C, id)) {
+ WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_ADDED, NULL);
+ }
+}
+
+static void rna_ID_asset_clear(ID *id)
+{
+ if (ED_asset_clear_id(id)) {
+ WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_REMOVED, NULL);
+ }
+}
+
static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
{
if (!ID_IS_OVERRIDABLE_LIBRARY(id)) {
@@ -1716,6 +1734,18 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "asset_mark", "rna_ID_asset_mark");
+ RNA_def_function_ui_description(
+ func,
+ "Enable easier reuse of the data-block through the Asset Browser, with the help of "
+ "customizable metadata (like previews, descriptions and tags)");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+
+ func = RNA_def_function(srna, "asset_clear", "rna_ID_asset_clear");
+ RNA_def_function_ui_description(
+ func,
+ "Delete all asset metadata and turn the asset data-block back into a normal data-block");
+
func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
RNA_def_function_ui_description(func,
"Create an overridden local copy of this linked data-block (not "
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index b0254ce2ef3..1da711f260c 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -65,6 +65,20 @@
const EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
{SOCK_IN, "IN", 0, "Input", ""}, {SOCK_OUT, "OUT", 0, "Output", ""}, {0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem node_socket_data_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_INT, "INT", 0, "Int", ""},
+ {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_STRING, "STRING", 0, "String", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
+ {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem rna_enum_node_socket_display_shape_items[] = {
{SOCK_DISPLAY_SHAPE_CIRCLE, "CIRCLE", 0, "Circle", ""},
@@ -1913,6 +1927,29 @@ static const EnumPropertyItem *itemf_function_check(
return item_array;
}
+static bool switch_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value,
+ SOCK_FLOAT,
+ SOCK_INT,
+ SOCK_BOOLEAN,
+ SOCK_VECTOR,
+ SOCK_STRING,
+ SOCK_RGBA,
+ SOCK_GEOMETRY,
+ SOCK_OBJECT,
+ SOCK_COLLECTION);
+}
+
+static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(node_socket_data_type_items, switch_type_supported);
+}
+
static bool attribute_clamp_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
@@ -9630,6 +9667,19 @@ static void def_geo_mesh_line(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_switch(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeSwitch", "storage");
+ prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "input_type");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeSwitch_type_itemf");
+ RNA_def_property_ui_text(prop, "Input Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 6b93a1c223c..3edfd5c44f4 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -84,7 +84,7 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
{OB_MODE_PAINT_GPENCIL,
"PAINT_GPENCIL",
ICON_GREASEPENCIL,
- "Draw",
+ "Draw Mode",
"Paint Grease Pencil Strokes"},
{OB_MODE_WEIGHT_GPENCIL,
"WEIGHT_GPENCIL",
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 26887b51f81..bacd3943141 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6160,7 +6160,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
prop,
"Python Scripts Directory",
"Alternate script path, matching the default layout with subdirectories: "
- "startup, add-ons and modules (requires restart)");
+ "startup, addons, modules, and presets (requires restart)");
/* TODO, editing should reset sys.path! */
prop = RNA_def_property(srna, "i18n_branches_directory", PROP_STRING, PROP_DIRPATH);
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index ea31bdc6e31..71ecc69eccb 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -21,10 +21,9 @@
* \ingroup modifiers
*/
-#include "BLI_utildefines.h"
-
#include "BLI_math.h"
-
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
@@ -57,6 +56,21 @@
#define BEND_EPS 0.000001f
+ALIGN_STRUCT struct DeformUserData {
+ bool invert_vgroup;
+ char mode;
+ char deform_axis;
+ int lock_axis;
+ int vgroup;
+ int limit_axis;
+ float weight;
+ float smd_factor;
+ float smd_limit[2];
+ float (*vertexCos)[3];
+ const SpaceTransform *transf;
+ const MDeformVert *dvert;
+};
+
/* Re-maps the indices for X Y Z by shifting them up and wrapping, such that
* X = Y, Y = Z, Z = X (for X axis), and X = Z, Y = X, Z = Y (for Y axis). This
* exists because the deformations (excluding bend) are based on the Z axis.
@@ -203,6 +217,88 @@ static void simpleDeform_bend(const float factor,
}
}
+static void simple_helper(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ const struct DeformUserData *curr_deform_data = userdata;
+ float weight = BKE_defvert_array_find_weight_safe(
+ curr_deform_data->dvert, iter, curr_deform_data->vgroup);
+ const uint *axis_map = axis_map_table[(curr_deform_data->mode != MOD_SIMPLEDEFORM_MODE_BEND) ?
+ curr_deform_data->deform_axis :
+ 2];
+ const float base_limit[2] = {0.0f, 0.0f};
+
+ if (curr_deform_data->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight != 0.0f) {
+ float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
+
+ if (curr_deform_data->transf) {
+ BLI_space_transform_apply(curr_deform_data->transf, curr_deform_data->vertexCos[iter]);
+ }
+
+ copy_v3_v3(co, curr_deform_data->vertexCos[iter]);
+
+ /* Apply axis limits, and axis mappings */
+ if (curr_deform_data->lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
+ axis_limit(0, base_limit, co, dcut);
+ }
+ if (curr_deform_data->lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
+ axis_limit(1, base_limit, co, dcut);
+ }
+ if (curr_deform_data->lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
+ axis_limit(2, base_limit, co, dcut);
+ }
+ axis_limit(curr_deform_data->limit_axis, curr_deform_data->smd_limit, co, dcut);
+
+ /* apply the deform to a mapped copy of the vertex, and then re-map it back. */
+ float co_remap[3];
+ float dcut_remap[3];
+ copy_v3_v3_map(co_remap, co, axis_map);
+ copy_v3_v3_map(dcut_remap, dcut, axis_map);
+ switch (curr_deform_data->mode) {
+ case MOD_SIMPLEDEFORM_MODE_TWIST:
+ simpleDeform_twist(curr_deform_data->smd_factor,
+ curr_deform_data->deform_axis,
+ dcut_remap,
+ co_remap); /* apply deform */
+ break;
+ case MOD_SIMPLEDEFORM_MODE_BEND:
+ simpleDeform_bend(curr_deform_data->smd_factor,
+ curr_deform_data->deform_axis,
+ dcut_remap,
+ co_remap); /* apply deform */
+ break;
+ case MOD_SIMPLEDEFORM_MODE_TAPER:
+ simpleDeform_taper(curr_deform_data->smd_factor,
+ curr_deform_data->deform_axis,
+ dcut_remap,
+ co_remap); /* apply deform */
+ break;
+ case MOD_SIMPLEDEFORM_MODE_STRETCH:
+ simpleDeform_stretch(curr_deform_data->smd_factor,
+ curr_deform_data->deform_axis,
+ dcut_remap,
+ co_remap); /* apply deform */
+ break;
+ default:
+ return; /* No simple-deform mode? */
+ }
+ copy_v3_v3_unmap(co, co_remap, axis_map);
+
+ /* Use vertex weight has coef of linear interpolation */
+ interp_v3_v3v3(
+ curr_deform_data->vertexCos[iter], curr_deform_data->vertexCos[iter], co, weight);
+
+ if (curr_deform_data->transf) {
+ BLI_space_transform_invert(curr_deform_data->transf, curr_deform_data->vertexCos[iter]);
+ }
+ }
+}
+
/* simple deform modifier */
static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
const ModifierEvalContext *UNUSED(ctx),
@@ -211,14 +307,9 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
float (*vertexCos)[3],
int numVerts)
{
- const float base_limit[2] = {0.0f, 0.0f};
int i;
float smd_limit[2], smd_factor;
SpaceTransform *transf = NULL, tmp_transf;
- void (*simpleDeform_callback)(const float factor,
- const int axis,
- const float dcut[3],
- float co[3]) = NULL; /* Mode callback */
int vgroup;
MDeformVert *dvert;
@@ -300,23 +391,6 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
smd_factor = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]);
}
- switch (smd->mode) {
- case MOD_SIMPLEDEFORM_MODE_TWIST:
- simpleDeform_callback = simpleDeform_twist;
- break;
- case MOD_SIMPLEDEFORM_MODE_BEND:
- simpleDeform_callback = simpleDeform_bend;
- break;
- case MOD_SIMPLEDEFORM_MODE_TAPER:
- simpleDeform_callback = simpleDeform_taper;
- break;
- case MOD_SIMPLEDEFORM_MODE_STRETCH:
- simpleDeform_callback = simpleDeform_stretch;
- break;
- default:
- return; /* No simple-deform mode? */
- }
-
if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) {
if (fabsf(smd_factor) < BEND_EPS) {
return;
@@ -325,53 +399,26 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
MOD_get_vgroup(ob, mesh, smd->vgroup_name, &dvert, &vgroup);
const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
- const uint *axis_map =
- axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2];
-
- for (i = 0; i < numVerts; i++) {
- float weight = BKE_defvert_array_find_weight_safe(dvert, i, vgroup);
-
- if (invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight != 0.0f) {
- float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
- if (transf) {
- BLI_space_transform_apply(transf, vertexCos[i]);
- }
-
- copy_v3_v3(co, vertexCos[i]);
-
- /* Apply axis limits, and axis mappings */
- if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) {
- axis_limit(0, base_limit, co, dcut);
- }
- if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) {
- axis_limit(1, base_limit, co, dcut);
- }
- if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) {
- axis_limit(2, base_limit, co, dcut);
- }
- axis_limit(limit_axis, smd_limit, co, dcut);
-
- /* apply the deform to a mapped copy of the vertex, and then re-map it back. */
- float co_remap[3];
- float dcut_remap[3];
- copy_v3_v3_map(co_remap, co, axis_map);
- copy_v3_v3_map(dcut_remap, dcut, axis_map);
- simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */
- copy_v3_v3_unmap(co, co_remap, axis_map);
-
- /* Use vertex weight has coef of linear interpolation */
- interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight);
-
- if (transf) {
- BLI_space_transform_invert(transf, vertexCos[i]);
- }
- }
- }
+ /* Build our data. */
+ const struct DeformUserData deform_pool_data = {
+ .mode = smd->mode,
+ .smd_factor = smd_factor,
+ .deform_axis = deform_axis,
+ .transf = transf,
+ .vertexCos = vertexCos,
+ .invert_vgroup = invert_vgroup,
+ .lock_axis = lock_axis,
+ .vgroup = vgroup,
+ .smd_limit[0] = smd_limit[0],
+ .smd_limit[1] = smd_limit[1],
+ .dvert = dvert,
+ .limit_axis = limit_axis,
+ };
+ /* Do deformation. */
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, numVerts, (void *)&deform_pool_data, simple_helper, &settings);
}
/* SimpleDeform */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 8168f0dba73..7a966b660b4 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -180,6 +180,7 @@ set(SRC
geometry/nodes/node_geo_points_to_volume.cc
geometry/nodes/node_geo_subdivide.cc
geometry/nodes/node_geo_subdivision_surface.cc
+ geometry/nodes/node_geo_switch.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
geometry/nodes/node_geo_volume_to_mesh.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index b84c80e916c..74d77787eea 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -69,6 +69,7 @@ void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_sample_texture(void);
void register_node_type_geo_subdivide(void);
void register_node_type_geo_subdivision_surface(void);
+void register_node_type_geo_switch(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_volume_to_mesh(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 5d1a217db9b..f2582600c7d 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -33,29 +33,28 @@ struct ModifierData;
namespace blender::nodes {
-using bke::BooleanReadAttribute;
-using bke::BooleanWriteAttribute;
-using bke::Color4fReadAttribute;
-using bke::Color4fWriteAttribute;
-using bke::Float2ReadAttribute;
-using bke::Float2WriteAttribute;
-using bke::Float3ReadAttribute;
-using bke::Float3WriteAttribute;
-using bke::FloatReadAttribute;
-using bke::FloatWriteAttribute;
using bke::geometry_set_realize_instances;
-using bke::Int32ReadAttribute;
-using bke::Int32WriteAttribute;
+using bke::OutputAttribute;
+using bke::OutputAttribute_Typed;
using bke::PersistentDataHandleMap;
using bke::PersistentObjectHandle;
-using bke::ReadAttribute;
-using bke::ReadAttributePtr;
-using bke::WriteAttribute;
-using bke::WriteAttributePtr;
+using bke::ReadAttributeLookup;
+using bke::WriteAttributeLookup;
using fn::CPPType;
using fn::GMutablePointer;
+using fn::GMutableSpan;
using fn::GPointer;
+using fn::GSpan;
using fn::GValueMap;
+using fn::GVArray;
+using fn::GVArray_GSpan;
+using fn::GVArray_Span;
+using fn::GVArray_Typed;
+using fn::GVArrayPtr;
+using fn::GVMutableArray;
+using fn::GVMutableArray_GSpan;
+using fn::GVMutableArray_Typed;
+using fn::GVMutableArrayPtr;
class GeoNodeExecParams {
private:
@@ -217,20 +216,21 @@ class GeoNodeExecParams {
* \note This will add an error message if the string socket is active and
* the input attribute does not exist.
*/
- ReadAttributePtr get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const;
+ GVArrayPtr get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const CustomDataType type,
+ const void *default_value) const;
template<typename T>
- bke::TypedReadAttribute<T> get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const T &default_value) const
+ GVArray_Typed<T> get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const T &default_value) const
{
const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
- return this->get_input_attribute(name, component, domain, type, &default_value);
+ GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value);
+ return GVArray_Typed<T>(std::move(varray));
}
/**
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index bf6bf34325a..12e14768c35 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -310,6 +310,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", Me
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "ATTRIBUTE_CLAMP", AttributeClamp, "Attribute Clamp", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
+DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh
index 34225208fe6..ec4859f0657 100644
--- a/source/blender/nodes/NOD_type_conversions.hh
+++ b/source/blender/nodes/NOD_type_conversions.hh
@@ -72,6 +72,10 @@ class DataTypeConversions {
const CPPType &to_type,
const void *from_value,
void *to_value) const;
+
+ fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const;
+
+ fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const;
};
const DataTypeConversions &get_implicit_type_conversions();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
index f10b81a33b4..c4d37a82617 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
@@ -50,10 +50,10 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
namespace blender::nodes {
-static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors,
- const FloatReadAttribute &factors,
+static void align_rotations_auto_pivot(const VArray<float3> &vectors,
+ const VArray<float> &factors,
const float3 local_main_axis,
- MutableSpan<float3> rotations)
+ const MutableSpan<float3> rotations)
{
for (const int i : IndexRange(vectors.size())) {
const float3 vector = vectors[i];
@@ -93,11 +93,11 @@ static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors,
}
}
-static void align_rotations_fixed_pivot(const Float3ReadAttribute &vectors,
- const FloatReadAttribute &factors,
+static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
+ const VArray<float> &factors,
const float3 local_main_axis,
const float3 local_pivot_axis,
- MutableSpan<float3> rotations)
+ const MutableSpan<float3> rotations)
{
if (local_main_axis == local_pivot_axis) {
/* Can't compute any meaningful rotation angle in this case. */
@@ -144,30 +144,30 @@ static void align_rotations_on_component(GeometryComponent &component,
const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *)
node.storage;
- OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- if (!rotation_attribute) {
+ OutputAttribute_Typed<float3> rotations = component.attribute_try_get_for_output<float3>(
+ "rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
+ if (!rotations) {
return;
}
- MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
- FloatReadAttribute factors = params.get_input_attribute<float>(
+ GVArray_Typed<float> factors = params.get_input_attribute<float>(
"Factor", component, ATTR_DOMAIN_POINT, 1.0f);
- Float3ReadAttribute vectors = params.get_input_attribute<float3>(
+ GVArray_Typed<float3> vectors = params.get_input_attribute<float3>(
"Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1});
float3 local_main_axis{0, 0, 0};
local_main_axis[storage.axis] = 1;
if (storage.pivot_axis == GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO) {
- align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations);
+ align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations.as_span());
}
else {
float3 local_pivot_axis{0, 0, 0};
local_pivot_axis[storage.pivot_axis - 1] = 1;
- align_rotations_fixed_pivot(vectors, factors, local_main_axis, local_pivot_axis, rotations);
+ align_rotations_fixed_pivot(
+ vectors, factors, local_main_axis, local_pivot_axis, rotations.as_span());
}
- rotation_attribute.apply_span_and_save();
+ rotations.save();
}
static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
index 95fa24c8bac..1943971d49f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
@@ -112,10 +112,13 @@ template<> inline Color4f clamp_value(const Color4f val, const Color4f min, cons
}
template<typename T>
-static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max)
+static void clamp_attribute(const VArray<T> &inputs,
+ const MutableSpan<T> outputs,
+ const T min,
+ const T max)
{
- for (const int i : span.index_range()) {
- span[i] = clamp_value<T>(read_span[i], min, max);
+ for (const int i : IndexRange(outputs.size())) {
+ outputs[i] = clamp_value<T>(inputs[i], min, max);
}
}
@@ -123,13 +126,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
- if (source_attribute) {
- return source_attribute->domain();
+ std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(source_name);
+ if (source_info) {
+ return source_info->domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -154,10 +157,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
const AttributeDomain domain = get_result_domain(component, attribute_name, result_name);
const int operation = static_cast<int>(storage.operation);
- ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
+ GVArrayPtr attribute_input = component.attribute_try_get_for_read(
attribute_name, domain, data_type);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, domain, data_type);
if (!attribute_result) {
@@ -169,8 +172,6 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
switch (data_type) {
case CD_PROP_FLOAT3: {
- Span<float3> read_span = attribute_input->get_span<float3>();
- MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>();
float3 min = params.get_input<float3>("Min");
float3 max = params.get_input<float3>("Max");
if (operation == NODE_CLAMP_RANGE) {
@@ -184,38 +185,35 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.z, max.z);
}
}
- clamp_attribute<float3>(read_span, span, min, max);
+ MutableSpan<float3> results = attribute_result.as_span<float3>();
+ clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max);
break;
}
case CD_PROP_FLOAT: {
- Span<float> read_span = attribute_input->get_span<float>();
- MutableSpan<float> span = attribute_result->get_span_for_write_only<float>();
const float min = params.get_input<float>("Min_001");
const float max = params.get_input<float>("Max_001");
+ MutableSpan<float> results = attribute_result.as_span<float>();
if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<float>(read_span, span, max, min);
+ clamp_attribute<float>(attribute_input->typed<float>(), results, max, min);
}
else {
- clamp_attribute<float>(read_span, span, min, max);
+ clamp_attribute<float>(attribute_input->typed<float>(), results, min, max);
}
break;
}
case CD_PROP_INT32: {
- Span<int> read_span = attribute_input->get_span<int>();
- MutableSpan<int> span = attribute_result->get_span_for_write_only<int>();
const int min = params.get_input<int>("Min_002");
const int max = params.get_input<int>("Max_002");
+ MutableSpan<int> results = attribute_result.as_span<int>();
if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<int>(read_span, span, max, min);
+ clamp_attribute<int>(attribute_input->typed<int>(), results, max, min);
}
else {
- clamp_attribute<int>(read_span, span, min, max);
+ clamp_attribute<int>(attribute_input->typed<int>(), results, min, max);
}
break;
}
case CD_PROP_COLOR: {
- Span<Color4f> read_span = attribute_input->get_span<Color4f>();
- MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>();
Color4f min = params.get_input<Color4f>("Min_003");
Color4f max = params.get_input<Color4f>("Max_003");
if (operation == NODE_CLAMP_RANGE) {
@@ -232,7 +230,8 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.a, max.a);
}
}
- clamp_attribute<Color4f>(read_span, span, min, max);
+ MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
+ clamp_attribute<Color4f>(attribute_input->typed<Color4f>(), results, min, max);
break;
}
default: {
@@ -241,7 +240,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
}
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index 2b913beb670..9e697226a01 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -47,15 +47,15 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the input attribute's domain if it exists. */
- ReadAttributePtr input_attribute = component.attribute_try_get_for_read(input_name);
- if (input_attribute) {
- return input_attribute->domain();
+ std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(input_name);
+ if (source_info) {
+ return source_info->domain;
}
return ATTR_DOMAIN_POINT;
@@ -71,27 +71,25 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
/* Always output a color attribute for now. We might want to allow users to customize.
* Using the type of an existing attribute could work, but does not have a real benefit
* currently. */
- const CustomDataType result_type = CD_PROP_COLOR;
const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, result_type);
+ OutputAttribute_Typed<Color4f> attribute_result =
+ component.attribute_try_get_for_output_only<Color4f>(result_name, result_domain);
if (!attribute_result) {
return;
}
- FloatReadAttribute attribute_in = component.attribute_get_for_read<float>(
+ GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
- Span<float> data_in = attribute_in.get_span();
- MutableSpan<Color4f> data_out = attribute_result->get_span_for_write_only<Color4f>();
+ MutableSpan<Color4f> results = attribute_result.as_span();
ColorBand *color_ramp = &node_storage->color_ramp;
- for (const int i : data_in.index_range()) {
- BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]);
+ for (const int i : IndexRange(attribute_in.size())) {
+ BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
index e9e07d34c17..d7ed8b6caf8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
@@ -77,9 +77,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -94,27 +94,25 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
}
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> attribute_result =
+ component.attribute_try_get_for_output_only<float3>(result_name, result_domain);
if (!attribute_result) {
return;
}
- FloatReadAttribute attribute_x = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_x = params.get_input_attribute<float>(
"X", component, result_domain, 0.0f);
- FloatReadAttribute attribute_y = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_y = params.get_input_attribute<float>(
"Y", component, result_domain, 0.0f);
- FloatReadAttribute attribute_z = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_z = params.get_input_attribute<float>(
"Z", component, result_domain, 0.0f);
- MutableSpan<float3> results = attribute_result->get_span_for_write_only<float3>();
- for (const int i : results.index_range()) {
+ for (const int i : IndexRange(attribute_result->size())) {
const float x = attribute_x[i];
const float y = attribute_y[i];
const float z = attribute_z[i];
- const float3 result = float3(x, y, z);
- results[i] = result;
+ attribute_result->set(i, {x, y, z});
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
index fe4045c39a6..ccfaeb9bb47 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
@@ -81,21 +81,18 @@ static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *n
nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage));
}
-static void do_math_operation(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
+static void do_math_operation(const VArray<float> &input_a,
+ const VArray<float> &input_b,
const FloatCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
- Span<float> span_a = input_a.get_span();
- Span<float> span_b = input_b.get_span();
-
if (try_dispatch_float_math_fl_fl_to_bool(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
for (const int i : IndexRange(size)) {
- const float a = span_a[i];
- const float b = span_b[i];
+ const float a = input_a[i];
+ const float b = input_b[i];
const bool out = math_function(a, b);
span_result[i] = out;
}
@@ -107,8 +104,8 @@ static void do_math_operation(const FloatReadAttribute &input_a,
BLI_assert(false);
}
-static void do_equal_operation_float(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
+static void do_equal_operation_float(const VArray<float> &input_a,
+ const VArray<float> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -120,8 +117,8 @@ static void do_equal_operation_float(const FloatReadAttribute &input_a,
}
}
-static void do_equal_operation_float3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
+static void do_equal_operation_float3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -134,8 +131,8 @@ static void do_equal_operation_float3(const Float3ReadAttribute &input_a,
}
}
-static void do_equal_operation_color4f(const Color4fReadAttribute &input_a,
- const Color4fReadAttribute &input_b,
+static void do_equal_operation_color4f(const VArray<Color4f> &input_a,
+ const VArray<Color4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -148,8 +145,8 @@ static void do_equal_operation_color4f(const Color4fReadAttribute &input_a,
}
}
-static void do_equal_operation_bool(const BooleanReadAttribute &input_a,
- const BooleanReadAttribute &input_b,
+static void do_equal_operation_bool(const VArray<bool> &input_a,
+ const VArray<bool> &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
@@ -161,8 +158,8 @@ static void do_equal_operation_bool(const BooleanReadAttribute &input_a,
}
}
-static void do_not_equal_operation_float(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
+static void do_not_equal_operation_float(const VArray<float> &input_a,
+ const VArray<float> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -174,8 +171,8 @@ static void do_not_equal_operation_float(const FloatReadAttribute &input_a,
}
}
-static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
+static void do_not_equal_operation_float3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -188,8 +185,8 @@ static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a,
}
}
-static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a,
- const Color4fReadAttribute &input_b,
+static void do_not_equal_operation_color4f(const VArray<Color4f> &input_a,
+ const VArray<Color4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -202,8 +199,8 @@ static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a,
}
}
-static void do_not_equal_operation_bool(const BooleanReadAttribute &input_a,
- const BooleanReadAttribute &input_b,
+static void do_not_equal_operation_bool(const VArray<bool> &input_a,
+ const VArray<bool> &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
@@ -237,9 +234,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -254,20 +251,19 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
node_storage->operation);
const std::string result_name = params.get_input<std::string>("Result");
- const CustomDataType result_type = CD_PROP_BOOL;
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, result_type);
+ OutputAttribute_Typed<bool> attribute_result = component.attribute_try_get_for_output_only<bool>(
+ result_name, result_domain);
if (!attribute_result) {
return;
}
const CustomDataType input_data_type = get_data_type(component, params, *node_storage);
- ReadAttributePtr attribute_a = params.get_input_attribute(
+ GVArrayPtr attribute_a = params.get_input_attribute(
"A", component, result_domain, input_data_type, nullptr);
- ReadAttributePtr attribute_b = params.get_input_attribute(
+ GVArrayPtr attribute_b = params.get_input_attribute(
"B", component, result_domain, input_data_type, nullptr);
if (!attribute_a || !attribute_b) {
@@ -275,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
return;
}
- MutableSpan<bool> result_span = attribute_result->get_span_for_write_only<bool>();
+ MutableSpan<bool> result_span = attribute_result.as_span();
/* Use specific types for correct equality operations, but for other operations we use implicit
* conversions and float comparison. In other words, the comparison is not element-wise. */
@@ -283,38 +279,47 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
const float threshold = params.get_input<float>("Threshold");
if (operation == NODE_FLOAT_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
- do_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_float(
+ attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
- do_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_float3(
+ attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_color4f(
+ attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
- do_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_bool(
+ attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
}
}
else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
- do_not_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_float(
+ attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
- do_not_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_float3(
+ attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_not_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_color4f(
+ attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
- do_not_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_bool(
+ attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
}
}
}
else {
- do_math_operation(*attribute_a, *attribute_b, operation, result_span);
+ do_math_operation(
+ attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span);
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
index 19c3aaa9c85..60bb27191b4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
@@ -55,13 +55,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
- if (source_attribute) {
- return source_attribute->domain();
+ std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(source_name);
+ if (source_info) {
+ return source_info->domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -75,14 +75,14 @@ static bool conversion_can_be_skipped(const GeometryComponent &component,
if (source_name != result_name) {
return false;
}
- ReadAttributePtr read_attribute = component.attribute_try_get_for_read(source_name);
- if (!read_attribute) {
+ std::optional<AttributeMetaData> info = component.attribute_get_meta_data(result_name);
+ if (!info) {
return false;
}
- if (read_attribute->domain() != result_domain) {
+ if (info->domain != result_domain) {
return false;
}
- if (read_attribute->cpp_type() != *bke::custom_data_type_to_cpp_type(result_type)) {
+ if (info->data_type != result_type) {
return false;
}
return true;
@@ -104,7 +104,7 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
+ GVArrayPtr source_attribute = component.attribute_try_get_for_read(
source_name, result_domain, result_type);
if (!source_attribute) {
params.error_message_add(NodeWarningType::Error,
@@ -112,25 +112,22 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
- OutputAttributePtr result_attribute = component.attribute_try_get_for_output(
+ OutputAttribute result_attribute = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!result_attribute) {
return;
}
- fn::GSpan source_span = source_attribute->get_span();
- fn::GMutableSpan result_span = result_attribute->get_span_for_write_only();
- if (source_span.is_empty() || result_span.is_empty()) {
- return;
- }
+ GVArray_GSpan source_span{*source_attribute};
+ GMutableSpan result_span = result_attribute.as_span();
+
BLI_assert(source_span.size() == result_span.size());
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(result_type);
BLI_assert(cpp_type != nullptr);
cpp_type->copy_to_initialized_n(source_span.data(), result_span.data(), result_span.size());
-
- result_attribute.apply_span_and_save();
+ result_attribute.save();
}
static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index 7b4483a31a1..3df64625b99 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -68,13 +68,12 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node
namespace blender::nodes {
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- StringRef attribute_name)
+static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(name);
+ if (result_info) {
+ return result_info->domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -93,7 +92,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
get_result_domain(component, attribute_name) :
domain;
- OutputAttributePtr attribute = component.attribute_try_get_for_output(
+ OutputAttribute attribute = component.attribute_try_get_for_output_only(
attribute_name, result_domain, data_type);
if (!attribute) {
return;
@@ -102,38 +101,34 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
switch (data_type) {
case CD_PROP_FLOAT: {
const float value = params.get_input<float>("Value_001");
- MutableSpan<float> attribute_span = attribute->get_span_for_write_only<float>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_FLOAT3: {
const float3 value = params.get_input<float3>("Value");
- MutableSpan<float3> attribute_span = attribute->get_span_for_write_only<float3>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_COLOR: {
const Color4f value = params.get_input<Color4f>("Value_002");
- MutableSpan<Color4f> attribute_span = attribute->get_span_for_write_only<Color4f>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_BOOL: {
const bool value = params.get_input<bool>("Value_003");
- MutableSpan<bool> attribute_span = attribute->get_span_for_write_only<bool>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_INT32: {
const int value = params.get_input<int>("Value_004");
- MutableSpan<int> attribute_span = attribute->get_span_for_write_only<int>();
- attribute_span.fill(value);
+ attribute->fill(&value);
+ break;
}
default:
break;
}
- attribute.apply_span_and_save();
+ attribute.save();
}
static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
index fdbdadf90b6..5d82897e9db 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
@@ -192,8 +192,8 @@ static float map_smootherstep(const float value,
return min_to + factor_mapped * (max_to - min_to);
}
-static void map_range_float(FloatReadAttribute attribute_input,
- FloatWriteAttribute attribute_result,
+static void map_range_float(const VArray<float> &attribute_input,
+ MutableSpan<float> results,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -204,32 +204,31 @@ static void map_range_float(FloatReadAttribute attribute_input,
const float min_to = params.get_input<float>("To Min");
const float max_to = params.get_input<float>("To Max");
- Span<float> span = attribute_input.get_span();
- MutableSpan<float> result_span = attribute_result.get_span();
+ VArray_Span<float> span{attribute_input};
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
for (int i : span.index_range()) {
- result_span[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
+ results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
}
break;
}
case NODE_MAP_RANGE_STEPPED: {
const float steps = params.get_input<float>("Steps");
for (int i : span.index_range()) {
- result_span[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
+ results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
}
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
for (int i : span.index_range()) {
- result_span[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
+ results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
}
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
for (int i : span.index_range()) {
- result_span[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
+ results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
}
break;
}
@@ -241,14 +240,14 @@ static void map_range_float(FloatReadAttribute attribute_input,
const float clamp_min = min_to < max_to ? min_to : max_to;
const float clamp_max = min_to < max_to ? max_to : min_to;
- for (int i : result_span.index_range()) {
- result_span[i] = std::clamp(result_span[i], clamp_min, clamp_max);
+ for (int i : results.index_range()) {
+ results[i] = std::clamp(results[i], clamp_min, clamp_max);
}
}
}
-static void map_range_float3(Float3ReadAttribute attribute_input,
- Float3WriteAttribute attribute_result,
+static void map_range_float3(const VArray<float3> &attribute_input,
+ const MutableSpan<float3> results,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -259,43 +258,39 @@ static void map_range_float3(Float3ReadAttribute attribute_input,
const float3 min_to = params.get_input<float3>("To Min_001");
const float3 max_to = params.get_input<float3>("To Max_001");
- Span<float3> span = attribute_input.get_span();
- MutableSpan<float3> result_span = attribute_result.get_span();
+ VArray_Span<float3> span{attribute_input};
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
for (int i : span.index_range()) {
- result_span[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- result_span[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- result_span[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
+ results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
+ results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
+ results[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
case NODE_MAP_RANGE_STEPPED: {
const float3 steps = params.get_input<float3>("Steps_001");
for (int i : span.index_range()) {
- result_span[i].x = map_stepped(
- span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
- result_span[i].y = map_stepped(
- span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
- result_span[i].z = map_stepped(
- span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
+ results[i].x = map_stepped(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
+ results[i].y = map_stepped(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
+ results[i].z = map_stepped(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
}
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
for (int i : span.index_range()) {
- result_span[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- result_span[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- result_span[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
+ results[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
+ results[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
+ results[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
for (int i : span.index_range()) {
- result_span[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- result_span[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- result_span[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
+ results[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
+ results[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
+ results[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
@@ -313,8 +308,8 @@ static void map_range_float3(Float3ReadAttribute attribute_input,
clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z;
clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z;
- for (int i : result_span.index_range()) {
- clamp_v3_v3v3(result_span[i], clamp_min, clamp_max);
+ for (int i : results.index_range()) {
+ clamp_v3_v3v3(results[i], clamp_min, clamp_max);
}
}
}
@@ -323,13 +318,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
- if (source_attribute) {
- return source_attribute->domain();
+ std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(source_name);
+ if (source_info) {
+ return source_info->domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -349,8 +344,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
const AttributeDomain domain = get_result_domain(component, input_name, result_name);
- ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
- input_name, domain, data_type);
+ GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type);
if (!attribute_input) {
params.error_message_add(NodeWarningType::Error,
@@ -358,7 +352,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
return;
}
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, domain, data_type);
if (!attribute_result) {
params.error_message_add(NodeWarningType::Error,
@@ -369,18 +363,19 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
switch (data_type) {
case CD_PROP_FLOAT: {
- map_range_float(*attribute_input, *attribute_result, params);
+ map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params);
break;
}
case CD_PROP_FLOAT3: {
- map_range_float3(*attribute_input, *attribute_result, params);
+ map_range_float3(
+ attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params);
break;
}
default:
BLI_assert_unreachable();
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index 5ee31e78be2..00ae6b373b2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -149,9 +149,9 @@ static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node
operation_use_input_c(operation));
}
-static void do_math_operation(Span<float> span_a,
- Span<float> span_b,
- Span<float> span_c,
+static void do_math_operation(const VArray<float> &span_a,
+ const VArray<float> &span_b,
+ const VArray<float> &span_c,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -165,8 +165,8 @@ static void do_math_operation(Span<float> span_a,
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation(Span<float> span_a,
- Span<float> span_b,
+static void do_math_operation(const VArray<float> &span_a,
+ const VArray<float> &span_b,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -180,7 +180,7 @@ static void do_math_operation(Span<float> span_a,
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation(Span<float> span_input,
+static void do_math_operation(const VArray<float> &span_input,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -200,9 +200,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -224,56 +224,39 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
const std::string result_name = params.get_input<std::string>("Result");
/* The result type of this node is always float. */
- const CustomDataType result_type = CD_PROP_FLOAT;
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, result_type);
+ OutputAttribute_Typed<float> attribute_result =
+ component.attribute_try_get_for_output_only<float>(result_name, result_domain);
if (!attribute_result) {
return;
}
- ReadAttributePtr attribute_a = params.get_input_attribute(
- "A", component, result_domain, result_type, nullptr);
- if (!attribute_a) {
- return;
- }
+ GVArray_Typed<float> attribute_a = params.get_input_attribute<float>(
+ "A", component, result_domain, 0.0f);
- /* Note that passing the data with `get_span<float>()` works
+ MutableSpan<float> result_span = attribute_result.as_span();
+
+ /* Note that passing the data with `get_internal_span<float>()` works
* because the attributes were accessed with #CD_PROP_FLOAT. */
if (operation_use_input_b(operation)) {
- ReadAttributePtr attribute_b = params.get_input_attribute(
- "B", component, result_domain, result_type, nullptr);
- if (!attribute_b) {
- return;
- }
+ GVArray_Typed<float> attribute_b = params.get_input_attribute<float>(
+ "B", component, result_domain, 0.0f);
if (operation_use_input_c(operation)) {
- ReadAttributePtr attribute_c = params.get_input_attribute(
- "C", component, result_domain, result_type, nullptr);
- if (!attribute_c) {
- return;
- }
- do_math_operation(attribute_a->get_span<float>(),
- attribute_b->get_span<float>(),
- attribute_c->get_span<float>(),
- attribute_result->get_span_for_write_only<float>(),
- operation);
+ GVArray_Typed<float> attribute_c = params.get_input_attribute<float>(
+ "C", component, result_domain, 0.0f);
+ do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation);
}
else {
- do_math_operation(attribute_a->get_span<float>(),
- attribute_b->get_span<float>(),
- attribute_result->get_span_for_write_only<float>(),
- operation);
+ do_math_operation(attribute_a, attribute_b, result_span, operation);
}
}
else {
- do_math_operation(attribute_a->get_span<float>(),
- attribute_result->get_span_for_write_only<float>(),
- operation);
+ do_math_operation(attribute_a, result_span, operation);
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_math_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
index 9d8cd3dfa82..7129679117d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
@@ -58,10 +58,10 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C),
namespace blender::nodes {
static void do_mix_operation_float(const int blend_mode,
- const FloatReadAttribute &factors,
- const FloatReadAttribute &inputs_a,
- const FloatReadAttribute &inputs_b,
- FloatWriteAttribute results)
+ const VArray<float> &factors,
+ const VArray<float> &inputs_a,
+ const VArray<float> &inputs_b,
+ VMutableArray<float> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -75,10 +75,10 @@ static void do_mix_operation_float(const int blend_mode,
}
static void do_mix_operation_float3(const int blend_mode,
- const FloatReadAttribute &factors,
- const Float3ReadAttribute &inputs_a,
- const Float3ReadAttribute &inputs_b,
- Float3WriteAttribute results)
+ const VArray<float> &factors,
+ const VArray<float3> &inputs_a,
+ const VArray<float3> &inputs_b,
+ VMutableArray<float3> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -91,10 +91,10 @@ static void do_mix_operation_float3(const int blend_mode,
}
static void do_mix_operation_color4f(const int blend_mode,
- const FloatReadAttribute &factors,
- const Color4fReadAttribute &inputs_a,
- const Color4fReadAttribute &inputs_b,
- Color4fWriteAttribute results)
+ const VArray<float> &factors,
+ const VArray<Color4f> &inputs_a,
+ const VArray<Color4f> &inputs_b,
+ VMutableArray<Color4f> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -108,22 +108,31 @@ static void do_mix_operation_color4f(const int blend_mode,
static void do_mix_operation(const CustomDataType result_type,
int blend_mode,
- const FloatReadAttribute &attribute_factor,
- const ReadAttribute &attribute_a,
- const ReadAttribute &attribute_b,
- WriteAttribute &attribute_result)
+ const VArray<float> &attribute_factor,
+ const GVArray &attribute_a,
+ const GVArray &attribute_b,
+ GVMutableArray &attribute_result)
{
if (result_type == CD_PROP_FLOAT) {
- do_mix_operation_float(
- blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
+ do_mix_operation_float(blend_mode,
+ attribute_factor,
+ attribute_a.typed<float>(),
+ attribute_b.typed<float>(),
+ attribute_result.typed<float>());
}
else if (result_type == CD_PROP_FLOAT3) {
- do_mix_operation_float3(
- blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
+ do_mix_operation_float3(blend_mode,
+ attribute_factor,
+ attribute_a.typed<float3>(),
+ attribute_b.typed<float3>(),
+ attribute_result.typed<float3>());
}
else if (result_type == CD_PROP_COLOR) {
- do_mix_operation_color4f(
- blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
+ do_mix_operation_color4f(blend_mode,
+ attribute_factor,
+ attribute_a.typed<Color4f>(),
+ attribute_b.typed<Color4f>(),
+ attribute_result.typed<Color4f>());
}
}
@@ -132,9 +141,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -158,17 +167,17 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
}
- FloatReadAttribute attribute_factor = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>(
"Factor", component, result_domain, 0.5f);
- ReadAttributePtr attribute_a = params.get_input_attribute(
+ GVArrayPtr attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
- ReadAttributePtr attribute_b = params.get_input_attribute(
+ GVArrayPtr attribute_b = params.get_input_attribute(
"B", component, result_domain, result_type, nullptr);
do_mix_operation(result_type,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index f09a9bf056e..8e9892f00b6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -62,7 +62,7 @@ namespace blender::nodes {
static void proximity_calc(MutableSpan<float> distance_span,
MutableSpan<float3> location_span,
- Span<float3> positions,
+ const VArray<float3> &positions,
BVHTreeFromMesh &tree_data_mesh,
BVHTreeFromPointCloud &tree_data_pointcloud,
const bool bvh_mesh_success,
@@ -169,19 +169,18 @@ static void attribute_calc_proximity(GeometryComponent &component,
const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
const std::string distance_attribute_name = params.get_input<std::string>("Distance");
- OutputAttributePtr distance_attribute = component.attribute_try_get_for_output(
- distance_attribute_name, result_domain, CD_PROP_FLOAT);
+ OutputAttribute_Typed<float> distance_attribute =
+ component.attribute_try_get_for_output_only<float>(distance_attribute_name, result_domain);
const std::string location_attribute_name = params.get_input<std::string>("Position");
- OutputAttributePtr location_attribute = component.attribute_try_get_for_output(
- location_attribute_name, result_domain, CD_PROP_FLOAT3);
-
- ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
- BLI_assert(position_attribute->custom_data_type() == CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> location_attribute =
+ component.attribute_try_get_for_output_only<float3>(location_attribute_name, result_domain);
+ ReadAttributeLookup position_attribute = component.attribute_try_get_for_read("position");
if (!position_attribute || (!distance_attribute && !location_attribute)) {
return;
}
+ BLI_assert(position_attribute.varray->type().is<float3>());
const bNode &node = params.node();
const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)
@@ -204,18 +203,15 @@ static void attribute_calc_proximity(GeometryComponent &component,
tree_data_pointcloud);
}
- Span<float3> position_span = position_attribute->get_span<float3>();
-
- MutableSpan<float> distance_span = distance_attribute ?
- distance_attribute->get_span_for_write_only<float>() :
- MutableSpan<float>();
- MutableSpan<float3> location_span = location_attribute ?
- location_attribute->get_span_for_write_only<float3>() :
- MutableSpan<float3>();
+ GVArray_Typed<float3> positions{*position_attribute.varray};
+ MutableSpan<float> distance_span = distance_attribute ? distance_attribute.as_span() :
+ MutableSpan<float>();
+ MutableSpan<float3> location_span = location_attribute ? location_attribute.as_span() :
+ MutableSpan<float3>();
proximity_calc(distance_span,
location_span,
- position_span,
+ positions,
tree_data_mesh,
tree_data_pointcloud,
bvh_mesh_success,
@@ -231,10 +227,10 @@ static void attribute_calc_proximity(GeometryComponent &component,
}
if (distance_attribute) {
- distance_attribute.apply_span_and_save();
+ distance_attribute.save();
}
if (location_attribute) {
- location_attribute.apply_span_and_save();
+ location_attribute.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index 28263287a10..cc6aacaca79 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -173,12 +173,12 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
const int domain_size = component.attribute_domain_size(domain);
/* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
- ReadAttributePtr hash_attribute = component.attribute_try_get_for_read("id", domain);
+ GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain);
Array<uint32_t> hashes(domain_size);
if (hash_attribute) {
BLI_assert(hashes.size() == hash_attribute->size());
- const CPPType &cpp_type = hash_attribute->cpp_type();
- fn::GSpan items = hash_attribute->get_span();
+ const CPPType &cpp_type = hash_attribute->type();
+ GVArray_GSpan items{*hash_attribute};
for (const int i : hashes.index_range()) {
hashes[i] = cpp_type.hash(items[i]);
}
@@ -196,12 +196,12 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
static AttributeDomain get_result_domain(const GeometryComponent &component,
const GeoNodeExecParams &params,
- StringRef attribute_name)
+ const StringRef name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the input domain chosen in the interface. */
@@ -228,15 +228,13 @@ static void randomize_attribute_on_component(GeometryComponent &component,
const AttributeDomain domain = get_result_domain(component, params, attribute_name);
- OutputAttributePtr attribute = component.attribute_try_get_for_output(
+ OutputAttribute attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
if (!attribute) {
return;
}
- fn::GMutableSpan span = (operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) ?
- attribute->get_span_for_write_only() :
- attribute->get_span();
+ GMutableSpan span = attribute.as_span();
Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain);
@@ -269,8 +267,8 @@ static void randomize_attribute_on_component(GeometryComponent &component,
}
}
- attribute.apply_span_and_save();
-} // namespace blender::nodes
+ attribute.save();
+}
static void geo_node_random_attribute_exec(GeoNodeExecParams params)
{
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
index d0b2595b5b9..fa11ef936cd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -49,19 +49,19 @@ static void geo_node_attribute_sample_texture_layout(uiLayout *layout,
namespace blender::nodes {
static AttributeDomain get_result_domain(const GeometryComponent &component,
- StringRef result_attribute_name,
- StringRef map_attribute_name)
+ const StringRef result_name,
+ const StringRef map_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_attribute_name);
- if (result_attribute) {
- return result_attribute->domain();
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
/* Otherwise use the name of the map attribute. */
- ReadAttributePtr map_attribute = component.attribute_try_get_for_read(map_attribute_name);
- if (map_attribute) {
- return map_attribute->domain();
+ std::optional<AttributeMetaData> map_info = component.attribute_get_meta_data(map_name);
+ if (map_info) {
+ return map_info->domain;
}
/* The node won't execute in this case, but we still have to return a value. */
@@ -85,16 +85,16 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
const AttributeDomain result_domain = get_result_domain(
component, result_attribute_name, mapping_name);
- OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
- result_attribute_name, result_domain, CD_PROP_COLOR);
+ OutputAttribute_Typed<Color4f> attribute_out =
+ component.attribute_try_get_for_output_only<Color4f>(result_attribute_name, result_domain);
if (!attribute_out) {
return;
}
- Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, result_domain, {0, 0, 0});
- MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>();
+ MutableSpan<Color4f> colors = attribute_out.as_span();
for (const int i : IndexRange(mapping_attribute.size())) {
TexResult texture_result = {0};
const float3 position = mapping_attribute[i];
@@ -103,7 +103,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false);
colors[i] = {texture_result.tr, texture_result.tg, texture_result.tb, texture_result.ta};
}
- attribute_out.apply_span_and_save();
+ attribute_out.save();
}
static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
index 656dc51149e..bbc6cb71032 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
@@ -71,23 +71,23 @@ static void extract_input(const int index, const Span<float3> &input, MutableSpa
static AttributeDomain get_result_domain(const GeometryComponent &component,
const GeoNodeExecParams &params,
- StringRef result_name_x,
- StringRef result_name_y,
- StringRef result_name_z)
+ const StringRef name_x,
+ const StringRef name_y,
+ const StringRef name_z)
{
/* Use the highest priority domain from any existing attribute outputs. */
Vector<AttributeDomain, 3> output_domains;
- ReadAttributePtr attribute_x = component.attribute_try_get_for_read(result_name_x);
- ReadAttributePtr attribute_y = component.attribute_try_get_for_read(result_name_y);
- ReadAttributePtr attribute_z = component.attribute_try_get_for_read(result_name_z);
- if (attribute_x) {
- output_domains.append(attribute_x->domain());
+ std::optional<AttributeMetaData> info_x = component.attribute_get_meta_data(name_x);
+ std::optional<AttributeMetaData> info_y = component.attribute_get_meta_data(name_y);
+ std::optional<AttributeMetaData> info_z = component.attribute_get_meta_data(name_z);
+ if (info_x) {
+ output_domains.append(info_x->domain);
}
- if (attribute_y) {
- output_domains.append(attribute_y->domain());
+ if (info_y) {
+ output_domains.append(info_y->domain);
}
- if (attribute_z) {
- output_domains.append(attribute_z->domain());
+ if (info_z) {
+ output_domains.append(info_z->domain);
}
if (output_domains.size() > 0) {
return bke::attribute_domain_highest_priority(output_domains);
@@ -107,37 +107,32 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
}
/* The node is only for float3 to float conversions. */
- const CustomDataType input_type = CD_PROP_FLOAT3;
- const CustomDataType result_type = CD_PROP_FLOAT;
const AttributeDomain result_domain = get_result_domain(
component, params, result_name_x, result_name_y, result_name_z);
- ReadAttributePtr attribute_input = params.get_input_attribute(
- "Vector", component, result_domain, input_type, nullptr);
- if (!attribute_input) {
- return;
- }
- const Span<float3> input_span = attribute_input->get_span<float3>();
+ GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>(
+ "Vector", component, result_domain, {0, 0, 0});
+ VArray_Span<float3> input_span{*attribute_input};
- OutputAttributePtr attribute_result_x = component.attribute_try_get_for_output(
- result_name_x, result_domain, result_type);
- OutputAttributePtr attribute_result_y = component.attribute_try_get_for_output(
- result_name_y, result_domain, result_type);
- OutputAttributePtr attribute_result_z = component.attribute_try_get_for_output(
- result_name_z, result_domain, result_type);
+ OutputAttribute_Typed<float> attribute_result_x =
+ component.attribute_try_get_for_output_only<float>(result_name_x, result_domain);
+ OutputAttribute_Typed<float> attribute_result_y =
+ component.attribute_try_get_for_output_only<float>(result_name_y, result_domain);
+ OutputAttribute_Typed<float> attribute_result_z =
+ component.attribute_try_get_for_output_only<float>(result_name_z, result_domain);
/* Only extract the components for the outputs with a given attribute. */
if (attribute_result_x) {
- extract_input(0, input_span, attribute_result_x->get_span_for_write_only<float>());
- attribute_result_x.apply_span_and_save();
+ extract_input(0, input_span, attribute_result_x.as_span());
+ attribute_result_x.save();
}
if (attribute_result_y) {
- extract_input(1, input_span, attribute_result_y->get_span_for_write_only<float>());
- attribute_result_y.apply_span_and_save();
+ extract_input(1, input_span, attribute_result_y.as_span());
+ attribute_result_y.save();
}
if (attribute_result_z) {
- extract_input(2, input_span, attribute_result_z->get_span_for_write_only<float>());
- attribute_result_z.apply_span_and_save();
+ extract_input(2, input_span, attribute_result_z.as_span());
+ attribute_result_z.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
index 1ae095a27d2..86fbc9dc6d0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
@@ -168,16 +168,16 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod
operation_use_input_c(operation));
}
-static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -189,25 +189,25 @@ static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- const Float3ReadAttribute &input_c,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ const VArray<float3> &input_c,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- Span<float3> span_c = input_c.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VArray_Span<float3> span_c{input_c};
+ VMutableArray_Span<float3> span_result{result};
bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -220,25 +220,25 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &inpu
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- const FloatReadAttribute &input_c,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ const VArray<float> &input_c,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- Span<float> span_c = input_c.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VArray_Span<float> span_c{input_c};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -251,23 +251,23 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- FloatWriteAttribute result,
+static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- MutableSpan<float> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VMutableArray_Span<float> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -279,23 +279,23 @@ static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
- const FloatReadAttribute &input_b,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
+ const VArray<float> &input_b,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float> span_b = input_b.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float> span_b{input_b};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -307,21 +307,21 @@ static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -332,21 +332,21 @@ static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
- FloatWriteAttribute result,
+static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a,
+ VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- MutableSpan<float> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VMutableArray_Span<float> span_result{result, false};
bool success = try_dispatch_float_math_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -357,7 +357,7 @@ static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
@@ -370,9 +370,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -406,13 +406,13 @@ static void attribute_vector_math_calc(GeometryComponent &component,
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
- ReadAttributePtr attribute_a = params.get_input_attribute(
+ GVArrayPtr attribute_a = params.get_input_attribute(
"A", component, result_domain, read_type_a, nullptr);
if (!attribute_a) {
return;
}
- ReadAttributePtr attribute_b;
- ReadAttributePtr attribute_c;
+ GVArrayPtr attribute_b;
+ GVArrayPtr attribute_c;
if (use_input_b) {
attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr);
if (!attribute_b) {
@@ -427,7 +427,7 @@ static void attribute_vector_math_calc(GeometryComponent &component,
}
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@@ -445,17 +445,27 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_MODULO:
case NODE_VECTOR_MATH_MINIMUM:
case NODE_VECTOR_MATH_MAXIMUM:
- do_math_operation_fl3_fl3_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
+ do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_DISTANCE:
- do_math_operation_fl3_fl3_to_fl(*attribute_a, *attribute_b, *attribute_result, operation);
+ do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_result->typed<float>(),
+ operation);
break;
case NODE_VECTOR_MATH_LENGTH:
- do_math_operation_fl3_to_fl(*attribute_a, *attribute_result, operation);
+ do_math_operation_fl3_to_fl(
+ attribute_a->typed<float3>(), attribute_result->typed<float>(), operation);
break;
case NODE_VECTOR_MATH_SCALE:
- do_math_operation_fl3_fl_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
+ do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
case NODE_VECTOR_MATH_NORMALIZE:
case NODE_VECTOR_MATH_FLOOR:
@@ -465,16 +475,23 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_SINE:
case NODE_VECTOR_MATH_COSINE:
case NODE_VECTOR_MATH_TANGENT:
- do_math_operation_fl3_to_fl3(*attribute_a, *attribute_result, operation);
+ do_math_operation_fl3_to_fl3(
+ attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation);
break;
case NODE_VECTOR_MATH_WRAP:
case NODE_VECTOR_MATH_FACEFORWARD:
- do_math_operation_fl3_fl3_fl3_to_fl3(
- *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
+ do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_c->typed<float3>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
case NODE_VECTOR_MATH_REFRACT:
- do_math_operation_fl3_fl3_fl_to_fl3(
- *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
+ do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_c->typed<float>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
}
attribute_result.save();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index 96455f080e7..b6fa4c0d48f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -39,15 +39,12 @@ static void compute_min_max_from_position_and_transform(const GeometryComponent
float3 &r_min,
float3 &r_max)
{
- ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
- if (!position_attribute) {
- BLI_assert(component.attribute_domain_size(ATTR_DOMAIN_POINT) == 0);
- return;
- }
- Span<float3> positions = position_attribute->get_span<float3>();
+ GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
for (const float4x4 &transform : transforms) {
- for (const float3 &position : positions) {
+ for (const int i : positions.index_range()) {
+ const float3 position = positions[i];
const float3 transformed_position = transform * position;
minmax_v3v3_v3(r_min, r_max, transformed_position);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 52512769a47..857b60dfb93 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -149,10 +149,10 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *>
Vector<CustomDataType> data_types;
Vector<AttributeDomain> domains;
for (const GeometryComponent *component : components) {
- ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
+ ReadAttributeLookup attribute = component->attribute_try_get_for_read(attribute_name);
if (attribute) {
- data_types.append(attribute->custom_data_type());
- domains.append(attribute->domain());
+ data_types.append(bke::cpp_type_to_custom_data_type(attribute.varray->type()));
+ domains.append(attribute.domain);
}
}
@@ -164,7 +164,7 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
StringRef attribute_name,
const CustomDataType data_type,
const AttributeDomain domain,
- fn::GMutableSpan dst_span)
+ GMutableSpan dst_span)
{
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
@@ -175,10 +175,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
if (domain_size == 0) {
continue;
}
- ReadAttributePtr read_attribute = component->attribute_get_for_read(
+ GVArrayPtr read_attribute = component->attribute_get_for_read(
attribute_name, domain, data_type, nullptr);
- fn::GSpan src_span = read_attribute->get_span();
+ GVArray_GSpan src_span{*read_attribute};
const void *src_buffer = src_span.data();
void *dst_buffer = dst_span[offset];
cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size);
@@ -201,16 +201,14 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
AttributeDomain domain;
determine_final_data_type_and_domain(src_components, attribute_name, &data_type, &domain);
- OutputAttributePtr write_attribute = result.attribute_try_get_for_output(
+ OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
attribute_name, domain, data_type);
- if (!write_attribute ||
- &write_attribute->cpp_type() != bke::custom_data_type_to_cpp_type(data_type) ||
- write_attribute->domain() != domain) {
+ if (!write_attribute) {
continue;
}
- fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
+ GMutableSpan dst_span = write_attribute.as_span();
fill_new_attribute(src_components, attribute_name, data_type, domain, dst_span);
- write_attribute.apply_span_and_save();
+ write_attribute.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 761d5d6c388..2806472286e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -194,9 +194,9 @@ static void calculate_uvs(Mesh *mesh,
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
- "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
- MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
Array<float2> circle(verts_num);
float angle = 0.0f;
@@ -271,7 +271,7 @@ static void calculate_uvs(Mesh *mesh,
}
}
- uv_attribute.apply_span_and_save();
+ uv_attribute.save();
}
Mesh *create_cylinder_or_cone_mesh(const float radius_top,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 14c57bc7135..5a4bab86421 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -44,9 +44,9 @@ static void calculate_uvs(
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
- "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
- MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
@@ -56,7 +56,7 @@ static void calculate_uvs(
uvs[i].y = (co.y + size_y * 0.5f) * dy;
}
- uv_attribute.apply_span_and_save();
+ uv_attribute.save();
}
static Mesh *create_grid_mesh(const int verts_x,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index fd95cdc81f7..cc93e71a5dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -224,9 +224,9 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
- "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
- MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
int loop_index = 0;
const float dy = 1.0f / rings;
@@ -256,7 +256,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
}
- uv_attribute.apply_span_and_save();
+ uv_attribute.save();
}
static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index 74cca8a2f3c..772bd8a1080 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -28,6 +28,7 @@
#include "BKE_geometry_set_instances.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
#include "BKE_pointcloud.h"
#include "UI_interface.h"
@@ -91,7 +92,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
static void sample_mesh_surface(const Mesh &mesh,
const float4x4 &transform,
const float base_density,
- const FloatReadAttribute *density_factors,
+ const VArray<float> *density_factors,
const int seed,
Vector<float3> &r_positions,
Vector<float3> &r_bary_coords,
@@ -113,9 +114,9 @@ static void sample_mesh_surface(const Mesh &mesh,
float looptri_density_factor = 1.0f;
if (density_factors != nullptr) {
- const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]);
- const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]);
- const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]);
+ const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop));
+ const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop));
+ const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop));
looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
}
const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
@@ -203,7 +204,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
const Mesh &mesh,
- const FloatReadAttribute &density_factors,
+ const VArray<float> &density_factors,
Span<float3> bary_coords,
Span<int> looptri_indices,
MutableSpan<bool> elimination_mask)
@@ -249,99 +250,27 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(Span<bool> elimination_m
}
}
-template<typename T>
-BLI_NOINLINE static void interpolate_attribute_point(const Mesh &mesh,
- const Span<float3> bary_coords,
- const Span<int> looptri_indices,
- const Span<T> data_in,
- MutableSpan<T> data_out)
-{
- BLI_assert(data_in.size() == mesh.totvert);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const float3 &bary_coord = bary_coords[i];
-
- const int v0_index = mesh.mloop[looptri.tri[0]].v;
- const int v1_index = mesh.mloop[looptri.tri[1]].v;
- const int v2_index = mesh.mloop[looptri.tri[2]].v;
-
- const T &v0 = data_in[v0_index];
- const T &v1 = data_in[v1_index];
- const T &v2 = data_in[v2_index];
-
- const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
- data_out[i] = interpolated_value;
- }
-}
-
-template<typename T>
-BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
- const Span<float3> bary_coords,
- const Span<int> looptri_indices,
- const Span<T> data_in,
- MutableSpan<T> data_out)
-{
- BLI_assert(data_in.size() == mesh.totloop);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const float3 &bary_coord = bary_coords[i];
-
- const int loop_index_0 = looptri.tri[0];
- const int loop_index_1 = looptri.tri[1];
- const int loop_index_2 = looptri.tri[2];
-
- const T &v0 = data_in[loop_index_0];
- const T &v1 = data_in[loop_index_1];
- const T &v2 = data_in[loop_index_2];
-
- const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
- data_out[i] = interpolated_value;
- }
-}
-
-template<typename T>
-BLI_NOINLINE static void interpolate_attribute_face(const Mesh &mesh,
- const Span<int> looptri_indices,
- const Span<T> data_in,
- MutableSpan<T> data_out)
-{
- BLI_assert(data_in.size() == mesh.totpoly);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : data_out.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const int poly_index = looptri.poly;
- data_out[i] = data_in[poly_index];
- }
-}
-
-template<typename T>
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
const AttributeDomain source_domain,
- Span<T> source_span,
- MutableSpan<T> output_span)
+ const GVArray &source_data,
+ GMutableSpan output_data)
{
switch (source_domain) {
case ATTR_DOMAIN_POINT: {
- interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, source_span, output_span);
+ bke::mesh_surface_sample::sample_point_attribute(
+ mesh, looptri_indices, bary_coords, source_data, output_data);
break;
}
case ATTR_DOMAIN_CORNER: {
- interpolate_attribute_corner<T>(
- mesh, bary_coords, looptri_indices, source_span, output_span);
+ bke::mesh_surface_sample::sample_corner_attribute(
+ mesh, looptri_indices, bary_coords, source_data, output_data);
break;
}
case ATTR_DOMAIN_FACE: {
- interpolate_attribute_face<T>(mesh, looptri_indices, source_span, output_span);
+ bke::mesh_surface_sample::sample_face_attribute(
+ mesh, looptri_indices, source_data, output_data);
break;
}
default: {
@@ -363,13 +292,13 @@ BLI_NOINLINE static void interpolate_existing_attributes(
StringRef attribute_name = entry.key;
const CustomDataType output_data_type = entry.value.data_type;
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
- OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
+ OutputAttribute attribute_out = component.attribute_try_get_for_output_only(
attribute_name, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
continue;
}
- fn::GMutableSpan out_span = attribute_out->get_span_for_write_only();
+ GMutableSpan out_span = attribute_out.as_span();
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -377,47 +306,41 @@ BLI_NOINLINE static void interpolate_existing_attributes(
const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *source_component.get_for_read();
- /* Use a dummy read without specifying a domain or data type in order to
- * get the existing attribute's domain. Interpolation is done manually based
- * on the bary coords in #interpolate_attribute. */
- ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
+ std::optional<AttributeMetaData> attribute_info = component.attribute_get_meta_data(
attribute_name);
- if (!dummy_attribute) {
+ if (!attribute_info) {
i_instance += set_group.transforms.size();
continue;
}
- const AttributeDomain source_domain = dummy_attribute->domain();
- ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
+ const AttributeDomain source_domain = attribute_info->domain;
+ GVArrayPtr source_attribute = source_component.attribute_get_for_read(
attribute_name, source_domain, output_data_type, nullptr);
if (!source_attribute) {
i_instance += set_group.transforms.size();
continue;
}
- fn::GSpan source_span = source_attribute->get_span();
+
+ for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ const int offset = instance_start_offsets[i_instance];
+ Span<float3> bary_coords = bary_coords_array[i_instance];
+ Span<int> looptri_indices = looptri_indices_array[i_instance];
+
+ GMutableSpan instance_span = out_span.slice(offset, bary_coords.size());
+ interpolate_attribute(
+ mesh, bary_coords, looptri_indices, source_domain, *source_attribute, instance_span);
+
+ i_instance++;
+ }
attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
using T = decltype(dummy);
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
- const int offset = instance_start_offsets[i_instance];
- Span<float3> bary_coords = bary_coords_array[i_instance];
- Span<int> looptri_indices = looptri_indices_array[i_instance];
-
- MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size());
- interpolate_attribute<T>(mesh,
- bary_coords,
- looptri_indices,
- source_domain,
- source_span.typed<T>(),
- instance_span);
-
- i_instance++;
- }
+ GVArray_Span<T> source_span{*source_attribute};
});
}
- attribute_out.apply_span_and_save();
+ attribute_out.save();
}
}
@@ -427,16 +350,16 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
{
- OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
- "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ OutputAttribute_Typed<float3> normal_attribute =
+ component.attribute_try_get_for_output_only<float3>("normal", ATTR_DOMAIN_POINT);
+ OutputAttribute_Typed<float3> rotation_attribute =
+ component.attribute_try_get_for_output_only<float3>("rotation", ATTR_DOMAIN_POINT);
- MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>();
- MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>();
- MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>();
+ MutableSpan<int> result_ids = id_attribute.as_span();
+ MutableSpan<float3> result_normals = normal_attribute.as_span();
+ MutableSpan<float3> result_rotations = rotation_attribute.as_span();
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : sets) {
@@ -480,9 +403,9 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
}
}
- id_attribute.apply_span_and_save();
- normal_attribute.apply_span_and_save();
- rotation_attribute.apply_span_and_save();
+ id_attribute.save();
+ normal_attribute.save();
+ rotation_attribute.save();
}
BLI_NOINLINE static void add_remaining_point_attributes(
@@ -520,7 +443,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
const Mesh &mesh = *component.get_for_read();
for (const float4x4 &transform : set_group.transforms) {
@@ -530,7 +453,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
sample_mesh_surface(mesh,
transform,
density,
- &density_factors,
+ &*density_factors,
seed,
positions,
bary_coords,
@@ -589,7 +512,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *component.get_for_read();
- const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index 20022e8d29d..65b7d068003 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -174,13 +174,13 @@ static void add_instances_from_geometry_component(InstancesComponent &instances,
Array<std::optional<InstancedData>> instances_data = get_instanced_data(
params, src_geometry, domain_size);
- Float3ReadAttribute positions = src_geometry.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
- Float3ReadAttribute rotations = src_geometry.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>(
"rotation", domain, {0, 0, 0});
- Float3ReadAttribute scales = src_geometry.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>(
"scale", domain, {1, 1, 1});
- Int32ReadAttribute ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
+ GVArray_Typed<int> ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
for (const int i : IndexRange(domain_size)) {
if (instances_data[i].has_value()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
index 2e7fce6ea30..73d489949ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
@@ -60,8 +60,8 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C),
namespace blender::nodes {
static void point_rotate__axis_angle__object_space(const int domain_size,
- const Float3ReadAttribute &axis,
- const FloatReadAttribute &angles,
+ const VArray<float3> &axis,
+ const VArray<float> &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -76,8 +76,8 @@ static void point_rotate__axis_angle__object_space(const int domain_size,
}
static void point_rotate__axis_angle__point_space(const int domain_size,
- const Float3ReadAttribute &axis,
- const FloatReadAttribute &angles,
+ const VArray<float3> &axis,
+ const VArray<float> &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -92,7 +92,7 @@ static void point_rotate__axis_angle__point_space(const int domain_size,
}
static void point_rotate__euler__object_space(const int domain_size,
- const Float3ReadAttribute &eulers,
+ const VArray<float3> &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -107,7 +107,7 @@ static void point_rotate__euler__object_space(const int domain_size,
}
static void point_rotate__euler__point_space(const int domain_size,
- const Float3ReadAttribute &eulers,
+ const VArray<float3> &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -127,19 +127,19 @@ static void point_rotate_on_component(GeometryComponent &component,
const bNode &node = params.node();
const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage;
- OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> rotation_attribute =
+ component.attribute_try_get_for_output<float3>("rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!rotation_attribute) {
return;
}
- MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
+ MutableSpan<float3> rotations = rotation_attribute.as_span();
const int domain_size = rotations.size();
if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
- Float3ReadAttribute axis = params.get_input_attribute<float3>(
+ GVArray_Typed<float3> axis = params.get_input_attribute<float3>(
"Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1});
- FloatReadAttribute angles = params.get_input_attribute<float>(
+ GVArray_Typed<float> angles = params.get_input_attribute<float>(
"Angle", component, ATTR_DOMAIN_POINT, 0);
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -150,7 +150,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
else {
- Float3ReadAttribute eulers = params.get_input_attribute<float3>(
+ GVArray_Typed<float3> eulers = params.get_input_attribute<float3>(
"Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -161,7 +161,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
- rotation_attribute.apply_span_and_save();
+ rotation_attribute.save();
}
static void geo_node_point_rotate_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
index 113e2c620f6..2ef21fb085b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
@@ -50,7 +50,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
* for the factor. But for it's simpler to simply always use float3, since that is usually
* expected anyway. */
static const float3 scale_default = float3(1.0f);
- OutputAttributePtr scale_attribute = component.attribute_try_get_for_output(
+ OutputAttribute_Typed<float3> scale_attribute = component.attribute_try_get_for_output(
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default);
if (!scale_attribute) {
return;
@@ -63,27 +63,27 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT :
CD_PROP_FLOAT3;
- ReadAttributePtr attribute = params.get_input_attribute(
+ GVArrayPtr attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr);
if (!attribute) {
return;
}
- MutableSpan<float3> scale_span = scale_attribute->get_span<float3>();
+ MutableSpan<float3> scale_span = scale_attribute.as_span();
if (data_type == CD_PROP_FLOAT) {
- Span<float> factors = attribute->get_span<float>();
+ GVArray_Typed<float> factors{*attribute};
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
else if (data_type == CD_PROP_FLOAT3) {
- Span<float3> factors = attribute->get_span<float3>();
+ GVArray_Typed<float3> factors{*attribute};
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
- scale_attribute.apply_span_and_save();
+ scale_attribute.save();
}
static void geo_node_point_scale_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
index 522dea4aa0e..6541d982629 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
@@ -58,27 +58,27 @@ static void copy_attributes_based_on_mask(const GeometryComponent &in_component,
const bool invert)
{
for (const std::string &name : in_component.attribute_names()) {
- ReadAttributePtr attribute = in_component.attribute_try_get_for_read(name);
- const CustomDataType data_type = attribute->custom_data_type();
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name);
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type());
/* Only copy point attributes. Theoretically this could interpolate attributes on other
* domains to the point domain, but that would conflict with attributes that are built-in
* on other domains, which causes creating the attributes to fail. */
- if (attribute->domain() != ATTR_DOMAIN_POINT) {
+ if (attribute.domain != ATTR_DOMAIN_POINT) {
continue;
}
- OutputAttributePtr result_attribute = result_component.attribute_try_get_for_output(
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
name, ATTR_DOMAIN_POINT, data_type);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- Span<T> span = attribute->get_span<T>();
- MutableSpan<T> out_span = result_attribute->get_span_for_write_only<T>();
+ GVArray_Span<T> span{*attribute.varray};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
copy_data_based_on_mask(span, masks, invert, out_span);
});
- result_attribute.apply_span_and_save();
+ result_attribute.save();
}
}
@@ -107,9 +107,9 @@ static void separate_points_from_component(const GeometryComponent &in_component
return;
}
- const BooleanReadAttribute mask_attribute = in_component.attribute_get_for_read<bool>(
+ const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>(
mask_name, ATTR_DOMAIN_POINT, false);
- Span<bool> masks = mask_attribute.get_span();
+ VArray_Span<bool> masks{mask_attribute};
const int total = masks.count(!invert);
if (total == 0) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
index 8c7387f7d9b..44203228899 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
@@ -42,24 +42,19 @@ namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
- OutputAttributePtr position_attribute = component.attribute_try_get_for_output(
- "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> position_attribute =
+ component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!position_attribute) {
return;
}
- ReadAttributePtr attribute = params.get_input_attribute(
- "Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
- if (!attribute) {
- return;
- }
+ GVArray_Typed<float3> attribute = params.get_input_attribute<float3>(
+ "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
- Span<float3> data = attribute->get_span<float3>();
- MutableSpan<float3> scale_span = position_attribute->get_span<float3>();
- for (const int i : scale_span.index_range()) {
- scale_span[i] = scale_span[i] + data[i];
+ for (const int i : IndexRange(attribute.size())) {
+ position_attribute->set(i, position_attribute->get(i) + attribute[i]);
}
- position_attribute.apply_span_and_save();
+ position_attribute.save();
}
static void geo_node_point_translate_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index a9eb136597e..d73c83b4caf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -147,13 +147,15 @@ static void gather_point_data_from_component(const GeoNodeExecParams &params,
Vector<float3> &r_positions,
Vector<float> &r_radii)
{
- Float3ReadAttribute positions = component.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- FloatReadAttribute radii = params.get_input_attribute<float>(
+ GVArray_Typed<float> radii = params.get_input_attribute<float>(
"Radius", component, ATTR_DOMAIN_POINT, 0.0f);
- r_positions.extend(positions.get_span());
- r_radii.extend(radii.get_span());
+ for (const int i : IndexRange(positions.size())) {
+ r_positions.append(positions[i]);
+ r_radii.append(radii[i]);
+ }
}
static void convert_to_grid_index_space(const float voxel_size,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
new file mode 100644
index 00000000000..6736e963184
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -0,0 +1,163 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static bNodeSocketTemplate geo_node_switch_in[] = {
+ {SOCK_BOOLEAN, N_("Switch")},
+
+ {SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_INT, N_("A"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_INT, N_("B"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_BOOLEAN, N_("A")},
+ {SOCK_BOOLEAN, N_("B")},
+ {SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_RGBA, N_("A"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_RGBA, N_("B"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_STRING, N_("A")},
+ {SOCK_STRING, N_("B")},
+ {SOCK_GEOMETRY, N_("A")},
+ {SOCK_GEOMETRY, N_("B")},
+ {SOCK_OBJECT, N_("A")},
+ {SOCK_OBJECT, N_("B")},
+ {SOCK_COLLECTION, N_("A")},
+ {SOCK_COLLECTION, N_("B")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_switch_out[] = {
+ {SOCK_FLOAT, N_("Output")},
+ {SOCK_INT, N_("Output")},
+ {SOCK_BOOLEAN, N_("Output")},
+ {SOCK_VECTOR, N_("Output")},
+ {SOCK_RGBA, N_("Output")},
+ {SOCK_STRING, N_("Output")},
+ {SOCK_GEOMETRY, N_("Output")},
+ {SOCK_OBJECT, N_("Output")},
+ {SOCK_COLLECTION, N_("Output")},
+ {-1, ""},
+};
+
+static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE);
+}
+
+static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
+ data->input_type = SOCK_FLOAT;
+ node->storage = data;
+}
+
+namespace blender::nodes {
+
+template<typename T>
+void output_input(GeoNodeExecParams &params,
+ const bool input,
+ const StringRef input_suffix,
+ const StringRef output_identifier)
+{
+ if (input) {
+ params.set_output(output_identifier, params.extract_input<T>("B" + input_suffix));
+ }
+ else {
+ params.set_output(output_identifier, params.extract_input<T>("A" + input_suffix));
+ }
+}
+
+static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeSwitch *node_storage = (NodeSwitch *)node->storage;
+ int index = 0;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(
+ socket, index == 0 || socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ index++;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ nodeSetSocketAvailability(socket,
+ socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ }
+}
+
+static void geo_node_switch_exec(GeoNodeExecParams params)
+{
+ const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
+ const bool input = params.extract_input<bool>("Switch");
+ switch ((eNodeSocketDatatype)storage.input_type) {
+ case SOCK_FLOAT: {
+ output_input<float>(params, input, "", "Output");
+ break;
+ }
+ case SOCK_INT: {
+ output_input<int>(params, input, "_001", "Output_001");
+ break;
+ }
+ case SOCK_BOOLEAN: {
+ output_input<bool>(params, input, "_002", "Output_002");
+ break;
+ }
+ case SOCK_VECTOR: {
+ output_input<float3>(params, input, "_003", "Output_003");
+ break;
+ }
+ case SOCK_RGBA: {
+ output_input<Color4f>(params, input, "_004", "Output_004");
+ break;
+ }
+ case SOCK_STRING: {
+ output_input<std::string>(params, input, "_005", "Output_005");
+ break;
+ }
+ case SOCK_GEOMETRY: {
+ output_input<GeometrySet>(params, input, "_006", "Output_006");
+ break;
+ }
+ case SOCK_OBJECT: {
+ output_input<bke::PersistentObjectHandle>(params, input, "_007", "Output_007");
+ break;
+ }
+ case SOCK_COLLECTION: {
+ output_input<bke::PersistentCollectionHandle>(params, input, "_008", "Output_008");
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_switch()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_switch_in, geo_node_switch_out);
+ node_type_init(&ntype, geo_node_switch_init);
+ node_type_update(&ntype, blender::nodes::geo_node_switch_update);
+ node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec;
+ ntype.draw_buttons = geo_node_switch_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index a4fb99a988e..08fbe1ac1e6 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -22,6 +22,7 @@
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
+#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
@@ -53,22 +54,29 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
-ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const
+GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const CustomDataType type,
+ const void *default_value) const
{
const bNodeSocket *found_socket = this->find_available_socket(name);
BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
+ const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
+ const int64_t domain_size = component.attribute_domain_size(domain);
+
+ if (default_value == nullptr) {
+ default_value = cpp_type->default_value();
+ }
+
if (found_socket == nullptr) {
- return component.attribute_get_constant_for_read(domain, type, default_value);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
/* Try getting the attribute without the default value. */
- ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type);
+ GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type);
if (attribute) {
return attribute;
}
@@ -80,25 +88,29 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
this->error_message_add(NodeWarningType::Error,
TIP_("No attribute with name \"") + name + "\"");
}
- return component.attribute_get_constant_for_read(domain, type, default_value);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
+ const DataTypeConversions &conversions = get_implicit_type_conversions();
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
- return component.attribute_get_constant_for_read_converted(
- domain, CD_PROP_FLOAT, type, &value);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_VECTOR) {
const float3 value = this->get_input<float3>(found_socket->identifier);
- return component.attribute_get_constant_for_read_converted(
- domain, CD_PROP_FLOAT3, type, &value);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_RGBA) {
const Color4f value = this->get_input<Color4f>(found_socket->identifier);
- return component.attribute_get_constant_for_read_converted(
- domain, CD_PROP_COLOR, type, &value);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<Color4f>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
BLI_assert(false);
- return component.attribute_get_constant_for_read(domain, type, default_value);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
@@ -114,11 +126,11 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
- ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
- if (!attribute) {
- return default_type;
+ std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
+ if (info) {
+ return info->data_type;
}
- return attribute->custom_data_type();
+ return default_type;
}
if (found_socket->type == SOCK_FLOAT) {
return CD_PROP_FLOAT;
@@ -157,9 +169,9 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
- ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
- if (attribute) {
- input_domains.append(attribute->domain());
+ std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
+ if (info) {
+ input_domains.append(info->domain);
}
}
}
diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc
index 1c1b7c7feb5..63f7b8a9ee8 100644
--- a/source/blender/nodes/intern/type_conversions.cc
+++ b/source/blender/nodes/intern/type_conversions.cc
@@ -24,6 +24,9 @@
namespace blender::nodes {
+using fn::GVArrayPtr;
+using fn::GVMutableArray;
+using fn::GVMutableArrayPtr;
using fn::MFDataType;
template<typename From, typename To, To (*ConversionF)(const From &)>
@@ -227,6 +230,11 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
const void *from_value,
void *to_value) const
{
+ if (from_type == to_type) {
+ from_type.copy_to_uninitialized(from_value, to_value);
+ return;
+ }
+
const ConversionFunctions *functions = this->get_conversion_functions(
MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type));
BLI_assert(functions != nullptr);
@@ -234,4 +242,108 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
functions->convert_single_to_uninitialized(from_value, to_value);
}
+class GVArray_For_ConvertedGVArray : public GVArray {
+ private:
+ GVArrayPtr varray_;
+ const CPPType &from_type_;
+ ConversionFunctions old_to_new_conversions_;
+
+ public:
+ GVArray_For_ConvertedGVArray(GVArrayPtr varray,
+ const CPPType &to_type,
+ const DataTypeConversions &conversions)
+ : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type())
+ {
+ old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
+ }
+
+ private:
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+};
+
+class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray {
+ private:
+ GVMutableArrayPtr varray_;
+ const CPPType &from_type_;
+ ConversionFunctions old_to_new_conversions_;
+ ConversionFunctions new_to_old_conversions_;
+
+ public:
+ GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray,
+ const CPPType &to_type,
+ const DataTypeConversions &conversions)
+ : GVMutableArray(to_type, varray->size()),
+ varray_(std::move(varray)),
+ from_type_(varray_->type())
+ {
+ old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
+ new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_);
+ }
+
+ private:
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+
+ void set_by_move_impl(const int64_t index, void *value) override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ new_to_old_conversions_.convert_single_to_uninitialized(value, buffer);
+ varray_->set_by_relocate(index, buffer);
+ }
+};
+
+fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray,
+ const CPPType &to_type) const
+{
+ const CPPType &from_type = varray->type();
+ if (from_type == to_type) {
+ return varray;
+ }
+ if (!this->is_convertible(from_type, to_type)) {
+ return {};
+ }
+ return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
+}
+
+fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray,
+ const CPPType &to_type) const
+{
+ const CPPType &from_type = varray->type();
+ if (from_type == to_type) {
+ return varray;
+ }
+ if (!this->is_convertible(from_type, to_type)) {
+ return {};
+ }
+ return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>(
+ std::move(varray), to_type, *this);
+}
+
} // namespace blender::nodes
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index d0965e83e33..e36e3b42617 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -37,17 +37,90 @@
#include "gpu_py_buffer.h"
-// #define PYGPU_BUFFER_PROTOCOL
+//#define PYGPU_BUFFER_PROTOCOL
+#define MAX_DIMENSIONS 64
/* -------------------------------------------------------------------- */
/** \name Utility Functions
* \{ */
-static bool pygpu_buffer_dimensions_compare(int ndim,
- const Py_ssize_t *shape_a,
- const Py_ssize_t *shape_b)
+static Py_ssize_t pygpu_buffer_dimensions_tot_elem(const Py_ssize_t *shape, Py_ssize_t shape_len)
+{
+ Py_ssize_t tot = shape[0];
+ for (int i = 1; i < shape_len; i++) {
+ tot *= shape[i];
+ }
+
+ return tot;
+}
+
+static bool pygpu_buffer_dimensions_tot_len_compare(const Py_ssize_t *shape_a,
+ const Py_ssize_t shape_a_len,
+ const Py_ssize_t *shape_b,
+ const Py_ssize_t shape_b_len)
+{
+ if (pygpu_buffer_dimensions_tot_elem(shape_a, shape_a_len) !=
+ pygpu_buffer_dimensions_tot_elem(shape_b, shape_b_len)) {
+ PyErr_Format(PyExc_BufferError, "array size does not match");
+ return false;
+ }
+
+ return true;
+}
+
+static bool pygpu_buffer_pyobj_as_shape(PyObject *shape_obj,
+ Py_ssize_t r_shape[MAX_DIMENSIONS],
+ Py_ssize_t *r_shape_len)
{
- return (bool)memcmp(shape_a, shape_b, ndim * sizeof(Py_ssize_t));
+ Py_ssize_t shape_len = 0;
+ if (PyLong_Check(shape_obj)) {
+ shape_len = 1;
+ if (((r_shape[0] = PyLong_AsLong(shape_obj)) < 1)) {
+ PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
+ return false;
+ }
+ }
+ else if (PySequence_Check(shape_obj)) {
+ shape_len = PySequence_Size(shape_obj);
+ if (shape_len > MAX_DIMENSIONS) {
+ PyErr_SetString(PyExc_AttributeError,
+ "too many dimensions, max is " STRINGIFY(MAX_DIMENSIONS));
+ return false;
+ }
+ if (shape_len < 1) {
+ PyErr_SetString(PyExc_AttributeError, "sequence must have at least one dimension");
+ return false;
+ }
+
+ for (int i = 0; i < shape_len; i++) {
+ PyObject *ob = PySequence_GetItem(shape_obj, i);
+ if (!PyLong_Check(ob)) {
+ PyErr_Format(PyExc_TypeError,
+ "invalid dimension %i, expected an int, not a %.200s",
+ i,
+ Py_TYPE(ob)->tp_name);
+ Py_DECREF(ob);
+ return false;
+ }
+
+ r_shape[i] = PyLong_AsLong(ob);
+ Py_DECREF(ob);
+
+ if (r_shape[i] < 1) {
+ PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
+ return false;
+ }
+ }
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "invalid second argument argument expected a sequence "
+ "or an int, not a %.200s",
+ Py_TYPE(shape_obj)->tp_name);
+ }
+
+ *r_shape_len = shape_len;
+ return true;
}
static const char *pygpu_buffer_formatstr(eGPUDataFormat data_format)
@@ -174,7 +247,7 @@ static PyObject *pygpu_buffer_to_list_recursive(BPyGPUBuffer *self)
return list;
}
-static PyObject *pygpu_buffer_dimensions(BPyGPUBuffer *self, void *UNUSED(arg))
+static PyObject *pygpu_buffer_dimensions_get(BPyGPUBuffer *self, void *UNUSED(arg))
{
PyObject *list = PyList_New(self->shape_len);
int i;
@@ -186,6 +259,30 @@ static PyObject *pygpu_buffer_dimensions(BPyGPUBuffer *self, void *UNUSED(arg))
return list;
}
+static int pygpu_buffer_dimensions_set(BPyGPUBuffer *self, PyObject *value, void *UNUSED(type))
+{
+ Py_ssize_t shape[MAX_DIMENSIONS];
+ Py_ssize_t shape_len = 0;
+
+ if (!pygpu_buffer_pyobj_as_shape(value, shape, &shape_len)) {
+ return -1;
+ }
+
+ if (!pygpu_buffer_dimensions_tot_len_compare(shape, shape_len, self->shape, self->shape_len)) {
+ return -1;
+ }
+
+ size_t size = shape_len * sizeof(*self->shape);
+ if (shape_len != self->shape_len) {
+ MEM_freeN(self->shape);
+ self->shape = MEM_mallocN(size, __func__);
+ }
+
+ self->shape_len = shape_len;
+ memcpy(self->shape, shape, size);
+ return 0;
+}
+
static int pygpu_buffer__tp_traverse(BPyGPUBuffer *self, visitproc visit, void *arg)
{
Py_VISIT(self->parent);
@@ -280,14 +377,13 @@ static int pygpu_buffer_ass_slice(BPyGPUBuffer *self,
return err;
}
-#define MAX_DIMENSIONS 64
static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
PyObject *length_ob, *init = NULL;
BPyGPUBuffer *buffer = NULL;
Py_ssize_t shape[MAX_DIMENSIONS];
- Py_ssize_t i, shape_len = 0;
+ Py_ssize_t shape_len = 0;
if (kwds && PyDict_Size(kwds)) {
PyErr_SetString(PyExc_TypeError, "Buffer(): takes no keyword args");
@@ -300,49 +396,7 @@ static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args
return NULL;
}
- if (PyLong_Check(length_ob)) {
- shape_len = 1;
- if (((shape[0] = PyLong_AsLong(length_ob)) < 1)) {
- PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
- return NULL;
- }
- }
- else if (PySequence_Check(length_ob)) {
- shape_len = PySequence_Size(length_ob);
- if (shape_len > MAX_DIMENSIONS) {
- PyErr_SetString(PyExc_AttributeError,
- "too many dimensions, max is " STRINGIFY(MAX_DIMENSIONS));
- return NULL;
- }
- if (shape_len < 1) {
- PyErr_SetString(PyExc_AttributeError, "sequence must have at least one dimension");
- return NULL;
- }
-
- for (i = 0; i < shape_len; i++) {
- PyObject *ob = PySequence_GetItem(length_ob, i);
- if (!PyLong_Check(ob)) {
- PyErr_Format(PyExc_TypeError,
- "invalid dimension %i, expected an int, not a %.200s",
- i,
- Py_TYPE(ob)->tp_name);
- Py_DECREF(ob);
- return NULL;
- }
- shape[i] = PyLong_AsLong(ob);
- Py_DECREF(ob);
-
- if (shape[i] < 1) {
- PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
- return NULL;
- }
- }
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "invalid second argument argument expected a sequence "
- "or an int, not a %.200s",
- Py_TYPE(length_ob)->tp_name);
+ if (!pygpu_buffer_pyobj_as_shape(length_ob, shape, &shape_len)) {
return NULL;
}
@@ -354,11 +408,7 @@ static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args
return NULL;
}
- if (shape_len != pybuffer.ndim ||
- !pygpu_buffer_dimensions_compare(shape_len, shape, pybuffer.shape)) {
- PyErr_Format(PyExc_TypeError, "array size does not match");
- }
- else {
+ if (pygpu_buffer_dimensions_tot_len_compare(shape, shape_len, pybuffer.shape, pybuffer.ndim)) {
buffer = pygpu_buffer_make_from_data(
init, pygpu_dataformat.value_found, pybuffer.ndim, shape, pybuffer.buf);
}
@@ -518,7 +568,11 @@ static PyMethodDef pygpu_buffer__tp_methods[] = {
};
static PyGetSetDef pygpu_buffer_getseters[] = {
- {"dimensions", (getter)pygpu_buffer_dimensions, NULL, NULL, NULL},
+ {"dimensions",
+ (getter)pygpu_buffer_dimensions_get,
+ (setter)pygpu_buffer_dimensions_set,
+ NULL,
+ NULL},
{NULL, NULL, NULL, NULL, NULL},
};
@@ -625,13 +679,7 @@ static size_t pygpu_buffer_calc_size(const int format,
const int shape_len,
const Py_ssize_t *shape)
{
- size_t r_size = GPU_texture_dataformat_size(format);
-
- for (int i = 0; i < shape_len; i++) {
- r_size *= shape[i];
- }
-
- return r_size;
+ return pygpu_buffer_dimensions_tot_elem(shape, shape_len) * GPU_texture_dataformat_size(format);
}
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 9ac8d4d9f47..2be2105d327 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -79,6 +79,7 @@ set(SRC
bpy_rna_driver.c
bpy_rna_gizmo.c
bpy_rna_id_collection.c
+ bpy_rna_operator.c
bpy_rna_types_capi.c
bpy_rna_ui.c
bpy_traceback.c
@@ -118,6 +119,7 @@ set(SRC
bpy_rna_driver.h
bpy_rna_gizmo.h
bpy_rna_id_collection.h
+ bpy_rna_operator.h
bpy_rna_types_capi.h
bpy_rna_ui.h
bpy_traceback.h
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 5f31e0bb74d..4144063cf5c 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -167,6 +167,14 @@ void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
}
}
+static void bpy_context_end(bContext *C)
+{
+ if (UNLIKELY(C == NULL)) {
+ return;
+ }
+ CTX_wm_operator_poll_msg_clear(C);
+}
+
/**
* Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
* In this case we don't want the Python context to override the values as it causes problems
@@ -524,6 +532,9 @@ void BPY_python_end(void)
/* finalizing, no need to grab the state, except when we are a module */
gilstate = PyGILState_Ensure();
+ /* Clear Python values in the context so freeing the context after Python exits doesn't crash. */
+ bpy_context_end(BPY_context_get());
+
/* Decrement user counts of all callback functions. */
BPY_rna_props_clear_all();
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 94ad6a8ef78..4a5e2552598 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -244,12 +244,16 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
}
if (WM_operator_poll_context((bContext *)C, ot, context) == false) {
- const char *msg = CTX_wm_operator_poll_msg_get(C);
+ bool msg_free = false;
+ const char *msg = CTX_wm_operator_poll_msg_get(C, &msg_free);
PyErr_Format(PyExc_RuntimeError,
"Operator bpy.ops.%.200s.poll() %.200s",
opname,
msg ? msg : "failed, context is incorrect");
- CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */
+ CTX_wm_operator_poll_msg_clear(C);
+ if (msg_free) {
+ MEM_freeN((void *)msg);
+ }
error_val = -1;
}
else {
diff --git a/source/blender/python/intern/bpy_rna_operator.c b/source/blender/python/intern/bpy_rna_operator.c
new file mode 100644
index 00000000000..6e0db3eca49
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_operator.c
@@ -0,0 +1,150 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ *
+ * This file extends `bpy.types.Operator` with C/Python API methods and attributes.
+ */
+
+#include <Python.h>
+
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+
+#include "../generic/python_utildefines.h"
+
+#include "BPY_extern.h"
+#include "bpy_capi_utils.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Operator `poll_message_set` Method
+ * \{ */
+
+static char *pyop_poll_message_get_fn(bContext *UNUSED(C), void *user_data)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ PyObject *py_args = user_data;
+ PyObject *py_func_or_msg = PyTuple_GET_ITEM(py_args, 0);
+
+ if (PyUnicode_Check(py_func_or_msg)) {
+ return BLI_strdup(PyUnicode_AsUTF8(py_func_or_msg));
+ }
+
+ PyObject *py_args_after_first = PyTuple_GetSlice(py_args, 1, PY_SSIZE_T_MAX);
+ PyObject *py_msg = PyObject_CallObject(py_func_or_msg, py_args_after_first);
+ Py_DECREF(py_args_after_first);
+
+ char *msg = NULL;
+ bool error = false;
+
+ /* NULL for no string. */
+ if (py_msg == NULL) {
+ error = true;
+ }
+ else {
+ if (py_msg == Py_None) {
+ /* pass */
+ }
+ else if (PyUnicode_Check(py_msg)) {
+ msg = BLI_strdup(PyUnicode_AsUTF8(py_msg));
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "poll_message_set(function, ...): expected string or None, got %.200s",
+ Py_TYPE(py_msg)->tp_name);
+ error = true;
+ }
+ Py_DECREF(py_msg);
+ }
+
+ if (error) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ PyGILState_Release(gilstate);
+ return msg;
+}
+
+static void pyop_poll_message_free_fn(bContext *UNUSED(C), void *user_data)
+{
+ /* Handles the GIL. */
+ BPY_DECREF(user_data);
+}
+
+PyDoc_STRVAR(BPY_rna_operator_poll_message_set_doc,
+ ".. method:: poll_message_set(message, ...)\n"
+ "\n"
+ " Set the message to show in the tool-tip when poll fails.\n"
+ "\n"
+ " When message is callable, "
+ "additional user defined positional arguments are passed to the message function.\n"
+ "\n"
+ " :param message: The message or a function that returns the message.\n"
+ " :type message: string or a callable that returns a string or None.\n");
+
+static PyObject *BPY_rna_operator_poll_message_set(PyObject *UNUSED(self), PyObject *args)
+{
+ const ssize_t args_len = PyTuple_GET_SIZE(args);
+ if (args_len == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "poll_message_set(message, ...): requires a message argument");
+ return NULL;
+ }
+
+ PyObject *py_func_or_msg = PyTuple_GET_ITEM(args, 0);
+
+ if (PyUnicode_Check(py_func_or_msg)) {
+ if (args_len > 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "poll_message_set(message): does not support additional arguments");
+ return NULL;
+ }
+ }
+ else if (PyCallable_Check(py_func_or_msg)) {
+ /* pass */
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "poll_message_set(message, ...): "
+ "expected at least 1 string or callable argument, got %.200s",
+ Py_TYPE(py_func_or_msg)->tp_name);
+ return NULL;
+ }
+
+ bContext *C = BPY_context_get();
+ struct bContextPollMsgDyn_Params params = {
+ .get_fn = pyop_poll_message_get_fn,
+ .free_fn = pyop_poll_message_free_fn,
+ .user_data = Py_INCREF_RET(args),
+ };
+
+ CTX_wm_operator_poll_msg_set_dynamic(C, &params);
+
+ Py_RETURN_NONE;
+}
+
+PyMethodDef BPY_rna_operator_poll_message_set_method_def = {
+ "poll_message_set",
+ (PyCFunction)BPY_rna_operator_poll_message_set,
+ METH_VARARGS | METH_STATIC,
+ BPY_rna_operator_poll_message_set_doc,
+};
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_rna_operator.h b/source/blender/python/intern/bpy_rna_operator.h
new file mode 100644
index 00000000000..8040d8a492a
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_operator.h
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern PyMethodDef BPY_rna_operator_poll_message_set_method_def;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index 9b15e84663d..2f6e197d1e2 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -41,6 +41,8 @@
#include "bpy_rna_types_capi.h"
#include "bpy_rna_ui.h"
+#include "bpy_rna_operator.h"
+
#include "../generic/py_capi_utils.h"
#include "RNA_access.h"
@@ -87,6 +89,17 @@ static struct PyMethodDef pyrna_uilayout_methods[] = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Operator
+ * \{ */
+
+static struct PyMethodDef pyrna_operator_methods[] = {
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_operator_poll_message_set */
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Window Manager Clipboard Property
*
* Avoid using the RNA API because this value may change between checking its length
@@ -228,6 +241,11 @@ void BPY_rna_types_extend_capi(void)
/* Space */
pyrna_struct_type_extend_capi(&RNA_Space, pyrna_space_methods, NULL);
+ /* wmOperator */
+ ARRAY_SET_ITEMS(pyrna_operator_methods, BPY_rna_operator_poll_message_set_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_operator_methods) == 2);
+ pyrna_struct_type_extend_capi(&RNA_Operator, pyrna_operator_methods, NULL);
+
/* WindowManager */
pyrna_struct_type_extend_capi(
&RNA_WindowManager, pyrna_windowmanager_methods, pyrna_windowmanager_getset);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index d54925272de..1d99b605205 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -132,17 +132,21 @@ struct wmWindowManager;
extern "C" {
#endif
+typedef void (*wmGenericUserDataFreeFn)(void *data);
+
typedef struct wmGenericUserData {
void *data;
/** When NULL, use #MEM_freeN. */
- void (*free_fn)(void *data);
+ wmGenericUserDataFreeFn free_fn;
bool use_free;
} wmGenericUserData;
+typedef void (*wmGenericCallbackFn)(struct bContext *C, void *user_data);
+
typedef struct wmGenericCallback {
- void (*exec)(struct bContext *C, void *user_data);
+ wmGenericCallbackFn exec;
void *user_data;
- void (*free_user_data)(void *user_data);
+ wmGenericUserDataFreeFn free_user_data;
} wmGenericCallback;
/* ************** wmOperatorType ************************ */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 0d1f4cc4830..5dfbd393c14 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1048,7 +1048,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
wmWindowManager *wm = CTX_wm_manager(C);
int retval = OPERATOR_CANCELLED;
- CTX_wm_operator_poll_msg_set(C, NULL);
+ CTX_wm_operator_poll_msg_clear(C);
if (op == NULL || op->type == NULL) {
return retval;
@@ -1469,7 +1469,7 @@ static int wm_operator_call_internal(bContext *C,
{
int retval;
- CTX_wm_operator_poll_msg_set(C, NULL);
+ CTX_wm_operator_poll_msg_clear(C);
/* Dummy test. */
if (ot) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index bbcb0669cce..d0ee7075516 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -2157,21 +2157,9 @@ static void wm_homefile_read_after_dialog_callback(bContext *C, void *user_data)
C, "WM_OT_read_homefile", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data);
}
-static void wm_free_operator_properties_callback(void *user_data)
-{
- IDProperty *properties = (IDProperty *)user_data;
- IDP_FreeProperty(properties);
-}
-
static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (U.uiflag & USER_SAVE_PROMPT &&
- wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
- wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
- callback->exec = wm_homefile_read_after_dialog_callback;
- callback->user_data = IDP_CopyProperty(op->properties);
- callback->free_user_data = wm_free_operator_properties_callback;
- wm_close_file_dialog(C, callback);
+ if (wm_operator_close_file_dialog_if_needed(C, op, wm_homefile_read_after_dialog_callback)) {
return OPERATOR_INTERFACE;
}
return wm_homefile_read_exec(C, op);
@@ -2331,13 +2319,7 @@ static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op)
set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
}
- if (U.uiflag & USER_SAVE_PROMPT &&
- wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
- wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
- callback->exec = wm_open_mainfile_after_dialog_callback;
- callback->user_data = IDP_CopyProperty(op->properties);
- callback->free_user_data = wm_free_operator_properties_callback;
- wm_close_file_dialog(C, callback);
+ if (wm_operator_close_file_dialog_if_needed(C, op, wm_open_mainfile_after_dialog_callback)) {
return OPERATOR_INTERFACE;
}
return wm_open_mainfile_dispatch(C, op);
@@ -2637,12 +2619,25 @@ static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static void wm_recover_last_session_after_dialog_callback(bContext *C, void *user_data)
+{
+ WM_operator_name_call_with_properties(
+ C, "WM_OT_recover_last_session", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data);
+}
+
+static int wm_recover_last_session_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
{
/* Keep the current setting instead of using the preferences since a file selector
* doesn't give us the option to change the setting. */
wm_open_init_use_scripts(op, false);
- return WM_operator_confirm(C, op, event);
+
+ if (wm_operator_close_file_dialog_if_needed(
+ C, op, wm_recover_last_session_after_dialog_callback)) {
+ return OPERATOR_INTERFACE;
+ }
+ return wm_recover_last_session_exec(C, op);
}
void WM_OT_recover_last_session(wmOperatorType *ot)
@@ -3270,7 +3265,10 @@ static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_dat
bool file_has_been_saved_before = BKE_main_blendfile_path(bmain)[0] != '\0';
if (file_has_been_saved_before) {
- WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL);
+ if (WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL) &
+ OPERATOR_CANCELLED) {
+ execute_callback = false;
+ }
}
else {
WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_INVOKE_DEFAULT, NULL);
@@ -3456,4 +3454,31 @@ void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
}
}
+static void wm_free_operator_properties_callback(void *user_data)
+{
+ IDProperty *properties = (IDProperty *)user_data;
+ IDP_FreeProperty(properties);
+}
+
+/**
+ * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
+ * then.
+ */
+bool wm_operator_close_file_dialog_if_needed(bContext *C,
+ wmOperator *op,
+ wmGenericCallbackFn post_action_fn)
+{
+ if (U.uiflag & USER_SAVE_PROMPT &&
+ wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
+ wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
+ callback->exec = post_action_fn;
+ callback->user_data = IDP_CopyProperty(op->properties);
+ callback->free_user_data = wm_free_operator_properties_callback;
+ wm_close_file_dialog(C, callback);
+ return true;
+ }
+
+ return false;
+}
+
/** \} */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index d54090a6025..c7fe07cad7f 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -45,6 +45,9 @@ void wm_homefile_read(struct bContext *C,
void wm_file_read_report(bContext *C, struct Main *bmain);
void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action);
+bool wm_operator_close_file_dialog_if_needed(bContext *C,
+ wmOperator *op,
+ wmGenericCallbackFn exec_fn);
bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm);
void WM_OT_save_homefile(struct wmOperatorType *ot);
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index cb5fc538e69..f1741c3b495 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -130,14 +130,11 @@ set(SRC
# MSVC 2010 gives linking errors with the manifest
if(WIN32 AND NOT UNIX)
- string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1)
- string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
- string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
add_definitions(
-DBLEN_VER_RC_STR="${BLENDER_VERSION}"
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
+ -DBLEN_VER_RC_1=${BLENDER_VERSION_MAJOR}
+ -DBLEN_VER_RC_2=${BLENDER_VERSION_MINOR}
+ -DBLEN_VER_RC_3=${BLENDER_VERSION_PATCH}
-DBLEN_VER_RC_4=0
)
diff --git a/source/creator/creator_intern.h b/source/creator/creator_intern.h
index bcc8a15355a..2260da8db11 100644
--- a/source/creator/creator_intern.h
+++ b/source/creator/creator_intern.h
@@ -72,7 +72,7 @@ enum {
/* for the callbacks: */
#ifndef WITH_PYTHON_MODULE
-# define BLEND_VERSION_FMT "Blender %d.%02d.%d"
+# define BLEND_VERSION_FMT "Blender %d.%d.%d"
# define BLEND_VERSION_ARG (BLENDER_VERSION / 100), (BLENDER_VERSION % 100), BLENDER_VERSION_PATCH
#endif