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:
authorClément Foucault <foucault.clem@gmail.com>2020-07-15 15:18:30 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-07-15 15:23:35 +0300
commite8f8c13d4b76ba587ef7cf33370b286d4fbd36bc (patch)
tree371472ae220ad8740b310aaa8f4c5746448302c5
parent0c062a9e082130212447c2b67e8e16b8a2e622d1 (diff)
parent44bb73e765a6f79bc14a46449368f83e572d8bad (diff)
PointCloud: Initial rendering support for Workbenchtmp-pointcloud-render
Also includes outline overlays. Removes the temp overlay drawing We make the geometry follow camera like billboards this uses less geometry. Currently we use half octahedron for now. Goal would be to use icospheres. This patch also optimize the case when pointcloud has uniform radius. However we should premultiply the radius prop by the default radius beforehand to avoid a multiplication on CPU. Differential Revision: https://developer.blender.org/D8301
-rw-r--r--.clang-tidy1
-rw-r--r--CMakeLists.txt2
-rw-r--r--build_files/build_environment/CMakeLists.txt3
-rw-r--r--build_files/build_environment/cmake/boost.cmake2
-rw-r--r--build_files/build_environment/cmake/check_software.cmake9
-rw-r--r--build_files/build_environment/cmake/ffmpeg.cmake9
-rw-r--r--build_files/build_environment/cmake/freetype.cmake3
-rw-r--r--build_files/build_environment/cmake/ispc.cmake13
-rw-r--r--build_files/build_environment/cmake/nasm.cmake29
-rw-r--r--build_files/build_environment/cmake/ogg.cmake1
-rw-r--r--build_files/build_environment/cmake/options.cmake9
-rw-r--r--build_files/build_environment/cmake/python.cmake12
-rw-r--r--build_files/build_environment/cmake/tiff.cmake8
-rw-r--r--build_files/build_environment/cmake/versions.cmake4
-rw-r--r--build_files/build_environment/cmake/x264.cmake18
-rw-r--r--build_files/build_environment/patches/ffmpeg.diff59
-rw-r--r--build_files/build_environment/patches/ispc.diff49
-rw-r--r--build_files/build_environment/patches/nasm.diff129
-rw-r--r--build_files/build_environment/patches/ogg.diff12
-rw-r--r--build_files/cmake/Modules/FindEmbree.cmake2
-rw-r--r--build_files/cmake/platform/platform_apple.cmake2
-rw-r--r--build_files/cmake/platform/platform_apple_xcode.cmake20
-rwxr-xr-xbuild_files/utils/make_test.py3
-rwxr-xr-xbuild_files/utils/make_update.py3
-rwxr-xr-xbuild_files/utils/make_utils.py17
-rw-r--r--doc/python_api/rst/info_overview.rst2
-rw-r--r--extern/mantaflow/helper/util/vectorbase.h12
-rw-r--r--extern/mantaflow/preprocessed/fileio/iomeshes.cpp19
-rw-r--r--extern/mantaflow/preprocessed/gitinfo.h2
-rw-r--r--intern/CMakeLists.txt1
-rw-r--r--intern/cycles/app/CMakeLists.txt2
-rw-r--r--intern/cycles/blender/addon/engine.py27
-rw-r--r--intern/cycles/blender/addon/properties.py37
-rw-r--r--intern/cycles/blender/addon/ui.py11
-rw-r--r--intern/cycles/blender/blender_camera.cpp4
-rw-r--r--intern/cycles/blender/blender_id_map.h2
-rw-r--r--intern/cycles/blender/blender_object.cpp4
-rw-r--r--intern/cycles/blender/blender_python.cpp1
-rw-r--r--intern/cycles/blender/blender_shader.cpp3
-rw-r--r--intern/cycles/blender/blender_sync.cpp61
-rw-r--r--intern/cycles/blender/blender_sync.h2
-rw-r--r--intern/cycles/cmake/external_libs.cmake4
-rw-r--r--intern/cycles/device/cuda/device_cuda_impl.cpp2
-rw-r--r--intern/cycles/device/device.cpp4
-rw-r--r--intern/cycles/device/device.h4
-rw-r--r--intern/cycles/device/device_cpu.cpp235
-rw-r--r--intern/cycles/device/device_denoising.cpp52
-rw-r--r--intern/cycles/device/device_denoising.h8
-rw-r--r--intern/cycles/device/device_multi.cpp47
-rw-r--r--intern/cycles/device/device_optix.cpp395
-rw-r--r--intern/cycles/device/device_task.h21
-rw-r--r--intern/cycles/device/opencl/device_opencl_impl.cpp2
-rw-r--r--intern/cycles/kernel/bvh/bvh.h23
-rw-r--r--intern/cycles/kernel/geom/geom_curve_intersect.h9
-rw-r--r--intern/cycles/kernel/kernel_camera.h2
-rw-r--r--intern/cycles/kernel/kernel_path.h12
-rw-r--r--intern/cycles/kernel/kernel_shader.h31
-rw-r--r--intern/cycles/kernel/kernels/optix/kernel_optix.cu48
-rw-r--r--intern/cycles/kernel/shaders/node_sky_texture.osl46
-rw-r--r--intern/cycles/kernel/svm/svm_sky.h17
-rw-r--r--intern/cycles/render/CMakeLists.txt2
-rw-r--r--intern/cycles/render/buffers.h46
-rw-r--r--intern/cycles/render/camera.cpp40
-rw-r--r--intern/cycles/render/denoising.cpp64
-rw-r--r--intern/cycles/render/denoising.h4
-rw-r--r--intern/cycles/render/image_sky.cpp33
-rw-r--r--intern/cycles/render/image_sky.h4
-rw-r--r--intern/cycles/render/light.cpp14
-rw-r--r--intern/cycles/render/nodes.cpp56
-rw-r--r--intern/cycles/render/nodes.h3
-rw-r--r--intern/cycles/render/object.cpp6
-rw-r--r--intern/cycles/render/session.cpp71
-rw-r--r--intern/cycles/render/session.h4
-rw-r--r--intern/cycles/util/CMakeLists.txt4
-rw-r--r--intern/cycles/util/util_debug.cpp1
-rw-r--r--intern/cycles/util/util_debug.h3
-rw-r--r--intern/cycles/util/util_math.h10
-rw-r--r--intern/cycles/util/util_tbb.h5
-rw-r--r--intern/ghost/GHOST_C-api.h4
-rw-r--r--intern/ghost/GHOST_IWindow.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp31
-rw-r--r--intern/ghost/intern/GHOST_Window.h4
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h5
-rw-r--r--intern/guardedalloc/test/simpletest/memtest.c2
-rw-r--r--intern/libc_compat/libc_compat.c12
-rw-r--r--intern/libmv/libmv/simple_pipeline/pipeline.cc4
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp14
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h8
-rw-r--r--intern/sky/CMakeLists.txt35
-rw-r--r--intern/sky/include/sky_model.h (renamed from intern/cycles/util/util_sky_model.h)102
-rw-r--r--intern/sky/source/sky_float3.h157
-rw-r--r--intern/sky/source/sky_model.cpp (renamed from intern/cycles/util/util_sky_model.cpp)30
-rw-r--r--intern/sky/source/sky_model_data.h (renamed from intern/cycles/util/util_sky_model_data.h)4
-rw-r--r--intern/sky/source/sky_nishita.cpp (renamed from intern/cycles/util/util_sky_nishita.cpp)94
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py3
-rw-r--r--release/scripts/modules/rna_manual_reference.py78
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py23
-rw-r--r--release/scripts/startup/bl_operators/view3d.py28
-rw-r--r--release/scripts/startup/bl_operators/wm.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py72
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py8
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py4
-rw-r--r--release/scripts/startup/bl_ui/space_image.py58
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py39
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py7
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py6
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h6
-rw-r--r--source/blender/blenkernel/BKE_cloth.h8
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_deform.h2
-rw-r--r--source/blender/blenkernel/BKE_derived_node_tree.hh39
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h2
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h2
-rw-r--r--source/blender/blenkernel/BKE_fluid.h8
-rw-r--r--source/blender/blenkernel/BKE_idtype.h20
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h1
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h7
-rw-r--r--source/blender/blenkernel/BKE_mesh.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h32
-rw-r--r--source/blender/blenkernel/BKE_node_tree_multi_function.hh374
-rw-r--r--source/blender/blenkernel/BKE_node_tree_ref.hh18
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h2
-rw-r--r--source/blender/blenkernel/BKE_particle.h4
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h8
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h5
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h16
-rw-r--r--source/blender/blenkernel/CMakeLists.txt4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_util.c2
-rw-r--r--source/blender/blenkernel/intern/anim_data.c27
-rw-r--r--source/blender/blenkernel/intern/appdir.c26
-rw-r--r--source/blender/blenkernel/intern/cloth.c28
-rw-r--r--source/blender/blenkernel/intern/collection.c33
-rw-r--r--source/blender/blenkernel/intern/collision.c14
-rw-r--r--source/blender/blenkernel/intern/curve.c40
-rw-r--r--source/blender/blenkernel/intern/customdata.c4
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c2
-rw-r--r--source/blender/blenkernel/intern/deform.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c32
-rw-r--r--source/blender/blenkernel/intern/effect.c4
-rw-r--r--source/blender/blenkernel/intern/fcurve.c2
-rw-r--r--source/blender/blenkernel/intern/fluid.c119
-rw-r--r--source/blender/blenkernel/intern/gpencil.c26
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c20
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c10
-rw-r--r--source/blender/blenkernel/intern/idtype.c33
-rw-r--r--source/blender/blenkernel/intern/image.c10
-rw-r--r--source/blender/blenkernel/intern/key.c10
-rw-r--r--source/blender/blenkernel/intern/lattice_deform.c4
-rw-r--r--source/blender/blenkernel/intern/lib_id.c54
-rw-r--r--source/blender/blenkernel/intern/lib_override.c65
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c2
-rw-r--r--source/blender/blenkernel/intern/movieclip.c4
-rw-r--r--source/blender/blenkernel/intern/multires.c2
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c2
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c2
-rw-r--r--source/blender/blenkernel/intern/node.c28
-rw-r--r--source/blender/blenkernel/intern/node_tree_multi_function.cc306
-rw-r--r--source/blender/blenkernel/intern/node_tree_ref.cc4
-rw-r--r--source/blender/blenkernel/intern/object.c55
-rw-r--r--source/blender/blenkernel/intern/object_deform.c2
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c2
-rw-r--r--source/blender/blenkernel/intern/ocean.c8
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c38
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c2
-rw-r--r--source/blender/blenkernel/intern/particle_system.c7
-rw-r--r--source/blender/blenkernel/intern/pbvh.c11
-rw-r--r--source/blender/blenkernel/intern/pointcache.c70
-rw-r--r--source/blender/blenkernel/intern/scene.c25
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c6
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c16
-rw-r--r--source/blender/blenkernel/intern/sequencer.c187
-rw-r--r--source/blender/blenkernel/intern/simulation.cc703
-rw-r--r--source/blender/blenkernel/intern/softbody.c18
-rw-r--r--source/blender/blenkernel/intern/sound.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c55
-rw-r--r--source/blender/blenkernel/intern/undo_system.c4
-rw-r--r--source/blender/blenkernel/intern/volume.cc2
-rw-r--r--source/blender/blenlib/BLI_array.hh43
-rw-r--r--source/blender/blenlib/BLI_blenlib.h2
-rw-r--r--source/blender/blenlib/BLI_color.hh35
-rw-r--r--source/blender/blenlib/BLI_disjoint_set.hh105
-rw-r--r--source/blender/blenlib/BLI_dot_export.hh5
-rw-r--r--source/blender/blenlib/BLI_float2.hh38
-rw-r--r--source/blender/blenlib/BLI_float3.hh18
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh10
-rw-r--r--source/blender/blenlib/BLI_ghash.h14
-rw-r--r--source/blender/blenlib/BLI_hash.hh7
-rw-r--r--source/blender/blenlib/BLI_hash_tables.hh4
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h2
-rw-r--r--source/blender/blenlib/BLI_linklist.h1
-rw-r--r--source/blender/blenlib/BLI_map.hh66
-rw-r--r--source/blender/blenlib/BLI_map_slots.hh66
-rw-r--r--source/blender/blenlib/BLI_math_color.h8
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh199
-rw-r--r--source/blender/blenlib/BLI_rand.h6
-rw-r--r--source/blender/blenlib/BLI_rand.hh109
-rw-r--r--source/blender/blenlib/BLI_resource_collector.hh145
-rw-r--r--source/blender/blenlib/BLI_set.hh86
-rw-r--r--source/blender/blenlib/BLI_set_slots.hh46
-rw-r--r--source/blender/blenlib/BLI_span.hh33
-rw-r--r--source/blender/blenlib/BLI_stack.hh25
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_timeit.hh8
-rw-r--r--source/blender/blenlib/BLI_utildefines.h10
-rw-r--r--source/blender/blenlib/BLI_vector.hh104
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh25
-rw-r--r--source/blender/blenlib/BLI_voxel.h11
-rw-r--r--source/blender/blenlib/CMakeLists.txt4
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c19
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c71
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c10
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c8
-rw-r--r--source/blender/blenlib/intern/fileops.c2
-rw-r--r--source/blender/blenlib/intern/math_color.c8
-rw-r--r--source/blender/blenlib/intern/math_matrix.c2
-rw-r--r--source/blender/blenlib/intern/math_vector.c2
-rw-r--r--source/blender/blenlib/intern/noise.c4
-rw-r--r--source/blender/blenlib/intern/path_util.c2
-rw-r--r--source/blender/blenlib/intern/rand.cc (renamed from source/blender/blenlib/intern/rand.c)236
-rw-r--r--source/blender/blenlib/intern/storage.c17
-rw-r--r--source/blender/blenlib/intern/system.c6
-rw-r--r--source/blender/blenlib/intern/threads.cc14
-rw-r--r--source/blender/blenlib/intern/timeit.cc6
-rw-r--r--source/blender/blenlib/intern/voronoi_2d.c2
-rw-r--r--source/blender/blenlib/intern/voxel.c13
-rw-r--r--source/blender/blenloader/BLO_read_write.h2
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/readblenentry.c12
-rw-r--r--source/blender/blenloader/intern/readfile.c302
-rw-r--r--source/blender/blenloader/intern/readfile.h15
-rw-r--r--source/blender/blenloader/intern/versioning_290.c40
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c2
-rw-r--r--source/blender/blenloader/intern/writefile.c1
-rw-r--r--source/blender/bmesh/CMakeLists.txt4
-rw-r--r--source/blender/bmesh/bmesh.h1
-rw-r--r--source/blender/bmesh/bmesh_tools.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c21
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c31
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.c169
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.h52
-rw-r--r--source/blender/bmesh/operators/bmo_create.c2
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c9
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c24
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c126
-rw-r--r--source/blender/bmesh/tools/bmesh_path_uv.c433
-rw-r--r--source/blender/bmesh/tools/bmesh_path_uv.h47
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c4
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp28
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cpp2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc13
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c7
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h6
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c8
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c18
-rw-r--r--source/blender/draw/intern/DRW_render.h2
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h4
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c94
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c17
-rw-r--r--source/blender/draw/intern/draw_manager.c2
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_manager_data.c2
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c11
-rw-r--r--source/blender/editors/animation/anim_markers.c2
-rw-r--r--source/blender/editors/armature/meshlaplacian.c4
-rw-r--r--source/blender/editors/armature/meshlaplacian.h2
-rw-r--r--source/blender/editors/armature/pose_lib.c10
-rw-r--r--source/blender/editors/curve/editcurve.c1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c6
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c2
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_fileselect.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_image.h4
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_object.h8
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_uvedit.h23
-rw-r--r--source/blender/editors/include/ED_view3d.h4
-rw-r--r--source/blender/editors/include/UI_interface.h9
-rw-r--r--source/blender/editors/interface/interface.c8
-rw-r--r--source/blender/editors/interface/interface_handlers.c10
-rw-r--r--source/blender/editors/interface/interface_templates.c55
-rw-r--r--source/blender/editors/interface/interface_widgets.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c6
-rw-r--r--source/blender/editors/lattice/editlattice_select.c2
-rw-r--r--source/blender/editors/mask/mask_add.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c358
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c15
-rw-r--r--source/blender/editors/mesh/mesh_intern.h1
-rw-r--r--source/blender/editors/mesh/meshtools.c41
-rw-r--r--source/blender/editors/object/object_constraint.c16
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_modifier.c158
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c134
-rw-r--r--source/blender/editors/object/object_shader_fx.c96
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c10
-rw-r--r--source/blender/editors/physics/particle_object.c8
-rw-r--r--source/blender/editors/physics/physics_fluid.c3
-rw-r--r--source/blender/editors/render/render_shading.c10
-rw-r--r--source/blender/editors/screen/screen_ops.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c203
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c17
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c12
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c10
-rw-r--r--source/blender/editors/space_clip/clip_draw.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c8
-rw-r--r--source/blender/editors/space_clip/tracking_select.c4
-rw-r--r--source/blender/editors/space_file/filelist.c14
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_file/fsmenu.c35
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c8
-rw-r--r--source/blender/editors/space_image/image_draw.c8
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c5
-rw-r--r--source/blender/editors/space_node/drawnode.c6
-rw-r--r--source/blender/editors/space_node/node_edit.c7
-rw-r--r--source/blender/editors/space_node/node_view.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c98
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c9
-rw-r--r--source/blender/editors/transform/transform_convert.c81
-rw-r--r--source/blender/editors/transform/transform_convert.h2
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c16
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c101
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c263
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c2
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c22
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c20
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt3
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h5
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c18
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_path.c771
-rw-r--r--source/blender/editors/uvedit/uvedit_rip.c981
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c218
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c38
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.cpp16
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h2
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.cpp2
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.h2
-rw-r--r--source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp2
-rw-r--r--source/blender/functions/CMakeLists.txt3
-rw-r--r--source/blender/functions/FN_attributes_ref.hh93
-rw-r--r--source/blender/functions/FN_cpp_type.hh338
-rw-r--r--source/blender/functions/FN_cpp_types.hh2
-rw-r--r--source/blender/functions/FN_generic_vector_array.hh4
-rw-r--r--source/blender/functions/FN_multi_function.hh17
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh77
-rw-r--r--source/blender/functions/FN_multi_function_data_type.hh5
-rw-r--r--source/blender/functions/FN_multi_function_network.hh78
-rw-r--r--source/blender/functions/FN_multi_function_network_optimization.hh32
-rw-r--r--source/blender/functions/FN_multi_function_param_type.hh5
-rw-r--r--source/blender/functions/FN_spans.hh10
-rw-r--r--source/blender/functions/intern/multi_function_builder.cc90
-rw-r--r--source/blender/functions/intern/multi_function_network.cc52
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc41
-rw-r--r--source/blender/functions/intern/multi_function_network_optimization.cc491
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c13
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c2
-rw-r--r--source/blender/gpu/GPU_buffers.h2
-rw-r--r--source/blender/gpu/GPU_material.h4
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c10
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c8
-rw-r--r--source/blender/gpu/intern/gpu_material.c4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl52
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl148
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h1
-rw-r--r--source/blender/imbuf/IMB_imbuf.h5
-rw-r--r--source/blender/imbuf/intern/anim_movie.c15
-rw-r--r--source/blender/imbuf/intern/colormanagement.c7
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.cpp4
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h4
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/imageprocess.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c4
-rw-r--r--source/blender/imbuf/intern/iris.c4
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c5
-rw-r--r--source/blender/imbuf/intern/tiff.c16
-rw-r--r--source/blender/io/alembic/CMakeLists.txt4
-rw-r--r--source/blender/io/alembic/exporter/abc_export_capi.cc7
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc11
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.h4
-rw-r--r--source/blender/io/avi/intern/avi_mjpeg.c15
-rw-r--r--source/blender/io/avi/intern/avi_mjpeg.h5
-rw-r--r--source/blender/io/avi/intern/avi_rgb.c5
-rw-r--r--source/blender/io/avi/intern/avi_rgb.h5
-rw-r--r--source/blender/io/collada/ArmatureImporter.cpp4
-rw-r--r--source/blender/io/collada/MeshImporter.cpp2
-rw-r--r--source/blender/io/collada/MeshImporter.h2
-rw-r--r--source/blender/io/collada/TransformWriter.cpp6
-rw-r--r--source/blender/io/collada/TransformWriter.h5
-rw-r--r--source/blender/io/collada/collada_utils.cpp2
-rw-r--r--source/blender/io/collada/collada_utils.h2
-rw-r--r--source/blender/io/common/CMakeLists.txt5
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h47
-rw-r--r--source/blender/io/common/IO_dupli_persistent_id.hh68
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc84
-rw-r--r--source/blender/io/common/intern/dupli_parent_finder.cc104
-rw-r--r--source/blender/io/common/intern/dupli_parent_finder.hh62
-rw-r--r--source/blender/io/common/intern/dupli_persistent_id.cc167
-rw-r--r--source/blender/io/common/intern/object_identifier.cc116
-rw-r--r--source/blender/io/usd/intern/usd_capi.cc7
-rw-r--r--source/blender/makesdna/DNA_brush_types.h11
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h8
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h5
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h12
-rw-r--r--source/blender/makesdna/DNA_space_types.h5
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h1
-rw-r--r--source/blender/makesdna/DNA_world_types.h6
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c86
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c171
-rw-r--r--source/blender/makesrna/intern/rna_access_internal.h5
-rw-r--r--source/blender/makesrna/intern/rna_brush.c12
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c2
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c59
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c3
-rw-r--r--source/blender/makesrna/intern/rna_internal.h16
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h51
-rw-r--r--source/blender/makesrna/intern/rna_layer.c2
-rw-r--r--source/blender/makesrna/intern/rna_main.c4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c52
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c33
-rw-r--r--source/blender/makesrna/intern/rna_object.c5
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c2
-rw-r--r--source/blender/makesrna/intern/rna_rna.c169
-rw-r--r--source/blender/makesrna/intern/rna_scene.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_screen.c12
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c26
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c37
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c104
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c17
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c12
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc53
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c2
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c19
-rw-r--r--source/blender/nodes/CMakeLists.txt14
-rw-r--r--source/blender/nodes/function/node_function_util.cc2
-rw-r--r--source/blender/nodes/function/node_function_util.hh (renamed from source/blender/nodes/function/node_function_util.h)4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc30
-rw-r--r--source/blender/nodes/function/nodes/node_fn_combine_strings.cc27
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc45
-rw-r--r--source/blender/nodes/function/nodes/node_fn_group_instance_id.cc32
-rw-r--r--source/blender/nodes/function/nodes/node_fn_switch.cc2
-rw-r--r--source/blender/nodes/intern/node_socket.cc113
-rw-r--r--source/blender/nodes/shader/node_shader_util.h6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c115
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc196
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c)71
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.c167
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc (renamed from source/blender/nodes/shader/nodes/node_shader_value.c)10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vector_math.c)136
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.c4
-rw-r--r--source/blender/physics/intern/hair_volume.cpp2
-rw-r--r--source/blender/physics/intern/implicit_blender.c8
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/intern/bpy_app.c29
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h2
-rw-r--r--source/blender/python/intern/bpy_interface.c2
-rw-r--r--source/blender/python/intern/bpy_props.c364
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c2
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c11
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c13
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c17
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c6
-rw-r--r--source/blender/render/intern/source/bake_api.c24
-rw-r--r--source/blender/render/intern/source/multires_bake.c7
-rw-r--r--source/blender/render/intern/source/render_texture.c2
-rw-r--r--source/blender/shader_fx/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/WM_api.h7
-rw-r--r--source/blender/windowmanager/WM_types.h1
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c12
-rw-r--r--source/blender/windowmanager/intern/wm_files.c7
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c4
-rw-r--r--source/creator/creator_args.c18
-rw-r--r--tests/gtests/blenlib/BLI_array_test.cc13
-rw-r--r--tests/gtests/blenlib/BLI_disjoint_set_test.cc36
-rw-r--r--tests/gtests/blenlib/BLI_ghash_performance_test.cc36
-rw-r--r--tests/gtests/blenlib/BLI_index_mask_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_index_range_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_linear_allocator_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_map_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_math_bits_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_memory_utils_test.cc159
-rw-r--r--tests/gtests/blenlib/BLI_set_test.cc47
-rw-r--r--tests/gtests/blenlib/BLI_span_test.cc12
-rw-r--r--tests/gtests/blenlib/BLI_stack_cxx_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_string_ref_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_vector_set_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_vector_test.cc27
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt2
-rw-r--r--tests/gtests/functions/FN_array_spans_test.cc16
-rw-r--r--tests/gtests/functions/FN_attributes_ref_test.cc16
-rw-r--r--tests/gtests/functions/FN_cpp_type_test.cc46
-rw-r--r--tests/gtests/functions/FN_generic_vector_array_test.cc16
-rw-r--r--tests/gtests/functions/FN_multi_function_network_test.cc16
-rw-r--r--tests/gtests/functions/FN_multi_function_test.cc84
-rw-r--r--tests/gtests/functions/FN_spans_test.cc16
-rw-r--r--tests/gtests/usd/CMakeLists.txt1
-rw-r--r--tests/gtests/usd/object_identifier_test.cc236
-rw-r--r--tests/python/alembic_tests.py57
564 files changed, 14353 insertions, 4329 deletions
diff --git a/.clang-tidy b/.clang-tidy
index df5fc05bfd1..ad8a89cab87 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -14,7 +14,6 @@ Checks: >
-readability-else-after-return,
-readability-inconsistent-declaration-parameter-name,
- -readability-non-const-parameter,
-readability-redundant-preprocessor,
-readability-function-size,
-readability-function-size,
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e03ebb578fa..149b7d93aed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -416,7 +416,7 @@ option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_ass
mark_as_advanced(WITH_ASSERT_ABORT)
if(UNIX AND NOT APPLE)
- option(WITH_CLANG_TIDY "Use Clang Tidy to analyze the source code (only enable for development on Limux using Clang)" OFF)
+ option(WITH_CLANG_TIDY "Use Clang Tidy to analyze the source code (only enable for development on Linux using Clang)" OFF)
mark_as_advanced(WITH_CLANG_TIDY)
endif()
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 3c228fd9f7d..7e7c5d58d71 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -30,7 +30,7 @@
# build_deps 2015 x64 / build_deps 2015 x86
#
# MAC OS X USAGE:
-# Install with homebrew: brew install cmake autoconf automake libtool yasm nasm
+# Install with homebrew: brew install cmake autoconf automake libtool yasm nasm bison
# Run "make deps" from main Blender directory
#
# LINUX USAGE:
@@ -76,6 +76,7 @@ include(cmake/llvm.cmake)
include(cmake/clang.cmake)
if(APPLE)
include(cmake/openmp.cmake)
+ include(cmake/nasm.cmake)
endif()
include(cmake/openimageio.cmake)
include(cmake/tiff.cmake)
diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake
index 94c649e9109..6e7ee8c66b1 100644
--- a/build_files/build_environment/cmake/boost.cmake
+++ b/build_files/build_environment/cmake/boost.cmake
@@ -44,7 +44,7 @@ if(WIN32)
elseif(APPLE)
set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
set(BOOST_BUILD_COMMAND ./b2)
- set(BOOST_BUILD_OPTIONS toolset=darwin cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} visibility=global --disable-icu boost.locale.icu=off)
+ set(BOOST_BUILD_OPTIONS toolset=clang-darwin cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} visibility=global --disable-icu boost.locale.icu=off)
set(BOOST_HARVEST_CMD echo .)
set(BOOST_PATCH_COMMAND echo .)
else()
diff --git a/build_files/build_environment/cmake/check_software.cmake b/build_files/build_environment/cmake/check_software.cmake
index f5774551879..384915aba84 100644
--- a/build_files/build_environment/cmake/check_software.cmake
+++ b/build_files/build_environment/cmake/check_software.cmake
@@ -30,6 +30,7 @@ if(UNIX)
nasm
yasm
tclsh
+ bison
)
foreach(_software ${_required_software})
@@ -40,6 +41,12 @@ if(UNIX)
unset(_software_find CACHE)
endforeach()
+ if(APPLE)
+ if(NOT EXISTS "/usr/local/opt/bison/bin/bison")
+ set(_software_missing "${_software_missing} bison")
+ endif()
+ endif()
+
if(_software_missing)
message(
"\n"
@@ -50,7 +57,7 @@ if(UNIX)
" apt install autoconf automake libtool yasm nasm tcl\n"
"\n"
"On macOS (with homebrew):\n"
- " brew install cmake autoconf automake libtool yasm nasm\n"
+ " brew install cmake autoconf automake libtool yasm nasm bison\n"
"\n"
"Other platforms:\n"
" Install equivalent packages.\n")
diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake
index 02e78c605af..164997b9aa5 100644
--- a/build_files/build_environment/cmake/ffmpeg.cmake
+++ b/build_files/build_environment/cmake/ffmpeg.cmake
@@ -50,7 +50,8 @@ if(APPLE)
set(FFMPEG_EXTRA_FLAGS
${FFMPEG_EXTRA_FLAGS}
--target-os=darwin
- )
+ --x86asmexe=${LIBDIR}/nasm/bin/nasm
+ )
endif()
ExternalProject_Add(external_ffmpeg
@@ -143,6 +144,12 @@ if(WIN32)
external_zlib_mingw
)
endif()
+if(APPLE)
+ add_dependencies(
+ external_ffmpeg
+ external_nasm
+ )
+endif()
if(BUILD_MODE STREQUAL Release AND WIN32)
ExternalProject_Add_Step(external_ffmpeg after_install
diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake
index 30dd2eed676..fefe2c900bc 100644
--- a/build_files/build_environment/cmake/freetype.cmake
+++ b/build_files/build_environment/cmake/freetype.cmake
@@ -24,7 +24,8 @@ set(FREETYPE_EXTRA_ARGS
-DFT_WITH_HARFBUZZ=OFF
-DFT_WITH_BZIP2=OFF
-DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz=TRUE
- -DCMAKE_DISABLE_FIND_PACKAGE_BZip2=TRUE)
+ -DCMAKE_DISABLE_FIND_PACKAGE_BZip2=TRUE
+ -DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec=TRUE)
ExternalProject_Add(external_freetype
URL ${FREETYPE_URI}
diff --git a/build_files/build_environment/cmake/ispc.cmake b/build_files/build_environment/cmake/ispc.cmake
index 0bb5db82aea..b67351dcf9f 100644
--- a/build_files/build_environment/cmake/ispc.cmake
+++ b/build_files/build_environment/cmake/ispc.cmake
@@ -22,6 +22,17 @@ if(WIN32)
-DBISON_EXECUTABLE=${LIBDIR}/flexbison/win_bison.exe
-DM4_EXECUTABLE=${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/m4.exe
)
+elseif(APPLE)
+ # Use bison installed via Homebrew.
+ # The one which comes which Xcode toolset is too old.
+ set(ISPC_EXTRA_ARGS_APPLE
+ -DBISON_EXECUTABLE=/usr/local/opt/bison/bin/bison
+ )
+elseif(UNIX)
+ set(ISPC_EXTRA_ARGS_UNIX
+ -DCMAKE_C_COMPILER=${LIBDIR}/clang/bin/clang
+ -DCMAKE_CXX_COMPILER=${LIBDIR}/clang/bin/clang++
+ )
endif()
set(ISPC_EXTRA_ARGS
@@ -36,6 +47,8 @@ set(ISPC_EXTRA_ARGS
-DCLANG_LIBRARY_DIR=${LIBDIR}/clang/lib
-DCLANG_INCLUDE_DIRS=${LIBDIR}/clang/include
${ISPC_EXTRA_ARGS_WIN}
+ ${ISPC_EXTRA_ARGS_APPLE}
+ ${ISPC_EXTRA_ARGS_UNIX}
)
ExternalProject_Add(external_ispc
diff --git a/build_files/build_environment/cmake/nasm.cmake b/build_files/build_environment/cmake/nasm.cmake
new file mode 100644
index 00000000000..51d7ebd8830
--- /dev/null
+++ b/build_files/build_environment/cmake/nasm.cmake
@@ -0,0 +1,29 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+ExternalProject_Add(external_nasm
+ URL ${NASM_URI}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH SHA256=${NASM_HASH}
+ PREFIX ${BUILD_DIR}/nasm
+ PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/nasm/src/external_nasm < ${PATCH_DIR}/nasm.diff
+ CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/nasm
+ BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && make -j${MAKE_THREADS}
+ INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && make install
+ INSTALL_DIR ${LIBDIR}/nasm
+)
diff --git a/build_files/build_environment/cmake/ogg.cmake b/build_files/build_environment/cmake/ogg.cmake
index e2d0f0905b8..808a35c6e4d 100644
--- a/build_files/build_environment/cmake/ogg.cmake
+++ b/build_files/build_environment/cmake/ogg.cmake
@@ -21,6 +21,7 @@ ExternalProject_Add(external_ogg
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH SHA256=${OGG_HASH}
PREFIX ${BUILD_DIR}/ogg
+ PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/ogg/src/external_ogg < ${PATCH_DIR}/ogg.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/ogg --disable-shared --enable-static
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && make install
diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake
index 4b973067020..39334af0bcf 100644
--- a/build_files/build_environment/cmake/options.cmake
+++ b/build_files/build_environment/cmake/options.cmake
@@ -113,14 +113,18 @@ else()
COMMAND xcode-select --print-path
OUTPUT_VARIABLE XCODE_DEV_PATH OUTPUT_STRIP_TRAILING_WHITESPACE
)
+ execute_process(
+ COMMAND xcodebuild -version -sdk macosx SDKVersion
+ OUTPUT_VARIABLE MACOSX_SDK_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
+
set(OSX_ARCHITECTURES x86_64)
- set(OSX_DEPLOYMENT_TARGET 10.11)
+ set(OSX_DEPLOYMENT_TARGET 10.13)
set(OSX_SYSROOT ${XCODE_DEV_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk)
set(PLATFORM_CFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET}")
set(PLATFORM_CXXFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -std=c++11 -stdlib=libc++")
set(PLATFORM_LDFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET}")
- set(PLATFORM_BUILD_TARGET --build=x86_64-apple-darwin15.0.0) # OS X 10.11
+ set(PLATFORM_BUILD_TARGET --build=x86_64-apple-darwin17.0.0) # OS X 10.13
set(PLATFORM_CMAKE_FLAGS
-DCMAKE_OSX_ARCHITECTURES:STRING=${OSX_ARCHITECTURES}
-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${OSX_DEPLOYMENT_TARGET}
@@ -155,6 +159,7 @@ else()
set(CONFIGURE_ENV
export MACOSX_DEPLOYMENT_TARGET=${OSX_DEPLOYMENT_TARGET} &&
+ export MACOSX_SDK_VERSION=${OSX_DEPLOYMENT_TARGET} &&
export CFLAGS=${PLATFORM_CFLAGS} &&
export CXXFLAGS=${PLATFORM_CXXFLAGS} &&
export LDFLAGS=${PLATFORM_LDFLAGS}
diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake
index 2d64feb9858..681b20577d6 100644
--- a/build_files/build_environment/cmake/python.cmake
+++ b/build_files/build_environment/cmake/python.cmake
@@ -48,7 +48,12 @@ if(WIN32)
else()
if(APPLE)
- # disable functions that can be in 10.13 sdk but aren't available on 10.9 target
+ # Disable functions that can be in 10.13 sdk but aren't available on 10.9 target.
+ #
+ # Disable libintl (gettext library) as it might come from Homebrew, which makes
+ # it so test program compiles, but the Python does not. This is because for Python
+ # we use isysroot, which seems to forbid using libintl.h.
+ # The gettext functionality seems to come from CoreFoundation, so should be all fine.
set(PYTHON_FUNC_CONFIGS
export ac_cv_func_futimens=no &&
export ac_cv_func_utimensat=no &&
@@ -60,7 +65,10 @@ else()
export ac_cv_func_getentropy=no &&
export ac_cv_func_mkostemp=no &&
export ac_cv_func_mkostemps=no &&
- export ac_cv_func_timingsafe_bcmp=no)
+ export ac_cv_func_timingsafe_bcmp=no &&
+ export ac_cv_header_libintl_h=no &&
+ export ac_cv_lib_intl_textdomain=no
+ )
set(PYTHON_CONFIGURE_ENV ${CONFIGURE_ENV} && ${PYTHON_FUNC_CONFIGS})
set(PYTHON_BINARY ${BUILD_DIR}/python/src/external_python/python.exe)
else()
diff --git a/build_files/build_environment/cmake/tiff.cmake b/build_files/build_environment/cmake/tiff.cmake
index fa5a1423603..fe2c82a6eaa 100644
--- a/build_files/build_environment/cmake/tiff.cmake
+++ b/build_files/build_environment/cmake/tiff.cmake
@@ -16,6 +16,12 @@
#
# ***** END GPL LICENSE BLOCK *****
+if(WITH_WEBP)
+ set(WITH_TIFF_WEBP ON)
+else()
+ set(WITH_TIFF_WEBP OFF)
+endif()
+
set(TIFF_EXTRA_ARGS
-DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY}
-DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include
@@ -23,6 +29,8 @@ set(TIFF_EXTRA_ARGS
-DBUILD_SHARED_LIBS=OFF
-Dlzma=OFF
-Djbig=OFF
+ -Dzstd=OFF
+ -Dwebp=${WITH_TIFF_WEBP}
)
ExternalProject_Add(external_tiff
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 5ec5553079c..ce2a1191f17 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -305,6 +305,10 @@ set(MESA_VERSION 18.3.1)
set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa//mesa-${MESA_VERSION}.tar.xz)
set(MESA_HASH d60828056d77bfdbae0970f9b15fb1be)
+set(NASM_VERSION 2.15.02)
+set(NASM_URI https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/nasm-${NASM_VERSION}.tar.xz)
+set(NASM_HASH f4fd1329b1713e1ccd34b2fc121c4bcd278c9f91cc4cb205ae8fcd2e4728dd14)
+
set(XR_OPENXR_SDK_VERSION 1.0.8)
set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz)
set(XR_OPENXR_SDK_HASH c6de63d2e0f9029aa58dfa97cad8ce07)
diff --git a/build_files/build_environment/cmake/x264.cmake b/build_files/build_environment/cmake/x264.cmake
index 8bcb5a2938f..96bf031ce83 100644
--- a/build_files/build_environment/cmake/x264.cmake
+++ b/build_files/build_environment/cmake/x264.cmake
@@ -21,12 +21,21 @@ if(WIN32)
endif()
+if(APPLE)
+ set(X264_CONFIGURE_ENV
+ export AS=${LIBDIR}/nasm/bin/nasm
+ )
+else()
+ set(X264_CONFIGURE_ENV echo .)
+endif()
+
ExternalProject_Add(external_x264
URL ${X264_URI}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH SHA256=${X264_HASH}
PREFIX ${BUILD_DIR}/x264
- CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/x264
+ CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${X264_CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ &&
+ ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/x264
--enable-static
--enable-pic
--disable-lavf
@@ -39,3 +48,10 @@ ExternalProject_Add(external_x264
if(MSVC)
set_target_properties(external_x264 PROPERTIES FOLDER Mingw)
endif()
+
+if(APPLE)
+ add_dependencies(
+ external_x264
+ external_nasm
+ )
+endif()
diff --git a/build_files/build_environment/patches/ffmpeg.diff b/build_files/build_environment/patches/ffmpeg.diff
index 960728ae980..e195ca272de 100644
--- a/build_files/build_environment/patches/ffmpeg.diff
+++ b/build_files/build_environment/patches/ffmpeg.diff
@@ -9,3 +9,62 @@
enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++"
enabled libopus && {
enabled libopus_decoder && {
+--- a/libavcodec/cfhddata.c
++++ b/libavcodec/cfhddata.c
+@@ -276,10 +276,10 @@
+ av_cold int ff_cfhd_init_vlcs(CFHDContext *s)
+ {
+ int i, j, ret = 0;
+- uint32_t new_cfhd_vlc_bits[NB_VLC_TABLE_18 * 2];
+- uint8_t new_cfhd_vlc_len[NB_VLC_TABLE_18 * 2];
+- uint16_t new_cfhd_vlc_run[NB_VLC_TABLE_18 * 2];
+- int16_t new_cfhd_vlc_level[NB_VLC_TABLE_18 * 2];
++ uint32_t *new_cfhd_vlc_bits = av_calloc(sizeof(uint32_t), NB_VLC_TABLE_18 * 2);
++ uint8_t *new_cfhd_vlc_len = av_calloc(sizeof(uint8_t), NB_VLC_TABLE_18 * 2);
++ uint16_t *new_cfhd_vlc_run = av_calloc(sizeof(uint16_t), NB_VLC_TABLE_18 * 2);
++ int16_t *new_cfhd_vlc_level = av_calloc(sizeof(int16_t), NB_VLC_TABLE_18 * 2);
+
+ /** Similar to dv.c, generate signed VLC tables **/
+
+@@ -305,8 +305,13 @@
+
+ ret = init_vlc(&s->vlc_9, VLC_BITS, j, new_cfhd_vlc_len,
+ 1, 1, new_cfhd_vlc_bits, 4, 4, 0);
+- if (ret < 0)
++ if (ret < 0) {
++ av_free(new_cfhd_vlc_bits);
++ av_free(new_cfhd_vlc_len);
++ av_free(new_cfhd_vlc_run);
++ av_free(new_cfhd_vlc_level);
+ return ret;
++ }
+ for (i = 0; i < s->vlc_9.table_size; i++) {
+ int code = s->vlc_9.table[i][0];
+ int len = s->vlc_9.table[i][1];
+@@ -346,8 +351,14 @@
+
+ ret = init_vlc(&s->vlc_18, VLC_BITS, j, new_cfhd_vlc_len,
+ 1, 1, new_cfhd_vlc_bits, 4, 4, 0);
+- if (ret < 0)
++ if (ret < 0) {
++ av_free(new_cfhd_vlc_bits);
++ av_free(new_cfhd_vlc_len);
++ av_free(new_cfhd_vlc_run);
++ av_free(new_cfhd_vlc_level);
+ return ret;
++ }
++
+ av_assert0(s->vlc_18.table_size == 4572);
+
+ for (i = 0; i < s->vlc_18.table_size; i++) {
+@@ -367,5 +378,10 @@
+ s->table_18_rl_vlc[i].run = run;
+ }
+
++ av_free(new_cfhd_vlc_bits);
++ av_free(new_cfhd_vlc_len);
++ av_free(new_cfhd_vlc_run);
++ av_free(new_cfhd_vlc_level);
++
+ return ret;
+ }
diff --git a/build_files/build_environment/patches/ispc.diff b/build_files/build_environment/patches/ispc.diff
index 710bfc7a448..689dd0abdc5 100644
--- a/build_files/build_environment/patches/ispc.diff
+++ b/build_files/build_environment/patches/ispc.diff
@@ -34,3 +34,52 @@ diff -Naur orig/cmake/GenerateBuiltins.cmake.txt external_ispc/cmake/GenerateBui
elseif ("${bit}" STREQUAL "64" AND ${arch} STREQUAL "x86")
set(target_arch "x86_64")
elseif ("${bit}" STREQUAL "32" AND ${arch} STREQUAL "arm")
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 46a8db8..f53beef 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -36,8 +36,12 @@
+ cmake_minimum_required(VERSION 3.13)
+
+ if (UNIX)
+- set(CMAKE_C_COMPILER "clang")
+- set(CMAKE_CXX_COMPILER "clang++")
++ if (NOT CMAKE_C_COMPILER)
++ set(CMAKE_C_COMPILER "clang")
++ endif()
++ if (NOT CMAKE_CXX_COMPILER)
++ set(CMAKE_CXX_COMPILER "clang++")
++ endif()
+ endif()
+
+ set(PROJECT_NAME ispc)
+@@ -412,6 +416,29 @@ else()
+ endif()
+ endif()
+
++# Link against libstdc++.a which must be provided to the linker after
++# LLVM and CLang libraries.
++# This is needed because some of LLVM/CLang dependencies are using
++# std::make_shared, which is defined in one of those:
++# - libclang-cpp.so
++# - libstdc++.a
++# Using the former one is tricky because then generated binary depends
++# on a library which is outside of the LD_LIBRARY_PATH.
++#
++# Hence, using C++ implementation from G++ which seems to work just fine.
++# In fact, from investigation seems that libclang-cpp.so itself is pulling
++# std::_Sp_make_shared_tag from G++'s libstdc++.a.
++if(UNIX AND NOT APPLE)
++ execute_process(
++ COMMAND g++ --print-file-name libstdc++.a
++ OUTPUT_VARIABLE GCC_LIBSTDCXX_A
++ OUTPUT_STRIP_TRAILING_WHITESPACE
++ )
++ if(GCC_LIBSTDCXX_A AND EXISTS ${GCC_LIBSTDCXX_A})
++ target_link_libraries(${PROJECT_NAME} ${GCC_LIBSTDCXX_A})
++ endif()
++endif()
++
+ # Build target for utility checking host ISA
+ if (ISPC_INCLUDE_UTILS)
+ add_executable(check_isa "")
diff --git a/build_files/build_environment/patches/nasm.diff b/build_files/build_environment/patches/nasm.diff
new file mode 100644
index 00000000000..821e1a1d905
--- /dev/null
+++ b/build_files/build_environment/patches/nasm.diff
@@ -0,0 +1,129 @@
+diff --git a/output/macho.h b/output/macho.h
+index 538c531e..fd5e8849 100644
+--- a/output/macho.h
++++ b/output/macho.h
+@@ -60,6 +60,8 @@
+ #define LC_SEGMENT 0x1
+ #define LC_SEGMENT_64 0x19
+ #define LC_SYMTAB 0x2
++#define LC_VERSION_MIN_MACOSX 0x24
++#define LC_BUILD_VERSION 0x32
+
+ /* Symbol type bits */
+ #define N_STAB 0xe0
+diff --git a/output/outmacho.c b/output/outmacho.c
+index 08147883..de6ec902 100644
+--- a/output/outmacho.c
++++ b/output/outmacho.c
+@@ -38,6 +38,8 @@
+
+ #include "compiler.h"
+
++#include <stdlib.h>
++
+ #include "nctype.h"
+
+ #include "nasm.h"
+@@ -64,6 +66,8 @@
+ #define MACHO_SYMCMD_SIZE 24
+ #define MACHO_NLIST_SIZE 12
+ #define MACHO_RELINFO_SIZE 8
++#define MACHO_BUILD_VERSION_SIZE 24
++#define MACHO_VERSION_MIN_MACOSX_SIZE 16
+
+ #define MACHO_HEADER64_SIZE 32
+ #define MACHO_SEGCMD64_SIZE 72
+@@ -1224,6 +1228,46 @@ static void macho_layout_symbols (uint32_t *numsyms,
+ }
+ }
+
++static bool get_full_version_from_env (const char *variable_name,
++ int *r_major,
++ int *r_minor,
++ int *r_patch) {
++ *r_major = 0;
++ *r_minor = 0;
++ *r_patch = 0;
++
++ const char *value = getenv(variable_name);
++ if (value == NULL || value[0] == '\0') {
++ return false;
++ }
++
++ const char *current_value = value;
++ const char *end_value = value + strlen(value);
++
++ char *endptr;
++
++ *r_major = strtol(current_value, &endptr, 10);
++ if (endptr >= end_value) {
++ return true;
++ }
++ current_value = endptr + 1;
++
++ *r_minor = strtol(current_value, &endptr, 10);
++ if (endptr >= end_value) {
++ return true;
++ }
++ current_value = endptr + 1;
++
++ *r_patch = strtol(current_value, &endptr, 10);
++
++ return true;
++}
++
++static bool need_version_min_macosx_command (void) {
++ return getenv("MACOSX_DEPLOYMENT_TARGET") &&
++ getenv("MACOSX_SDK_VERSION");
++}
++
+ /* Calculate some values we'll need for writing later. */
+
+ static void macho_calculate_sizes (void)
+@@ -1270,6 +1314,12 @@ static void macho_calculate_sizes (void)
+ head_sizeofcmds += fmt.segcmd_size + seg_nsects * fmt.sectcmd_size;
+ }
+
++ /* LC_VERSION_MIN_MACOSX */
++ if (need_version_min_macosx_command()) {
++ ++head_ncmds;
++ head_sizeofcmds += MACHO_VERSION_MIN_MACOSX_SIZE;
++ }
++
+ if (nsyms > 0) {
+ ++head_ncmds;
+ head_sizeofcmds += MACHO_SYMCMD_SIZE;
+@@ -1653,6 +1703,33 @@ static void macho_write (void)
+ else
+ nasm_warn(WARN_OTHER, "no sections?");
+
++#define ENCODE_BUILD_VERSION(major, minor, patch) \
++ (((major) << 16) | ((minor) << 8) | (patch))
++
++ if (0) {
++ fwriteint32_t(LC_BUILD_VERSION, ofile); /* cmd == LC_BUILD_VERSION */
++ fwriteint32_t(MACHO_BUILD_VERSION_SIZE, ofile); /* size of load command */
++ fwriteint32_t(1, ofile); /* platform */
++ fwriteint32_t(ENCODE_BUILD_VERSION(10, 13, 0), ofile); /* minos, X.Y.Z is encoded in nibbles xxxx.yy.zz */
++ fwriteint32_t(ENCODE_BUILD_VERSION(10, 15, 4), ofile); /* sdk, X.Y.Z is encoded in nibbles xxxx.yy.zz */
++ fwriteint32_t(0, ofile); /* number of tool entries following this */
++ }
++
++ if (need_version_min_macosx_command()) {
++ int sdk_major, sdk_minor, sdk_patch;
++ get_full_version_from_env("MACOSX_SDK_VERSION", &sdk_major, &sdk_minor, &sdk_patch);
++
++ int version_major, version_minor, version_patch;
++ get_full_version_from_env("MACOSX_DEPLOYMENT_TARGET", &version_major, &version_minor, &version_patch);
++
++ fwriteint32_t(LC_VERSION_MIN_MACOSX, ofile); /* cmd == LC_VERSION_MIN_MACOSX */
++ fwriteint32_t(MACHO_VERSION_MIN_MACOSX_SIZE, ofile); /* size of load command */
++ fwriteint32_t(ENCODE_BUILD_VERSION(version_major, version_minor, version_patch), ofile); /* minos, X.Y.Z is encoded in nibbles xxxx.yy.zz */
++ fwriteint32_t(ENCODE_BUILD_VERSION(sdk_major, sdk_minor, sdk_patch), ofile); /* sdk, X.Y.Z is encoded in nibbles xxxx.yy.zz */
++ }
++
++#undef ENCODE_BUILD_VERSION
++
+ if (nsyms > 0) {
+ /* write out symbol command */
+ fwriteint32_t(LC_SYMTAB, ofile); /* cmd == LC_SYMTAB */
diff --git a/build_files/build_environment/patches/ogg.diff b/build_files/build_environment/patches/ogg.diff
new file mode 100644
index 00000000000..fca426e1d35
--- /dev/null
+++ b/build_files/build_environment/patches/ogg.diff
@@ -0,0 +1,12 @@
+diff --git a/include/ogg/os_types.h b/include/ogg/os_types.h
+index eb8a322..6f73b72 100644
+--- a/include/ogg/os_types.h
++++ b/include/ogg/os_types.h
+@@ -71,6 +71,7 @@
+ #elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+ # include <sys/types.h>
++# include <stdint.h>
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
diff --git a/build_files/cmake/Modules/FindEmbree.cmake b/build_files/cmake/Modules/FindEmbree.cmake
index d9d525d4586..fa613f62308 100644
--- a/build_files/cmake/Modules/FindEmbree.cmake
+++ b/build_files/cmake/Modules/FindEmbree.cmake
@@ -82,7 +82,7 @@ FIND_LIBRARY(EMBREE_LIBRARY
# handle the QUIETLY and REQUIRED arguments and set EMBREE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(EMBREE DEFAULT_MSG
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Embree DEFAULT_MSG
_embree_LIBRARIES EMBREE_INCLUDE_DIR)
IF(EMBREE_FOUND)
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index d8ee82d4c10..b24d7734423 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -20,7 +20,7 @@
# Libraries configuration for Apple.
-set(MACOSX_DEPLOYMENT_TARGET "10.11")
+set(MACOSX_DEPLOYMENT_TARGET "10.13")
macro(find_package_wrapper)
# do nothing, just satisfy the macro
diff --git a/build_files/cmake/platform/platform_apple_xcode.cmake b/build_files/cmake/platform/platform_apple_xcode.cmake
index f1f02c151ee..434c2ee31b9 100644
--- a/build_files/cmake/platform/platform_apple_xcode.cmake
+++ b/build_files/cmake/platform/platform_apple_xcode.cmake
@@ -65,13 +65,9 @@ endif()
message(STATUS "Detected OS X ${OSX_SYSTEM} and Xcode ${XCODE_VERSION} at ${XCODE_BUNDLE}")
-# Older Xcode versions had different approach to the directory hiearchy.
-# Require newer Xcode which is also have better chances of being able to compile with the
-# required deployment target.
-#
-# NOTE: Xcode version 8.2 is the latest one which runs on macOS 10.11.
-if(${XCODE_VERSION} VERSION_LESS 8.2)
- message(FATAL_ERROR "Only Xcode version 8.2 and newer is supported")
+# Require a relatively recent Xcode version.
+if(${XCODE_VERSION} VERSION_LESS 10.0)
+ message(FATAL_ERROR "Only Xcode version 10.0 and newer is supported")
endif()
# note: xcode-select path could be ambiguous,
@@ -133,14 +129,14 @@ if(${CMAKE_GENERATOR} MATCHES "Xcode")
endif()
unset(OSX_SDKROOT)
-# 10.11 is our min. target, if you use higher sdk, weak linking happens
+# 10.13 is our min. target, if you use higher sdk, weak linking happens
if(CMAKE_OSX_DEPLOYMENT_TARGET)
- if(${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.11)
- message(STATUS "Setting deployment target to 10.11, lower versions are not supported")
- set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "" FORCE)
+ if(${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.13)
+ message(STATUS "Setting deployment target to 10.13, lower versions are not supported")
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "" FORCE)
endif()
else()
- set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "" FORCE)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "" FORCE)
endif()
if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode")
diff --git a/build_files/utils/make_test.py b/build_files/utils/make_test.py
index 309ab36ecdd..15bd6dde352 100755
--- a/build_files/utils/make_test.py
+++ b/build_files/utils/make_test.py
@@ -40,7 +40,8 @@ if make_utils.command_missing(git_command):
# Test if we are building a specific release version.
branch = make_utils.git_branch(git_command)
-release_version = make_utils.git_branch_release_version(branch)
+tag = make_utils.git_tag(git_command)
+release_version = make_utils.git_branch_release_version(branch, tag)
lib_tests_dirpath = os.path.join('..', 'lib', "tests")
if not os.path.exists(lib_tests_dirpath):
diff --git a/build_files/utils/make_update.py b/build_files/utils/make_update.py
index b6157107c23..324bb6944bf 100755
--- a/build_files/utils/make_update.py
+++ b/build_files/utils/make_update.py
@@ -197,7 +197,8 @@ if __name__ == "__main__":
# Test if we are building a specific release version.
branch = make_utils.git_branch(args.git_command)
- release_version = make_utils.git_branch_release_version(branch)
+ tag = make_utils.git_tag(args.git_command)
+ release_version = make_utils.git_branch_release_version(branch, tag)
if not args.no_libraries:
svn_update(args, release_version)
diff --git a/build_files/utils/make_utils.py b/build_files/utils/make_utils.py
index 7b21bc607a4..9a3d25f4952 100755
--- a/build_files/utils/make_utils.py
+++ b/build_files/utils/make_utils.py
@@ -36,7 +36,7 @@ def check_output(cmd, exit_on_error=True):
return output.strip()
def git_branch(git_command):
- # Test if we are building a specific release version.
+ # Get current branch name.
try:
branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
except subprocess.CalledProcessError as e:
@@ -45,10 +45,23 @@ def git_branch(git_command):
return branch.strip().decode('utf8')
-def git_branch_release_version(branch):
+def git_tag(git_command):
+ # Get current tag name.
+ try:
+ tag = subprocess.check_output([git_command, "describe", "--exact-match"])
+ except subprocess.CalledProcessError as e:
+ return None
+
+ return tag.strip().decode('utf8')
+
+def git_branch_release_version(branch, tag):
release_version = re.search("^blender-v(.*)-release$", branch)
if release_version:
release_version = release_version.group(1)
+ elif tag:
+ release_version = re.search("^v([0-9]*\.[0-9]*).*", tag)
+ if release_version:
+ release_version = release_version.group(1)
return release_version
def svn_libraries_base_url(release_version):
diff --git a/doc/python_api/rst/info_overview.rst b/doc/python_api/rst/info_overview.rst
index 9676489950e..50928963f60 100644
--- a/doc/python_api/rst/info_overview.rst
+++ b/doc/python_api/rst/info_overview.rst
@@ -248,7 +248,7 @@ using the ``bl_idname`` rather than the classes original name.
.. note::
There are some exceptions to this for class names which aren't guarantee to be unique.
- In this case use: :func:`bpy.types.Struct.bl_rna_get_subclass`.
+ In this case use: :func:`bpy.types.Struct.bl_rna_get_subclass_py`.
When loading a class, Blender performs sanity checks making sure all required properties and functions are found,
diff --git a/extern/mantaflow/helper/util/vectorbase.h b/extern/mantaflow/helper/util/vectorbase.h
index 41584663a0f..9ccf445f42c 100644
--- a/extern/mantaflow/helper/util/vectorbase.h
+++ b/extern/mantaflow/helper/util/vectorbase.h
@@ -248,12 +248,14 @@ template<class S> class Vector3D {
protected:
};
-//! helper to check whether float/double value is non-zero
-inline bool notZero(Real f)
+//! helper to check whether value is non-zero
+template<class S> inline bool notZero(S v)
{
- if (std::abs(f) > VECTOR_EPSILON)
- return true;
- return false;
+ return (std::abs(v) > VECTOR_EPSILON);
+}
+template<class S> inline bool notZero(Vector3D<S> v)
+{
+ return (std::abs(norm(v)) > VECTOR_EPSILON);
}
//************************************************************************
diff --git a/extern/mantaflow/preprocessed/fileio/iomeshes.cpp b/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
index 1c50376de77..b5e51625077 100644
--- a/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
+++ b/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
@@ -315,10 +315,14 @@ int readObjFile(const std::string &name, Mesh *mesh, bool append)
return 0;
}
+ const Real dx = mesh->getParent()->getDx();
+ const Vec3 gs = toVec3(mesh->getParent()->getGridSize());
+
if (!append)
mesh->clear();
int nodebase = mesh->numNodes();
- int cnt = nodebase;
+ int cntNodes = nodebase, cntNormals = nodebase;
+
while (ifs.good() && !ifs.eof()) {
string id;
ifs >> id;
@@ -333,19 +337,23 @@ int readObjFile(const std::string &name, Mesh *mesh, bool append)
}
else if (id == "vn") {
// normals
- if (!mesh->numNodes()) {
+ if (mesh->numNodes() != cntNodes) {
errMsg("invalid amount of nodes");
return 0;
}
- Node n = mesh->nodes(cnt);
- ifs >> n.normal.x >> n.normal.y >> n.normal.z;
- cnt++;
+ Node *n = &mesh->nodes(cntNormals);
+ ifs >> n->normal.x >> n->normal.y >> n->normal.z;
+ cntNormals++;
}
else if (id == "v") {
// vertex
Node n;
ifs >> n.pos.x >> n.pos.y >> n.pos.z;
+ // convert to grid space
+ n.pos /= dx;
+ n.pos += gs * 0.5;
mesh->addNode(n);
+ cntNodes++;
}
else if (id == "g") {
// group
@@ -408,7 +416,6 @@ int writeObjFile(const string &name, Mesh *mesh)
// write normals
for (int i = 0; i < numVerts; i++) {
Vector3D<float> n = toVec3f(mesh->nodes(i).normal);
- // normalize to unit cube around 0
ofs << "vn " << n.value[0] << " " << n.value[1] << " " << n.value[2] << " "
<< "\n";
}
diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h
index 73ff70b10a0..03dcbb3d9c5 100644
--- a/extern/mantaflow/preprocessed/gitinfo.h
+++ b/extern/mantaflow/preprocessed/gitinfo.h
@@ -1,3 +1,3 @@
-#define MANTA_GIT_VERSION "commit d80d3c821de74315ab26b5efd153d41477b976c4"
+#define MANTA_GIT_VERSION "commit 7395d36e3f504edbdabe34b30edc855b422c7baa"
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index fa18f4d793a..0758567bb78 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -30,6 +30,7 @@ add_subdirectory(opensubdiv)
add_subdirectory(mikktspace)
add_subdirectory(glew-mx)
add_subdirectory(eigen)
+add_subdirectory(sky)
if(WITH_AUDASPACE)
add_subdirectory(audaspace)
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index ef374f91a65..a2b0ed03925 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -35,7 +35,7 @@ if(WITH_CYCLES_OSL)
endif()
if(NOT CYCLES_STANDALONE_REPOSITORY)
- list(APPEND LIBRARIES bf_intern_glew_mx bf_intern_guardedalloc bf_intern_numaapi)
+ list(APPEND LIBRARIES bf_intern_glew_mx bf_intern_guardedalloc bf_intern_numaapi bf_intern_sky)
endif()
if(WITH_CYCLES_LOGGING)
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 7566ca28dd7..67e448db859 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -224,7 +224,7 @@ def system_info():
import _cycles
return _cycles.system_info()
-def list_render_passes(srl):
+def list_render_passes(scene, srl):
# Builtin Blender passes.
yield ("Combined", "RGBA", 'COLOR')
@@ -279,14 +279,17 @@ def list_render_passes(srl):
yield ("Denoising Normal", "XYZ", 'VECTOR')
yield ("Denoising Albedo", "RGB", 'COLOR')
yield ("Denoising Depth", "Z", 'VALUE')
- yield ("Denoising Shadowing", "X", 'VALUE')
- yield ("Denoising Variance", "RGB", 'COLOR')
- yield ("Denoising Intensity", "X", 'VALUE')
- clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
- "denoising_glossy_direct", "denoising_glossy_indirect",
- "denoising_transmission_direct", "denoising_transmission_indirect")
- if any(getattr(crl, option) for option in clean_options):
- yield ("Denoising Clean", "RGB", 'COLOR')
+
+ if scene.cycles.denoiser == 'NLM':
+ yield ("Denoising Shadowing", "X", 'VALUE')
+ yield ("Denoising Variance", "RGB", 'COLOR')
+ yield ("Denoising Intensity", "X", 'VALUE')
+
+ clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
+ "denoising_glossy_direct", "denoising_glossy_indirect",
+ "denoising_transmission_direct", "denoising_transmission_indirect")
+ if any(getattr(crl, option) for option in clean_options):
+ yield ("Denoising Clean", "RGB", 'COLOR')
# Custom AOV passes.
for aov in crl.aovs:
@@ -298,15 +301,15 @@ def list_render_passes(srl):
def register_passes(engine, scene, view_layer):
# Detect duplicate render pass names, first one wins.
listed = set()
- for name, channelids, channeltype in list_render_passes(view_layer):
+ for name, channelids, channeltype in list_render_passes(scene, view_layer):
if name not in listed:
engine.register_pass(scene, view_layer, name, len(channelids), channelids, channeltype)
listed.add(name)
-def detect_conflicting_passes(view_layer):
+def detect_conflicting_passes(scene, view_layer):
# Detect conflicting render pass names for UI.
counter = {}
- for name, _, _ in list_render_passes(view_layer):
+ for name, _, _ in list_render_passes(scene, view_layer):
counter[name] = counter.get(name, 0) + 1
for aov in view_layer.cycles.aovs:
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index da706451f88..45d25720aff 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -182,6 +182,7 @@ enum_aov_types = (
('COLOR', "Color", "Write a Color pass", 1),
)
+
def enum_openimagedenoise_denoiser(self, context):
if _cycles.with_openimagedenoise:
return [('OPENIMAGEDENOISE', "OpenImageDenoise", "Use Intel OpenImageDenoise AI denoiser running on the CPU", 4)]
@@ -208,14 +209,23 @@ def enum_preview_denoiser(self, context):
def enum_denoiser(self, context):
items = [('NLM', "NLM", "Cycles native non-local means denoiser, running on any compute device", 1)]
items += enum_optix_denoiser(self, context)
+ items += enum_openimagedenoise_denoiser(self, context)
return items
-enum_denoising_optix_input_passes = (
+enum_denoising_input_passes = (
('RGB', "Color", "Use only color as input", 1),
('RGB_ALBEDO', "Color + Albedo", "Use color and albedo data as input", 2),
('RGB_ALBEDO_NORMAL', "Color + Albedo + Normal", "Use color, albedo and normal data as input", 3),
)
+
+def update_render_passes(self, context):
+ scene = context.scene
+ view_layer = context.view_layer
+ view_layer.update_render_passes()
+ engine.detect_conflicting_passes(scene, view_layer)
+
+
class CyclesRenderSettings(bpy.types.PropertyGroup):
device: EnumProperty(
@@ -261,9 +271,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
denoiser: EnumProperty(
name="Denoiser",
- description="Denoise the image with the selected denoiser",
+ description="Denoise the image with the selected denoiser. "
+ "For denoising the image after rendering, denoising data render passes "
+ "also adapt to the selected denoiser",
items=enum_denoiser,
default=1,
+ update=update_render_passes,
)
preview_denoiser: EnumProperty(
name="Viewport Denoiser",
@@ -818,6 +831,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False)
debug_optix_cuda_streams: IntProperty(name="CUDA Streams", default=1, min=1)
+ debug_optix_curves_api: BoolProperty(name="Native OptiX Curve Primitive", default=False)
debug_opencl_kernel_type: EnumProperty(
name="OpenCL Kernel Type",
@@ -1291,12 +1305,6 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
del bpy.types.Scene.cycles_curves
-def update_render_passes(self, context):
- view_layer = context.view_layer
- view_layer.update_render_passes()
- engine.detect_conflicting_passes(view_layer)
-
-
class CyclesAOVPass(bpy.types.PropertyGroup):
name: StringProperty(
name="Name",
@@ -1430,7 +1438,7 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
)
denoising_store_passes: BoolProperty(
name="Store Denoising Passes",
- description="Store the denoising feature passes and the noisy image",
+ description="Store the denoising feature passes and the noisy image. The passes adapt to the denoiser selected for rendering",
default=False,
update=update_render_passes,
)
@@ -1443,11 +1451,18 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
denoising_optix_input_passes: EnumProperty(
name="Input Passes",
- description="Passes handed over to the OptiX denoiser (this can have different effects on the denoised image)",
- items=enum_denoising_optix_input_passes,
+ description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
+ items=enum_denoising_input_passes,
default='RGB_ALBEDO',
)
+ denoising_openimagedenoise_input_passes: EnumProperty(
+ name="Input Passes",
+ description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
+ items=enum_denoising_input_passes,
+ default='RGB_ALBEDO_NORMAL',
+ )
+
use_pass_crypto_object: BoolProperty(
name="Cryptomatte Object",
description="Render cryptomatte object pass, for isolating objects in compositing",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 129f16b0357..03b1675c309 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -265,7 +265,12 @@ class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel):
row = heading.row(align=True)
row.prop(cscene, "use_denoising", text="")
sub = row.row()
+
sub.active = cscene.use_denoising
+ for view_layer in scene.view_layers:
+ if view_layer.cycles.denoising_store_passes:
+ sub.active = True
+
sub.prop(cscene, "denoiser", text="")
heading = layout.column(align=False, heading="Viewport")
@@ -777,10 +782,6 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_solid", text="Surfaces")
col.prop(view_layer, "use_strand", text="Hair")
col.prop(view_layer, "use_volumes", text="Volumes")
- if with_freestyle:
- sub = col.row(align=True)
- sub.prop(view_layer, "use_freestyle", text="Freestyle")
- sub.active = rd.use_freestyle
class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel):
@@ -1007,6 +1008,7 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
col.prop(cycles_view_layer, "denoising_optix_input_passes")
return
elif denoiser == 'OPENIMAGEDENOISE':
+ col.prop(cycles_view_layer, "denoising_openimagedenoise_input_passes")
return
col.prop(cycles_view_layer, "denoising_radius", text="Radius")
@@ -2026,6 +2028,7 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
col = layout.column()
col.label(text="OptiX Flags:")
col.prop(cscene, "debug_optix_cuda_streams")
+ col.prop(cscene, "debug_optix_curves_api")
col.separator()
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 011678a7a65..592a69585de 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -709,6 +709,10 @@ static void blender_camera_from_view(BlenderCamera *bcam,
/* 3d view transform */
bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
+
+ /* dimensions */
+ bcam->full_width = width;
+ bcam->full_height = height;
}
static void blender_camera_view_subset(BL::RenderEngine &b_engine,
diff --git a/intern/cycles/blender/blender_id_map.h b/intern/cycles/blender/blender_id_map.h
index 3bc42e349ae..b5f6aaa67a8 100644
--- a/intern/cycles/blender/blender_id_map.h
+++ b/intern/cycles/blender/blender_id_map.h
@@ -200,7 +200,7 @@ template<typename K, typename T> class id_map {
* To uniquely identify instances, we use the parent, object and persistent instance ID.
* We also export separate object for a mesh and its particle hair. */
-enum { OBJECT_PERSISTENT_ID_SIZE = 16 };
+enum { OBJECT_PERSISTENT_ID_SIZE = 8 /* MAX_DUPLI_RECUR in Blender. */ };
struct ObjectKey {
void *parent;
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index d3a37563ef4..3ea6892a349 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -59,7 +59,7 @@ bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob)
return false;
}
-bool BlenderSync::object_is_mesh(BL::Object &b_ob)
+bool BlenderSync::object_is_geometry(BL::Object &b_ob)
{
BL::ID b_ob_data = b_ob.data();
@@ -143,7 +143,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
}
/* only interested in object that we can create meshes from */
- if (!object_is_mesh(b_ob)) {
+ if (!object_is_geometry(b_ob)) {
return NULL;
}
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 3e595c3ee52..25c77b74ce3 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -92,6 +92,7 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene)
flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
/* Synchronize OptiX flags. */
flags.optix.cuda_streams = get_int(cscene, "debug_optix_cuda_streams");
+ flags.optix.curves_api = get_boolean(cscene, "debug_optix_curves_api");
/* Synchronize OpenCL device type. */
switch (get_enum(cscene, "debug_opencl_device_type")) {
case 0:
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 19d2730dc93..33e73b5a4b9 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -815,9 +815,10 @@ static ShaderNode *add_node(Scene *scene,
sky->ground_albedo = b_sky_node.ground_albedo();
sky->sun_disc = b_sky_node.sun_disc();
sky->sun_size = b_sky_node.sun_size();
+ sky->sun_intensity = b_sky_node.sun_intensity();
sky->sun_elevation = b_sky_node.sun_elevation();
sky->sun_rotation = b_sky_node.sun_rotation();
- sky->altitude = b_sky_node.altitude();
+ sky->altitude = 1000.0f * b_sky_node.altitude();
sky->air_density = b_sky_node.air_density();
sky->dust_density = b_sky_node.dust_density();
sky->ozone_density = b_sky_node.ozone_density();
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index bf065cc5492..d509f2fc786 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -147,30 +147,43 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
/* Object */
else if (b_id.is_a(&RNA_Object)) {
BL::Object b_ob(b_id);
- const bool updated_geometry = b_update->is_updated_geometry();
+ const bool is_geometry = object_is_geometry(b_ob);
+ const bool is_light = !is_geometry && object_is_light(b_ob);
- if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
- object_map.set_recalc(b_ob);
- light_map.set_recalc(b_ob);
- }
+ if (is_geometry || is_light) {
+ const bool updated_geometry = b_update->is_updated_geometry();
- if (object_is_mesh(b_ob)) {
- if (updated_geometry ||
- (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) {
- BL::ID key = BKE_object_is_modified(b_ob) ? b_ob : b_ob.data();
- geometry_map.set_recalc(key);
- }
- }
- else if (object_is_light(b_ob)) {
- if (updated_geometry) {
- light_map.set_recalc(b_ob);
+ /* Geometry (mesh, hair, volume). */
+ if (is_geometry) {
+ if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
+ object_map.set_recalc(b_ob);
+ }
+
+ if (updated_geometry ||
+ (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) {
+ BL::ID key = BKE_object_is_modified(b_ob) ? b_ob : b_ob.data();
+ geometry_map.set_recalc(key);
+ }
+
+ if (updated_geometry) {
+ BL::Object::particle_systems_iterator b_psys;
+ for (b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end();
+ ++b_psys) {
+ particle_system_map.set_recalc(b_ob);
+ }
+ }
}
- }
+ /* Light */
+ else if (is_light) {
+ if (b_update->is_updated_transform() || b_update->is_updated_shading()) {
+ object_map.set_recalc(b_ob);
+ light_map.set_recalc(b_ob);
+ }
- if (updated_geometry) {
- BL::Object::particle_systems_iterator b_psys;
- for (b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys)
- particle_system_map.set_recalc(b_ob);
+ if (updated_geometry) {
+ light_map.set_recalc(b_ob);
+ }
+ }
}
}
/* Mesh */
@@ -941,7 +954,13 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
denoising.strength = get_float(clayer, "denoising_strength");
denoising.feature_strength = get_float(clayer, "denoising_feature_strength");
denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca");
- denoising.optix_input_passes = get_enum(clayer, "denoising_optix_input_passes");
+
+ denoising.input_passes = (DenoiserInput)get_enum(
+ clayer,
+ (denoising.type == DENOISER_OPTIX) ? "denoising_optix_input_passes" :
+ "denoising_openimagedenoise_input_passes",
+ DENOISER_INPUT_NUM,
+ DENOISER_INPUT_RGB_ALBEDO_NORMAL);
denoising.store_passes = get_boolean(clayer, "denoising_store_passes");
}
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 0214d9eb3b8..a551ec31e04 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -208,7 +208,7 @@ class BlenderSync {
/* util */
void find_shader(BL::ID &id, vector<Shader *> &used_shaders, Shader *default_shader);
bool BKE_object_is_modified(BL::Object &b_ob);
- bool object_is_mesh(BL::Object &b_ob);
+ bool object_is_geometry(BL::Object &b_ob);
bool object_is_light(BL::Object &b_ob);
/* variables */
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index 0b082b11cf7..b09f442bd16 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -133,9 +133,9 @@ if(CYCLES_STANDALONE_REPOSITORY)
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
####
- # embree
+ # Embree
if(WITH_CYCLES_EMBREE)
- find_package(embree 3.8.0 REQUIRED)
+ find_package(Embree 3.8.0 REQUIRED)
endif()
####
diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp
index b9bbeb9a25b..0be2c322dfa 100644
--- a/intern/cycles/device/cuda/device_cuda_impl.cpp
+++ b/intern/cycles/device/cuda/device_cuda_impl.cpp
@@ -1760,7 +1760,7 @@ void CUDADevice::denoise(RenderTile &rtile, DenoisingTask &denoising)
denoising.render_buffer.samples = rtile.sample;
denoising.buffer.gpu_temporary_mem = true;
- denoising.run_denoising(&rtile);
+ denoising.run_denoising(rtile);
}
void CUDADevice::adaptive_sampling_filter(uint filter_sample,
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 9dbb33980b4..407f73e8451 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -209,13 +209,13 @@ bool Device::bind_fallback_display_space_shader(const float width, const float h
glUseProgram(fallback_shader_program);
image_texture_location = glGetUniformLocation(fallback_shader_program, "image_texture");
if (image_texture_location < 0) {
- LOG(ERROR) << "Shader doesn't containt the 'image_texture' uniform.";
+ LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
return false;
}
fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen");
if (fullscreen_location < 0) {
- LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform.";
+ LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
return false;
}
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index a5833369a17..115b05e3911 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -439,10 +439,10 @@ class Device {
{
return 0;
}
- virtual void map_neighbor_tiles(Device * /*sub_device*/, RenderTile * /*tiles*/)
+ virtual void map_neighbor_tiles(Device * /*sub_device*/, RenderTileNeighbors & /*neighbors*/)
{
}
- virtual void unmap_neighbor_tiles(Device * /*sub_device*/, RenderTile * /*tiles*/)
+ virtual void unmap_neighbor_tiles(Device * /*sub_device*/, RenderTileNeighbors & /*neighbors*/)
{
}
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 8f68e66a1b4..ee3a3ddea64 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -182,6 +182,7 @@ class CPUDevice : public Device {
oidn::DeviceRef oidn_device;
oidn::FilterRef oidn_filter;
#endif
+ thread_spin_lock oidn_task_lock;
bool use_split_kernel;
@@ -948,12 +949,25 @@ class CPUDevice : public Device {
}
}
- void denoise_openimagedenoise(DeviceTask &task, RenderTile &rtile)
+ void denoise_openimagedenoise_buffer(DeviceTask &task,
+ float *buffer,
+ const size_t offset,
+ const size_t stride,
+ const size_t x,
+ const size_t y,
+ const size_t w,
+ const size_t h,
+ const float scale)
{
#ifdef WITH_OPENIMAGEDENOISE
assert(openimagedenoise_supported());
- /* Only one at a time, since OpenImageDenoise itself is multithreaded. */
+ /* Only one at a time, since OpenImageDenoise itself is multithreaded for full
+ * buffers, and for tiled rendering because creating multiple devices and filters
+ * is slow and memory hungry as well.
+ *
+ * TODO: optimize tiled rendering case, by batching together denoising of many
+ * tiles somehow? */
static thread_mutex mutex;
thread_scoped_lock lock(mutex);
@@ -964,54 +978,192 @@ class CPUDevice : public Device {
}
if (!oidn_filter) {
oidn_filter = oidn_device.newFilter("RT");
+ oidn_filter.set("hdr", true);
+ oidn_filter.set("srgb", false);
}
- /* Copy pixels from compute device to CPU (no-op for CPU device). */
- rtile.buffers->buffer.copy_from_device();
-
/* Set images with appropriate stride for our interleaved pass storage. */
- const struct {
+ struct {
const char *name;
- int offset;
- } passes[] = {{"color", task.pass_denoising_data + DENOISING_PASS_COLOR},
- {"normal", task.pass_denoising_data + DENOISING_PASS_NORMAL},
- {"albedo", task.pass_denoising_data + DENOISING_PASS_ALBEDO},
- {"output", 0},
+ const int offset;
+ const bool scale;
+ const bool use;
+ array<float> scaled_buffer;
+ } passes[] = {{"color", task.pass_denoising_data + DENOISING_PASS_COLOR, false, true},
+ {"albedo",
+ task.pass_denoising_data + DENOISING_PASS_ALBEDO,
+ true,
+ task.denoising.input_passes >= DENOISER_INPUT_RGB_ALBEDO},
+ {"normal",
+ task.pass_denoising_data + DENOISING_PASS_NORMAL,
+ true,
+ task.denoising.input_passes >= DENOISER_INPUT_RGB_ALBEDO_NORMAL},
+ {"output", 0, false, true},
{ NULL,
0 }};
for (int i = 0; passes[i].name; i++) {
- const int64_t offset = rtile.offset + rtile.x + rtile.y * rtile.stride;
- const int64_t buffer_offset = (offset * task.pass_stride + passes[i].offset) * sizeof(float);
- const int64_t pixel_stride = task.pass_stride * sizeof(float);
- const int64_t row_stride = rtile.stride * pixel_stride;
+ if (!passes[i].use) {
+ continue;
+ }
- oidn_filter.setImage(passes[i].name,
- (char *)rtile.buffer + buffer_offset,
- oidn::Format::Float3,
- rtile.w,
- rtile.h,
- 0,
- pixel_stride,
- row_stride);
+ const int64_t pixel_offset = offset + x + y * stride;
+ const int64_t buffer_offset = (pixel_offset * task.pass_stride + passes[i].offset);
+ const int64_t pixel_stride = task.pass_stride;
+ const int64_t row_stride = stride * pixel_stride;
+
+ if (passes[i].scale && scale != 1.0f) {
+ /* Normalize albedo and normal passes as they are scaled by the number of samples.
+ * For the color passes OIDN will perform auto-exposure making it unnecessary. */
+ array<float> &scaled_buffer = passes[i].scaled_buffer;
+ scaled_buffer.resize(w * h * 3);
+
+ for (int y = 0; y < h; y++) {
+ const float *pass_row = buffer + buffer_offset + y * row_stride;
+ float *scaled_row = scaled_buffer.data() + y * w * 3;
+
+ for (int x = 0; x < w; x++) {
+ scaled_row[x * 3 + 0] = pass_row[x * pixel_stride + 0] * scale;
+ scaled_row[x * 3 + 1] = pass_row[x * pixel_stride + 1] * scale;
+ scaled_row[x * 3 + 2] = pass_row[x * pixel_stride + 2] * scale;
+ }
+ }
+
+ oidn_filter.setImage(
+ passes[i].name, scaled_buffer.data(), oidn::Format::Float3, w, h, 0, 0, 0);
+ }
+ else {
+ oidn_filter.setImage(passes[i].name,
+ buffer + buffer_offset,
+ oidn::Format::Float3,
+ w,
+ h,
+ 0,
+ pixel_stride * sizeof(float),
+ row_stride * sizeof(float));
+ }
}
/* Execute filter. */
- oidn_filter.set("hdr", true);
- oidn_filter.set("srgb", false);
oidn_filter.commit();
oidn_filter.execute();
-
- /* todo: it may be possible to avoid this copy, but we have to ensure that
- * when other code copies data from the device it doesn't overwrite the
- * denoiser buffers. */
- rtile.buffers->buffer.copy_to_device();
#else
(void)task;
- (void)rtile;
+ (void)buffer;
+ (void)offset;
+ (void)stride;
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+ (void)scale;
#endif
}
+ void denoise_openimagedenoise(DeviceTask &task, RenderTile &rtile)
+ {
+ if (task.type == DeviceTask::DENOISE_BUFFER) {
+ /* Copy pixels from compute device to CPU (no-op for CPU device). */
+ rtile.buffers->buffer.copy_from_device();
+
+ denoise_openimagedenoise_buffer(task,
+ (float *)rtile.buffer,
+ rtile.offset,
+ rtile.stride,
+ rtile.x,
+ rtile.y,
+ rtile.w,
+ rtile.h,
+ 1.0f / rtile.sample);
+
+ /* todo: it may be possible to avoid this copy, but we have to ensure that
+ * when other code copies data from the device it doesn't overwrite the
+ * denoiser buffers. */
+ rtile.buffers->buffer.copy_to_device();
+ }
+ else {
+ /* Per-tile denoising. */
+ rtile.sample = rtile.start_sample + rtile.num_samples;
+ const float scale = 1.0f / rtile.sample;
+ const float invscale = rtile.sample;
+ const size_t pass_stride = task.pass_stride;
+
+ /* Map neighboring tiles into one buffer for denoising. */
+ RenderTileNeighbors neighbors(rtile);
+ task.map_neighbor_tiles(neighbors, this);
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+ rtile = center_tile;
+
+ /* Calculate size of the tile to denoise (including overlap). The overlap
+ * size was chosen empirically. OpenImageDenoise specifies an overlap size
+ * of 128 but this is significantly bigger than typical tile size. */
+ const int4 rect = rect_clip(rect_expand(center_tile.bounds(), 64), neighbors.bounds());
+ const int2 rect_size = make_int2(rect.z - rect.x, rect.w - rect.y);
+
+ /* Adjacent tiles are in separate memory regions, copy into single buffer. */
+ array<float> merged(rect_size.x * rect_size.y * task.pass_stride);
+
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ RenderTile &ntile = neighbors.tiles[i];
+ if (!ntile.buffer) {
+ continue;
+ }
+
+ const int xmin = max(ntile.x, rect.x);
+ const int ymin = max(ntile.y, rect.y);
+ const int xmax = min(ntile.x + ntile.w, rect.z);
+ const int ymax = min(ntile.y + ntile.h, rect.w);
+
+ const size_t tile_offset = ntile.offset + xmin + ymin * ntile.stride;
+ const float *tile_buffer = (float *)ntile.buffer + tile_offset * pass_stride;
+
+ const size_t merged_stride = rect_size.x;
+ const size_t merged_offset = (xmin - rect.x) + (ymin - rect.y) * merged_stride;
+ float *merged_buffer = merged.data() + merged_offset * pass_stride;
+
+ for (int y = ymin; y < ymax; y++) {
+ for (int x = 0; x < pass_stride * (xmax - xmin); x++) {
+ merged_buffer[x] = tile_buffer[x] * scale;
+ }
+ tile_buffer += ntile.stride * pass_stride;
+ merged_buffer += merged_stride * pass_stride;
+ }
+ }
+
+ /* Denoise */
+ denoise_openimagedenoise_buffer(
+ task, merged.data(), 0, rect_size.x, 0, 0, rect_size.x, rect_size.y, 1.0f);
+
+ /* Copy back result from merged buffer. */
+ RenderTile &ntile = neighbors.target;
+ if (ntile.buffer) {
+ const int xmin = max(ntile.x, rect.x);
+ const int ymin = max(ntile.y, rect.y);
+ const int xmax = min(ntile.x + ntile.w, rect.z);
+ const int ymax = min(ntile.y + ntile.h, rect.w);
+
+ const size_t tile_offset = ntile.offset + xmin + ymin * ntile.stride;
+ float *tile_buffer = (float *)ntile.buffer + tile_offset * pass_stride;
+
+ const size_t merged_stride = rect_size.x;
+ const size_t merged_offset = (xmin - rect.x) + (ymin - rect.y) * merged_stride;
+ const float *merged_buffer = merged.data() + merged_offset * pass_stride;
+
+ for (int y = ymin; y < ymax; y++) {
+ for (int x = 0; x < pass_stride * (xmax - xmin); x += pass_stride) {
+ tile_buffer[x + 0] = merged_buffer[x + 0] * invscale;
+ tile_buffer[x + 1] = merged_buffer[x + 1] * invscale;
+ tile_buffer[x + 2] = merged_buffer[x + 2] * invscale;
+ }
+ tile_buffer += ntile.stride * pass_stride;
+ merged_buffer += merged_stride * pass_stride;
+ }
+ }
+
+ task.unmap_neighbor_tiles(neighbors, this);
+ }
+ }
+
void denoise_nlm(DenoisingTask &denoising, RenderTile &tile)
{
ProfilingHelper profiling(denoising.profiler, PROFILING_DENOISING);
@@ -1040,7 +1192,7 @@ class CPUDevice : public Device {
denoising.render_buffer.samples = tile.sample;
denoising.buffer.gpu_temporary_mem = false;
- denoising.run_denoising(&tile);
+ denoising.run_denoising(tile);
}
void thread_render(DeviceTask &task)
@@ -1070,10 +1222,23 @@ class CPUDevice : public Device {
}
}
+ /* NLM denoiser. */
DenoisingTask *denoising = NULL;
+ /* OpenImageDenoise: we can only denoise with one thread at a time, so to
+ * avoid waiting with mutex locks in the denoiser, we let only a single
+ * thread acquire denoising tiles. */
+ uint tile_types = task.tile_types;
+ bool hold_denoise_lock = false;
+ if ((tile_types & RenderTile::DENOISE) && task.denoising.type == DENOISER_OPENIMAGEDENOISE) {
+ if (!oidn_task_lock.try_lock()) {
+ tile_types &= ~RenderTile::DENOISE;
+ hold_denoise_lock = true;
+ }
+ }
+
RenderTile tile;
- while (task.acquire_tile(this, tile, task.tile_types)) {
+ while (task.acquire_tile(this, tile, tile_types)) {
if (tile.task == RenderTile::PATH_TRACE) {
if (use_split_kernel) {
device_only_memory<uchar> void_buffer(this, "void_buffer");
@@ -1108,6 +1273,10 @@ class CPUDevice : public Device {
}
}
+ if (hold_denoise_lock) {
+ oidn_task_lock.unlock();
+ }
+
profiler.remove_state(&kg->profiler);
thread_kernel_globals_free((KernelGlobals *)kgbuffer.device_pointer);
diff --git a/intern/cycles/device/device_denoising.cpp b/intern/cycles/device/device_denoising.cpp
index 89de80a5bcd..38c42d15cab 100644
--- a/intern/cycles/device/device_denoising.cpp
+++ b/intern/cycles/device/device_denoising.cpp
@@ -71,29 +71,30 @@ DenoisingTask::~DenoisingTask()
tile_info_mem.free();
}
-void DenoisingTask::set_render_buffer(RenderTile *rtiles)
+void DenoisingTask::set_render_buffer(RenderTileNeighbors &neighbors)
{
- for (int i = 0; i < 9; i++) {
- tile_info->offsets[i] = rtiles[i].offset;
- tile_info->strides[i] = rtiles[i].stride;
- tile_info->buffers[i] = rtiles[i].buffer;
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ RenderTile &rtile = neighbors.tiles[i];
+ tile_info->offsets[i] = rtile.offset;
+ tile_info->strides[i] = rtile.stride;
+ tile_info->buffers[i] = rtile.buffer;
}
- tile_info->x[0] = rtiles[3].x;
- tile_info->x[1] = rtiles[4].x;
- tile_info->x[2] = rtiles[5].x;
- tile_info->x[3] = rtiles[5].x + rtiles[5].w;
- tile_info->y[0] = rtiles[1].y;
- tile_info->y[1] = rtiles[4].y;
- tile_info->y[2] = rtiles[7].y;
- tile_info->y[3] = rtiles[7].y + rtiles[7].h;
-
- target_buffer.offset = rtiles[9].offset;
- target_buffer.stride = rtiles[9].stride;
- target_buffer.ptr = rtiles[9].buffer;
-
- if (do_prefilter && rtiles[9].buffers) {
+ tile_info->x[0] = neighbors.tiles[3].x;
+ tile_info->x[1] = neighbors.tiles[4].x;
+ tile_info->x[2] = neighbors.tiles[5].x;
+ tile_info->x[3] = neighbors.tiles[5].x + neighbors.tiles[5].w;
+ tile_info->y[0] = neighbors.tiles[1].y;
+ tile_info->y[1] = neighbors.tiles[4].y;
+ tile_info->y[2] = neighbors.tiles[7].y;
+ tile_info->y[3] = neighbors.tiles[7].y + neighbors.tiles[7].h;
+
+ target_buffer.offset = neighbors.target.offset;
+ target_buffer.stride = neighbors.target.stride;
+ target_buffer.ptr = neighbors.target.buffer;
+
+ if (do_prefilter && neighbors.target.buffers) {
target_buffer.denoising_output_offset =
- rtiles[9].buffers->params.get_denoising_prefiltered_offset();
+ neighbors.target.buffers->params.get_denoising_prefiltered_offset();
}
else {
target_buffer.denoising_output_offset = 0;
@@ -320,12 +321,11 @@ void DenoisingTask::reconstruct()
functions.solve(target_buffer.ptr);
}
-void DenoisingTask::run_denoising(RenderTile *tile)
+void DenoisingTask::run_denoising(RenderTile &tile)
{
- RenderTile rtiles[10];
- rtiles[4] = *tile;
- functions.map_neighbor_tiles(rtiles);
- set_render_buffer(rtiles);
+ RenderTileNeighbors neighbors(tile);
+ functions.map_neighbor_tiles(neighbors);
+ set_render_buffer(neighbors);
setup_denoising_buffer();
@@ -347,7 +347,7 @@ void DenoisingTask::run_denoising(RenderTile *tile)
write_buffer();
}
- functions.unmap_neighbor_tiles(rtiles);
+ functions.unmap_neighbor_tiles(neighbors);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_denoising.h b/intern/cycles/device/device_denoising.h
index 4c122e981eb..2c0dc23b44a 100644
--- a/intern/cycles/device/device_denoising.h
+++ b/intern/cycles/device/device_denoising.h
@@ -102,8 +102,8 @@ class DenoisingTask {
device_ptr output_ptr)>
detect_outliers;
function<bool(int out_offset, device_ptr frop_ptr, device_ptr buffer_ptr)> write_feature;
- function<void(RenderTile *rtiles)> map_neighbor_tiles;
- function<void(RenderTile *rtiles)> unmap_neighbor_tiles;
+ function<void(RenderTileNeighbors &neighbors)> map_neighbor_tiles;
+ function<void(RenderTileNeighbors &neighbors)> unmap_neighbor_tiles;
} functions;
/* Stores state of the current Reconstruction operation,
@@ -154,7 +154,7 @@ class DenoisingTask {
DenoisingTask(Device *device, const DeviceTask &task);
~DenoisingTask();
- void run_denoising(RenderTile *tile);
+ void run_denoising(RenderTile &tile);
struct DenoiseBuffers {
int pass_stride;
@@ -179,7 +179,7 @@ class DenoisingTask {
protected:
Device *device;
- void set_render_buffer(RenderTile *rtiles);
+ void set_render_buffer(RenderTileNeighbors &neighbors);
void setup_denoising_buffer();
void prefilter_shadowing();
void prefilter_features();
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index fd14bbdccc5..9ea8782d0f0 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -177,8 +177,11 @@ class MultiDevice : public Device {
return false;
if (requested_features.use_denoising) {
+ /* Only need denoising feature, everything else is unused. */
+ DeviceRequestedFeatures denoising_features;
+ denoising_features.use_denoising = true;
foreach (SubDevice &sub, denoising_devices)
- if (!sub.device->load_kernels(requested_features))
+ if (!sub.device->load_kernels(denoising_features))
return false;
}
@@ -581,20 +584,22 @@ class MultiDevice : public Device {
return -1;
}
- void map_neighbor_tiles(Device *sub_device, RenderTile *tiles)
+ void map_neighbor_tiles(Device *sub_device, RenderTileNeighbors &neighbors)
{
- for (int i = 0; i < 9; i++) {
- if (!tiles[i].buffers) {
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ RenderTile &tile = neighbors.tiles[i];
+
+ if (!tile.buffers) {
continue;
}
- device_vector<float> &mem = tiles[i].buffers->buffer;
- tiles[i].buffer = mem.device_pointer;
+ device_vector<float> &mem = tile.buffers->buffer;
+ tile.buffer = mem.device_pointer;
if (mem.device == this && matching_rendering_and_denoising_devices) {
/* Skip unnecessary copies in viewport mode (buffer covers the
* whole image), but still need to fix up the tile device pointer. */
- map_tile(sub_device, tiles[i]);
+ map_tile(sub_device, tile);
continue;
}
@@ -607,15 +612,15 @@ class MultiDevice : public Device {
* also required for the case where a CPU thread is denoising
* a tile rendered on the GPU. In that case we have to avoid
* overwriting the buffer being de-noised by the CPU thread. */
- if (!tiles[i].buffers->map_neighbor_copied) {
- tiles[i].buffers->map_neighbor_copied = true;
+ if (!tile.buffers->map_neighbor_copied) {
+ tile.buffers->map_neighbor_copied = true;
mem.copy_from_device();
}
if (mem.device == this) {
/* Can re-use memory if tile is already allocated on the sub device. */
- map_tile(sub_device, tiles[i]);
- mem.swap_device(sub_device, mem.device_size, tiles[i].buffer);
+ map_tile(sub_device, tile);
+ mem.swap_device(sub_device, mem.device_size, tile.buffer);
}
else {
mem.swap_device(sub_device, 0, 0);
@@ -623,40 +628,42 @@ class MultiDevice : public Device {
mem.copy_to_device();
- tiles[i].buffer = mem.device_pointer;
- tiles[i].device_size = mem.device_size;
+ tile.buffer = mem.device_pointer;
+ tile.device_size = mem.device_size;
mem.restore_device();
}
}
}
- void unmap_neighbor_tiles(Device *sub_device, RenderTile *tiles)
+ void unmap_neighbor_tiles(Device *sub_device, RenderTileNeighbors &neighbors)
{
- device_vector<float> &mem = tiles[9].buffers->buffer;
+ RenderTile &target_tile = neighbors.target;
+ device_vector<float> &mem = target_tile.buffers->buffer;
if (mem.device == this && matching_rendering_and_denoising_devices) {
return;
}
/* Copy denoised result back to the host. */
- mem.swap_device(sub_device, tiles[9].device_size, tiles[9].buffer);
+ mem.swap_device(sub_device, target_tile.device_size, target_tile.buffer);
mem.copy_from_device();
mem.restore_device();
/* Copy denoised result to the original device. */
mem.copy_to_device();
- for (int i = 0; i < 9; i++) {
- if (!tiles[i].buffers) {
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ RenderTile &tile = neighbors.tiles[i];
+ if (!tile.buffers) {
continue;
}
- device_vector<float> &mem = tiles[i].buffers->buffer;
+ device_vector<float> &mem = tile.buffers->buffer;
if (mem.device != sub_device && mem.device != this) {
/* Free up memory again if it was allocated for the copy above. */
- mem.swap_device(sub_device, tiles[i].device_size, tiles[i].buffer);
+ mem.swap_device(sub_device, tile.device_size, tile.buffer);
sub_device->mem_free(mem);
mem.restore_device();
}
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index ececca3df53..1cc45983565 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -131,8 +131,12 @@ class OptiXDevice : public CUDADevice {
PG_RGEN,
PG_MISS,
PG_HITD, // Default hit group
- PG_HITL, // __BVH_LOCAL__ hit group
PG_HITS, // __SHADOW_RECORD_ALL__ hit group
+ PG_HITL, // __BVH_LOCAL__ hit group (only used for triangles)
+# if OPTIX_ABI_VERSION >= 36
+ PG_HITD_MOTION,
+ PG_HITS_MOTION,
+# endif
# ifdef WITH_CYCLES_DEBUG
PG_EXCP,
# endif
@@ -177,6 +181,7 @@ class OptiXDevice : public CUDADevice {
OptixDeviceContext context = NULL;
OptixModule optix_module = NULL; // All necessary OptiX kernels are in one module
+ OptixModule builtin_modules[2] = {};
OptixPipeline pipelines[NUM_PIPELINES] = {};
bool motion_blur = false;
@@ -264,6 +269,9 @@ class OptiXDevice : public CUDADevice {
// Unload modules
if (optix_module != NULL)
optixModuleDestroy(optix_module);
+ for (unsigned int i = 0; i < 2; ++i)
+ if (builtin_modules[i] != NULL)
+ optixModuleDestroy(builtin_modules[i]);
for (unsigned int i = 0; i < NUM_PIPELINES; ++i)
if (pipelines[i] != NULL)
optixPipelineDestroy(pipelines[i]);
@@ -338,6 +346,12 @@ class OptiXDevice : public CUDADevice {
optixModuleDestroy(optix_module);
optix_module = NULL;
}
+ for (unsigned int i = 0; i < 2; ++i) {
+ if (builtin_modules[i] != NULL) {
+ optixModuleDestroy(builtin_modules[i]);
+ builtin_modules[i] = NULL;
+ }
+ }
for (unsigned int i = 0; i < NUM_PIPELINES; ++i) {
if (pipelines[i] != NULL) {
optixPipelineDestroy(pipelines[i]);
@@ -369,6 +383,18 @@ class OptiXDevice : public CUDADevice {
# endif
pipeline_options.pipelineLaunchParamsVariableName = "__params"; // See kernel_globals.h
+# if OPTIX_ABI_VERSION >= 36
+ pipeline_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE;
+ if (requested_features.use_hair) {
+ if (DebugFlags().optix.curves_api && requested_features.use_hair_thick) {
+ pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE;
+ }
+ else {
+ pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
+ }
+ }
+# endif
+
// Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
// This is necessary since objects may be reported to have motion if the Vector pass is
// active, but may still need to be rendered without motion blur if that isn't active as well
@@ -442,6 +468,34 @@ class OptiXDevice : public CUDADevice {
group_descs[PG_HITD].hitgroup.entryFunctionNameIS = "__intersection__curve_ribbon";
group_descs[PG_HITS].hitgroup.entryFunctionNameIS = "__intersection__curve_ribbon";
}
+
+# if OPTIX_ABI_VERSION >= 36
+ if (DebugFlags().optix.curves_api && requested_features.use_hair_thick) {
+ OptixBuiltinISOptions builtin_options;
+ builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
+ builtin_options.usesMotionBlur = false;
+
+ check_result_optix_ret(optixBuiltinISModuleGet(
+ context, &module_options, &pipeline_options, &builtin_options, &builtin_modules[0]));
+
+ group_descs[PG_HITD].hitgroup.moduleIS = builtin_modules[0];
+ group_descs[PG_HITD].hitgroup.entryFunctionNameIS = nullptr;
+ group_descs[PG_HITS].hitgroup.moduleIS = builtin_modules[0];
+ group_descs[PG_HITS].hitgroup.entryFunctionNameIS = nullptr;
+
+ if (motion_blur) {
+ builtin_options.usesMotionBlur = true;
+
+ check_result_optix_ret(optixBuiltinISModuleGet(
+ context, &module_options, &pipeline_options, &builtin_options, &builtin_modules[1]));
+
+ group_descs[PG_HITD_MOTION] = group_descs[PG_HITD];
+ group_descs[PG_HITD_MOTION].hitgroup.moduleIS = builtin_modules[1];
+ group_descs[PG_HITS_MOTION] = group_descs[PG_HITS];
+ group_descs[PG_HITS_MOTION].hitgroup.moduleIS = builtin_modules[1];
+ }
+ }
+# endif
}
if (requested_features.use_subsurface || requested_features.use_shader_raytrace) {
@@ -493,8 +547,14 @@ class OptiXDevice : public CUDADevice {
unsigned int trace_css = stack_size[PG_HITD].cssCH;
// This is based on the maximum of closest-hit and any-hit/intersection programs
trace_css = std::max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH);
- trace_css = std::max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH);
trace_css = std::max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH);
+ trace_css = std::max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH);
+# if OPTIX_ABI_VERSION >= 36
+ trace_css = std::max(trace_css,
+ stack_size[PG_HITD_MOTION].cssIS + stack_size[PG_HITD_MOTION].cssAH);
+ trace_css = std::max(trace_css,
+ stack_size[PG_HITS_MOTION].cssIS + stack_size[PG_HITS_MOTION].cssAH);
+# endif
OptixPipelineLinkOptions link_options;
link_options.maxTraceDepth = 1;
@@ -503,17 +563,23 @@ class OptiXDevice : public CUDADevice {
# else
link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
# endif
- link_options.overrideUsesMotionBlur = pipeline_options.usesMotionBlur;
+# if OPTIX_ABI_VERSION < 24
+ link_options.overrideUsesMotionBlur = motion_blur;
+# endif
{ // Create path tracing pipeline
OptixProgramGroup pipeline_groups[] = {
- groups[PG_RGEN],
- groups[PG_MISS],
- groups[PG_HITD],
- groups[PG_HITS],
- groups[PG_HITL],
+ groups[PG_RGEN],
+ groups[PG_MISS],
+ groups[PG_HITD],
+ groups[PG_HITS],
+ groups[PG_HITL],
+# if OPTIX_ABI_VERSION >= 36
+ groups[PG_HITD_MOTION],
+ groups[PG_HITS_MOTION],
+# endif
# ifdef WITH_CYCLES_DEBUG
- groups[PG_EXCP],
+ groups[PG_EXCP],
# endif
};
check_result_optix_ret(
@@ -530,8 +596,8 @@ class OptiXDevice : public CUDADevice {
const unsigned int css = stack_size[PG_RGEN].cssRG + link_options.maxTraceDepth * trace_css;
// Set stack size depending on pipeline options
- check_result_optix_ret(optixPipelineSetStackSize(
- pipelines[PIP_PATH_TRACE], 0, 0, css, (pipeline_options.usesMotionBlur ? 3 : 2)));
+ check_result_optix_ret(
+ optixPipelineSetStackSize(pipelines[PIP_PATH_TRACE], 0, 0, css, (motion_blur ? 3 : 2)));
}
// Only need to create shader evaluation pipeline if one of these features is used:
@@ -541,15 +607,19 @@ class OptiXDevice : public CUDADevice {
if (use_shader_eval_pipeline) { // Create shader evaluation pipeline
OptixProgramGroup pipeline_groups[] = {
- groups[PG_BAKE],
- groups[PG_DISP],
- groups[PG_BACK],
- groups[PG_MISS],
- groups[PG_HITD],
- groups[PG_HITS],
- groups[PG_HITL],
+ groups[PG_BAKE],
+ groups[PG_DISP],
+ groups[PG_BACK],
+ groups[PG_MISS],
+ groups[PG_HITD],
+ groups[PG_HITS],
+ groups[PG_HITL],
+# if OPTIX_ABI_VERSION >= 36
+ groups[PG_HITD_MOTION],
+ groups[PG_HITS_MOTION],
+# endif
# ifdef WITH_CYCLES_DEBUG
- groups[PG_EXCP],
+ groups[PG_EXCP],
# endif
};
check_result_optix_ret(
@@ -672,7 +742,11 @@ class OptiXDevice : public CUDADevice {
sbt_params.missRecordCount = 1;
sbt_params.hitgroupRecordBase = sbt_data.device_pointer + PG_HITD * sizeof(SbtRecord);
sbt_params.hitgroupRecordStrideInBytes = sizeof(SbtRecord);
- sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITL, PG_HITS
+# if OPTIX_ABI_VERSION >= 36
+ sbt_params.hitgroupRecordCount = 5; // PG_HITD(_MOTION), PG_HITS(_MOTION), PG_HITL
+# else
+ sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITS, PG_HITL
+# endif
// Launch the ray generation program
check_result_optix(optixLaunch(pipelines[PIP_PATH_TRACE],
@@ -727,19 +801,18 @@ class OptiXDevice : public CUDADevice {
// 0 1 2
// 3 4 5
// 6 7 8 9
- RenderTile rtiles[10];
- rtiles[4] = rtile;
- task.map_neighbor_tiles(rtiles, this);
- rtile = rtiles[4]; // Tile may have been modified by mapping code
+ RenderTileNeighbors neighbors(rtile);
+ task.map_neighbor_tiles(neighbors, this);
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+ RenderTile &target_tile = neighbors.target;
+ rtile = center_tile; // Tile may have been modified by mapping code
// Calculate size of the tile to denoise (including overlap)
- int4 rect = make_int4(
- rtiles[4].x, rtiles[4].y, rtiles[4].x + rtiles[4].w, rtiles[4].y + rtiles[4].h);
+ int4 rect = center_tile.bounds();
// Overlap between tiles has to be at least 64 pixels
// TODO(pmours): Query this value from OptiX
rect = rect_expand(rect, 64);
- int4 clip_rect = make_int4(
- rtiles[3].x, rtiles[1].y, rtiles[5].x + rtiles[5].w, rtiles[7].y + rtiles[7].h);
+ int4 clip_rect = neighbors.bounds();
rect = rect_clip(rect, clip_rect);
int2 rect_size = make_int2(rect.z - rect.x, rect.w - rect.y);
int2 overlap_offset = make_int2(rtile.x - rect.x, rtile.y - rect.y);
@@ -760,14 +833,14 @@ class OptiXDevice : public CUDADevice {
device_only_memory<float> input(this, "denoiser input");
device_vector<TileInfo> tile_info_mem(this, "denoiser tile info", MEM_READ_WRITE);
- if ((!rtiles[0].buffer || rtiles[0].buffer == rtile.buffer) &&
- (!rtiles[1].buffer || rtiles[1].buffer == rtile.buffer) &&
- (!rtiles[2].buffer || rtiles[2].buffer == rtile.buffer) &&
- (!rtiles[3].buffer || rtiles[3].buffer == rtile.buffer) &&
- (!rtiles[5].buffer || rtiles[5].buffer == rtile.buffer) &&
- (!rtiles[6].buffer || rtiles[6].buffer == rtile.buffer) &&
- (!rtiles[7].buffer || rtiles[7].buffer == rtile.buffer) &&
- (!rtiles[8].buffer || rtiles[8].buffer == rtile.buffer)) {
+ bool contiguous_memory = true;
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ if (neighbors.tiles[i].buffer && neighbors.tiles[i].buffer != rtile.buffer) {
+ contiguous_memory = false;
+ }
+ }
+
+ if (contiguous_memory) {
// Tiles are in continous memory, so can just subtract overlap offset
input_ptr -= (overlap_offset.x + overlap_offset.y * rtile.stride) * pixel_stride;
// Stride covers the whole width of the image and not just a single tile
@@ -782,19 +855,19 @@ class OptiXDevice : public CUDADevice {
input_stride *= rect_size.x;
TileInfo *tile_info = tile_info_mem.alloc(1);
- for (int i = 0; i < 9; i++) {
- tile_info->offsets[i] = rtiles[i].offset;
- tile_info->strides[i] = rtiles[i].stride;
- tile_info->buffers[i] = rtiles[i].buffer;
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ tile_info->offsets[i] = neighbors.tiles[i].offset;
+ tile_info->strides[i] = neighbors.tiles[i].stride;
+ tile_info->buffers[i] = neighbors.tiles[i].buffer;
}
- tile_info->x[0] = rtiles[3].x;
- tile_info->x[1] = rtiles[4].x;
- tile_info->x[2] = rtiles[5].x;
- tile_info->x[3] = rtiles[5].x + rtiles[5].w;
- tile_info->y[0] = rtiles[1].y;
- tile_info->y[1] = rtiles[4].y;
- tile_info->y[2] = rtiles[7].y;
- tile_info->y[3] = rtiles[7].y + rtiles[7].h;
+ tile_info->x[0] = neighbors.tiles[3].x;
+ tile_info->x[1] = neighbors.tiles[4].x;
+ tile_info->x[2] = neighbors.tiles[5].x;
+ tile_info->x[3] = neighbors.tiles[5].x + neighbors.tiles[5].w;
+ tile_info->y[0] = neighbors.tiles[1].y;
+ tile_info->y[1] = neighbors.tiles[4].y;
+ tile_info->y[2] = neighbors.tiles[7].y;
+ tile_info->y[3] = neighbors.tiles[7].y + neighbors.tiles[7].h;
tile_info_mem.copy_to_device();
void *args[] = {
@@ -804,7 +877,7 @@ class OptiXDevice : public CUDADevice {
# if OPTIX_DENOISER_NO_PIXEL_STRIDE
device_only_memory<float> input_rgb(this, "denoiser input rgb");
- input_rgb.alloc_to_device(rect_size.x * rect_size.y * 3 * task.denoising.optix_input_passes);
+ input_rgb.alloc_to_device(rect_size.x * rect_size.y * 3 * task.denoising.input_passes);
void *input_args[] = {&input_rgb.device_pointer,
&input_ptr,
@@ -813,7 +886,7 @@ class OptiXDevice : public CUDADevice {
&input_stride,
&task.pass_stride,
const_cast<int *>(pass_offset),
- &task.denoising.optix_input_passes,
+ &task.denoising.input_passes,
&rtile.sample};
launch_filter_kernel(
"kernel_cuda_filter_convert_to_rgb", rect_size.x, rect_size.y, input_args);
@@ -824,7 +897,7 @@ class OptiXDevice : public CUDADevice {
# endif
const bool recreate_denoiser = (denoiser == NULL) ||
- (task.denoising.optix_input_passes != denoiser_input_passes);
+ (task.denoising.input_passes != denoiser_input_passes);
if (recreate_denoiser) {
// Destroy existing handle before creating new one
if (denoiser != NULL) {
@@ -833,23 +906,29 @@ class OptiXDevice : public CUDADevice {
// Create OptiX denoiser handle on demand when it is first used
OptixDenoiserOptions denoiser_options;
- assert(task.denoising.optix_input_passes >= 1 && task.denoising.optix_input_passes <= 3);
+ assert(task.denoising.input_passes >= 1 && task.denoising.input_passes <= 3);
denoiser_options.inputKind = static_cast<OptixDenoiserInputKind>(
- OPTIX_DENOISER_INPUT_RGB + (task.denoising.optix_input_passes - 1));
+ OPTIX_DENOISER_INPUT_RGB + (task.denoising.input_passes - 1));
+# if OPTIX_ABI_VERSION < 28
denoiser_options.pixelFormat = OPTIX_PIXEL_FORMAT_FLOAT3;
+# endif
check_result_optix_ret(optixDenoiserCreate(context, &denoiser_options, &denoiser));
check_result_optix_ret(
optixDenoiserSetModel(denoiser, OPTIX_DENOISER_MODEL_KIND_HDR, NULL, 0));
// OptiX denoiser handle was created with the requested number of input passes
- denoiser_input_passes = task.denoising.optix_input_passes;
+ denoiser_input_passes = task.denoising.input_passes;
}
OptixDenoiserSizes sizes = {};
check_result_optix_ret(
optixDenoiserComputeMemoryResources(denoiser, rect_size.x, rect_size.y, &sizes));
+# if OPTIX_ABI_VERSION < 28
const size_t scratch_size = sizes.recommendedScratchSizeInBytes;
+# else
+ const size_t scratch_size = sizes.withOverlapScratchSizeInBytes;
+# endif
const size_t scratch_offset = sizes.stateSizeInBytes;
// Allocate denoiser state if tile size has changed since last setup
@@ -897,10 +976,10 @@ class OptiXDevice : public CUDADevice {
int2 output_offset = overlap_offset;
overlap_offset = make_int2(0, 0); // Not supported by denoiser API, so apply manually
# else
- output_layers[0].data = rtiles[9].buffer + pixel_offset;
- output_layers[0].width = rtiles[9].w;
- output_layers[0].height = rtiles[9].h;
- output_layers[0].rowStrideInBytes = rtiles[9].stride * pixel_stride;
+ output_layers[0].data = target_tile.buffer + pixel_offset;
+ output_layers[0].width = target_tile.w;
+ output_layers[0].height = target_tile.h;
+ output_layers[0].rowStrideInBytes = target_tile.stride * pixel_stride;
output_layers[0].pixelStrideInBytes = pixel_stride;
# endif
output_layers[0].format = OPTIX_PIXEL_FORMAT_FLOAT3;
@@ -913,7 +992,7 @@ class OptiXDevice : public CUDADevice {
denoiser_state.device_pointer,
scratch_offset,
input_layers,
- task.denoising.optix_input_passes,
+ task.denoising.input_passes,
overlap_offset.x,
overlap_offset.y,
output_layers,
@@ -922,26 +1001,26 @@ class OptiXDevice : public CUDADevice {
# if OPTIX_DENOISER_NO_PIXEL_STRIDE
void *output_args[] = {&input_ptr,
- &rtiles[9].buffer,
+ &target_tile.buffer,
&output_offset.x,
&output_offset.y,
&rect_size.x,
&rect_size.y,
- &rtiles[9].x,
- &rtiles[9].y,
- &rtiles[9].w,
- &rtiles[9].h,
- &rtiles[9].offset,
- &rtiles[9].stride,
+ &target_tile.x,
+ &target_tile.y,
+ &target_tile.w,
+ &target_tile.h,
+ &target_tile.offset,
+ &target_tile.stride,
&task.pass_stride,
&rtile.sample};
launch_filter_kernel(
- "kernel_cuda_filter_convert_from_rgb", rtiles[9].w, rtiles[9].h, output_args);
+ "kernel_cuda_filter_convert_from_rgb", target_tile.w, target_tile.h, output_args);
# endif
check_result_cuda_ret(cuStreamSynchronize(0));
- task.unmap_neighbor_tiles(rtiles, this);
+ task.unmap_neighbor_tiles(neighbors, this);
}
else {
// Run CUDA denoising kernels
@@ -993,7 +1072,11 @@ class OptiXDevice : public CUDADevice {
sbt_params.missRecordCount = 1;
sbt_params.hitgroupRecordBase = sbt_data.device_pointer + PG_HITD * sizeof(SbtRecord);
sbt_params.hitgroupRecordStrideInBytes = sizeof(SbtRecord);
- sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITL, PG_HITS
+# if OPTIX_ABI_VERSION >= 36
+ sbt_params.hitgroupRecordCount = 5; // PG_HITD(_MOTION), PG_HITS(_MOTION), PG_HITL
+# else
+ sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITS, PG_HITL
+# endif
check_result_optix(optixLaunch(pipelines[PIP_SHADER_EVAL],
cuda_stream[thread_index],
@@ -1070,7 +1153,7 @@ class OptiXDevice : public CUDADevice {
&build_input,
1,
temp_mem.device_pointer,
- temp_mem.device_size,
+ sizes.tempSizeInBytes,
out_data,
sizes.outputSizeInBytes,
&out_handle,
@@ -1142,7 +1225,6 @@ class OptiXDevice : public CUDADevice {
continue;
}
- const size_t num_curves = hair->num_curves();
const size_t num_segments = hair->num_segments();
size_t num_motion_steps = 1;
@@ -1152,7 +1234,18 @@ class OptiXDevice : public CUDADevice {
}
device_vector<OptixAabb> aabb_data(this, "temp_aabb_data", MEM_READ_ONLY);
- aabb_data.alloc(num_segments * num_motion_steps);
+# if OPTIX_ABI_VERSION >= 36
+ device_vector<int> index_data(this, "temp_index_data", MEM_READ_ONLY);
+ device_vector<float4> vertex_data(this, "temp_vertex_data", MEM_READ_ONLY);
+ // Four control points for each curve segment
+ const size_t num_vertices = num_segments * 4;
+ if (DebugFlags().optix.curves_api && hair->curve_shape == CURVE_THICK) {
+ index_data.alloc(num_segments);
+ vertex_data.alloc(num_vertices * num_motion_steps);
+ }
+ else
+# endif
+ aabb_data.alloc(num_segments * num_motion_steps);
// Get AABBs for each motion step
for (size_t step = 0; step < num_motion_steps; ++step) {
@@ -1165,44 +1258,127 @@ class OptiXDevice : public CUDADevice {
keys = motion_keys->data_float3() + attr_offset * hair->curve_keys.size();
}
- size_t i = step * num_segments;
- for (size_t j = 0; j < num_curves; ++j) {
- const Hair::Curve c = hair->get_curve(j);
-
- for (size_t k = 0; k < c.num_segments(); ++i, ++k) {
- BoundBox bounds = BoundBox::empty;
- c.bounds_grow(k, keys, hair->curve_radius.data(), bounds);
-
- aabb_data[i].minX = bounds.min.x;
- aabb_data[i].minY = bounds.min.y;
- aabb_data[i].minZ = bounds.min.z;
- aabb_data[i].maxX = bounds.max.x;
- aabb_data[i].maxY = bounds.max.y;
- aabb_data[i].maxZ = bounds.max.z;
+ for (size_t j = 0, i = 0; j < hair->num_curves(); ++j) {
+ const Hair::Curve curve = hair->get_curve(j);
+
+ for (int segment = 0; segment < curve.num_segments(); ++segment, ++i) {
+# if OPTIX_ABI_VERSION >= 36
+ if (DebugFlags().optix.curves_api && hair->curve_shape == CURVE_THICK) {
+ int k0 = curve.first_key + segment;
+ int k1 = k0 + 1;
+ int ka = max(k0 - 1, curve.first_key);
+ int kb = min(k1 + 1, curve.first_key + curve.num_keys - 1);
+
+ const float4 px = make_float4(keys[ka].x, keys[k0].x, keys[k1].x, keys[kb].x);
+ const float4 py = make_float4(keys[ka].y, keys[k0].y, keys[k1].y, keys[kb].y);
+ const float4 pz = make_float4(keys[ka].z, keys[k0].z, keys[k1].z, keys[kb].z);
+ const float4 pw = make_float4(hair->curve_radius[ka],
+ hair->curve_radius[k0],
+ hair->curve_radius[k1],
+ hair->curve_radius[kb]);
+
+ // Convert Catmull-Rom data to Bezier spline
+ static const float4 cr2bsp0 = make_float4(+7, -4, +5, -2) / 6.f;
+ static const float4 cr2bsp1 = make_float4(-2, 11, -4, +1) / 6.f;
+ static const float4 cr2bsp2 = make_float4(+1, -4, 11, -2) / 6.f;
+ static const float4 cr2bsp3 = make_float4(-2, +5, -4, +7) / 6.f;
+
+ index_data[i] = i * 4;
+ float4 *const v = vertex_data.data() + step * num_vertices + index_data[i];
+ v[0] = make_float4(
+ dot(cr2bsp0, px), dot(cr2bsp0, py), dot(cr2bsp0, pz), dot(cr2bsp0, pw));
+ v[1] = make_float4(
+ dot(cr2bsp1, px), dot(cr2bsp1, py), dot(cr2bsp1, pz), dot(cr2bsp1, pw));
+ v[2] = make_float4(
+ dot(cr2bsp2, px), dot(cr2bsp2, py), dot(cr2bsp2, pz), dot(cr2bsp2, pw));
+ v[3] = make_float4(
+ dot(cr2bsp3, px), dot(cr2bsp3, py), dot(cr2bsp3, pz), dot(cr2bsp3, pw));
+ }
+ else
+# endif
+ {
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(segment, keys, hair->curve_radius.data(), bounds);
+
+ const size_t index = step * num_segments + i;
+ aabb_data[index].minX = bounds.min.x;
+ aabb_data[index].minY = bounds.min.y;
+ aabb_data[index].minZ = bounds.min.z;
+ aabb_data[index].maxX = bounds.max.x;
+ aabb_data[index].maxY = bounds.max.y;
+ aabb_data[index].maxZ = bounds.max.z;
+ }
}
}
}
// Upload AABB data to GPU
aabb_data.copy_to_device();
+# if OPTIX_ABI_VERSION >= 36
+ index_data.copy_to_device();
+ vertex_data.copy_to_device();
+# endif
vector<device_ptr> aabb_ptrs;
aabb_ptrs.reserve(num_motion_steps);
+# if OPTIX_ABI_VERSION >= 36
+ vector<device_ptr> width_ptrs;
+ vector<device_ptr> vertex_ptrs;
+ width_ptrs.reserve(num_motion_steps);
+ vertex_ptrs.reserve(num_motion_steps);
+# endif
for (size_t step = 0; step < num_motion_steps; ++step) {
aabb_ptrs.push_back(aabb_data.device_pointer + step * num_segments * sizeof(OptixAabb));
+# if OPTIX_ABI_VERSION >= 36
+ const device_ptr base_ptr = vertex_data.device_pointer +
+ step * num_vertices * sizeof(float4);
+ width_ptrs.push_back(base_ptr + 3 * sizeof(float)); // Offset by vertex size
+ vertex_ptrs.push_back(base_ptr);
+# endif
}
- // Disable visibility test anyhit program, since it is already checked during intersection
- // Those trace calls that require anyhit can force it with OPTIX_RAY_FLAG_ENFORCE_ANYHIT
- unsigned int build_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT;
+ // Force a single any-hit call, so shadow record-all behavior works correctly
+ unsigned int build_flags = OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;
OptixBuildInput build_input = {};
- build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
- build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
- build_input.aabbArray.numPrimitives = num_segments;
- build_input.aabbArray.strideInBytes = sizeof(OptixAabb);
- build_input.aabbArray.flags = &build_flags;
- build_input.aabbArray.numSbtRecords = 1;
- build_input.aabbArray.primitiveIndexOffset = hair->optix_prim_offset;
+# if OPTIX_ABI_VERSION >= 36
+ if (DebugFlags().optix.curves_api && hair->curve_shape == CURVE_THICK) {
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES;
+ build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
+ build_input.curveArray.numPrimitives = num_segments;
+ build_input.curveArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data();
+ build_input.curveArray.numVertices = num_vertices;
+ build_input.curveArray.vertexStrideInBytes = sizeof(float4);
+ build_input.curveArray.widthBuffers = (CUdeviceptr *)width_ptrs.data();
+ build_input.curveArray.widthStrideInBytes = sizeof(float4);
+ build_input.curveArray.indexBuffer = (CUdeviceptr)index_data.device_pointer;
+ build_input.curveArray.indexStrideInBytes = sizeof(int);
+ build_input.curveArray.flag = build_flags;
+ build_input.curveArray.primitiveIndexOffset = hair->optix_prim_offset;
+ }
+ else
+# endif
+ {
+ // Disable visibility test any-hit program, since it is already checked during
+ // intersection. Those trace calls that require anyhit can force it with a ray flag.
+ build_flags |= OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT;
+
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
+# if OPTIX_ABI_VERSION < 23
+ build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.aabbArray.numPrimitives = num_segments;
+ build_input.aabbArray.strideInBytes = sizeof(OptixAabb);
+ build_input.aabbArray.flags = &build_flags;
+ build_input.aabbArray.numSbtRecords = 1;
+ build_input.aabbArray.primitiveIndexOffset = hair->optix_prim_offset;
+# else
+ build_input.customPrimitiveArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.customPrimitiveArray.numPrimitives = num_segments;
+ build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb);
+ build_input.customPrimitiveArray.flags = &build_flags;
+ build_input.customPrimitiveArray.numSbtRecords = 1;
+ build_input.customPrimitiveArray.primitiveIndexOffset = hair->optix_prim_offset;
+# endif
+ }
// Allocate memory for new BLAS and build it
OptixTraversableHandle handle;
@@ -1257,8 +1433,8 @@ class OptiXDevice : public CUDADevice {
vertex_ptrs.push_back(vertex_data.device_pointer + num_verts * step * sizeof(float3));
}
- // No special build flags for triangle primitives
- unsigned int build_flags = OPTIX_GEOMETRY_FLAG_NONE;
+ // Force a single any-hit call, so shadow record-all behavior works correctly
+ unsigned int build_flags = OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;
OptixBuildInput build_input = {};
build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES;
build_input.triangleArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data();
@@ -1324,9 +1500,26 @@ class OptiXDevice : public CUDADevice {
// Set user instance ID to object index
instance.instanceId = ob->get_device_index();
- // Volumes have a special bit set in the visibility mask so a trace can mask only volumes
- // See 'scene_intersect_volume' in bvh.h
- instance.visibilityMask = (ob->geometry->has_volume ? 3 : 1);
+ // Have to have at least one bit in the mask, or else instance would always be culled
+ instance.visibilityMask = 1;
+
+ if (ob->geometry->has_volume) {
+ // Volumes have a special bit set in the visibility mask so a trace can mask only volumes
+ instance.visibilityMask |= 2;
+ }
+
+ if (ob->geometry->type == Geometry::HAIR) {
+ // Same applies to curves (so they can be skipped in local trace calls)
+ instance.visibilityMask |= 4;
+
+# if OPTIX_ABI_VERSION >= 36
+ if (motion_blur && ob->geometry->has_motion_blur() && DebugFlags().optix.curves_api &&
+ static_cast<const Hair *>(ob->geometry)->curve_shape == CURVE_THICK) {
+ // Select between motion blur and non-motion blur built-in intersection module
+ instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
+ }
+# endif
+ }
// Insert motion traversable if object has motion
if (motion_blur && ob->use_motion()) {
diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h
index 600973b8100..fd380788282 100644
--- a/intern/cycles/device/device_task.h
+++ b/intern/cycles/device/device_task.h
@@ -29,6 +29,7 @@ CCL_NAMESPACE_BEGIN
class Device;
class RenderBuffers;
class RenderTile;
+class RenderTileNeighbors;
class Tile;
enum DenoiserType {
@@ -41,6 +42,14 @@ enum DenoiserType {
DENOISER_ALL = ~0,
};
+enum DenoiserInput {
+ DENOISER_INPUT_RGB = 1,
+ DENOISER_INPUT_RGB_ALBEDO = 2,
+ DENOISER_INPUT_RGB_ALBEDO_NORMAL = 3,
+
+ DENOISER_INPUT_NUM,
+};
+
typedef int DenoiserTypeMask;
class DenoiseParams {
@@ -72,10 +81,10 @@ class DenoiseParams {
/* Clamp the input to the range of +-1e8. Should be enough for any legitimate data. */
bool clamp_input;
- /** Optix Denoiser **/
+ /** OIDN/Optix Denoiser **/
- /* Passes handed over to the OptiX denoiser (default to color + albedo). */
- int optix_input_passes;
+ /* Passes handed over to the OIDN/OptiX denoiser (default to color + albedo). */
+ DenoiserInput input_passes;
DenoiseParams()
{
@@ -91,7 +100,7 @@ class DenoiseParams {
neighbor_frames = 2;
clamp_input = true;
- optix_input_passes = 2;
+ input_passes = DENOISER_INPUT_RGB_ALBEDO_NORMAL;
start_sample = 0;
}
@@ -150,8 +159,8 @@ class DeviceTask {
function<void(RenderTile &)> update_tile_sample;
function<void(RenderTile &)> release_tile;
function<bool()> get_cancel;
- function<void(RenderTile *, Device *)> map_neighbor_tiles;
- function<void(RenderTile *, Device *)> unmap_neighbor_tiles;
+ function<void(RenderTileNeighbors &, Device *)> map_neighbor_tiles;
+ function<void(RenderTileNeighbors &, Device *)> unmap_neighbor_tiles;
uint tile_types;
DenoiseParams denoising;
diff --git a/intern/cycles/device/opencl/device_opencl_impl.cpp b/intern/cycles/device/opencl/device_opencl_impl.cpp
index 8c94815b193..e851749949d 100644
--- a/intern/cycles/device/opencl/device_opencl_impl.cpp
+++ b/intern/cycles/device/opencl/device_opencl_impl.cpp
@@ -1850,7 +1850,7 @@ void OpenCLDevice::denoise(RenderTile &rtile, DenoisingTask &denoising)
denoising.render_buffer.samples = rtile.sample;
denoising.buffer.gpu_temporary_mem = true;
- denoising.run_denoising(&rtile);
+ denoising.run_denoising(rtile);
}
void OpenCLDevice::shader(DeviceTask &task)
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 80b58f46329..3049f243ae9 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -172,11 +172,11 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
0.0f,
ray->t,
ray->time,
- 0xFF,
+ 0xF,
OPTIX_RAY_FLAG_NONE,
+ 0, // SBT offset for PG_HITD
0,
0,
- 0, // SBT offset for PG_HITD
p0,
p1,
p2,
@@ -264,12 +264,13 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals *kg,
0.0f,
ray->t,
ray->time,
+ // Skip curves
+ 0x3,
// Need to always call into __anyhit__kernel_optix_local_hit
- 0xFF,
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
- 1,
+ 2, // SBT offset for PG_HITL
+ 0,
0,
- 0, // SBT offset for PG_HITL
p0,
p1,
p2,
@@ -374,12 +375,12 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg,
0.0f,
ray->t,
ray->time,
+ 0xF,
// Need to always call into __anyhit__kernel_optix_shadow_all_hit
- 0xFF,
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
- 2,
+ 1, // SBT offset for PG_HITS
+ 0,
0,
- 0, // SBT offset for PG_HITS
p0,
p1,
*num_hits,
@@ -458,12 +459,12 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals *kg,
0.0f,
ray->t,
ray->time,
- // Visibility mask set to only intersect objects with volumes
- 0x02,
+ // Skip everything but volumes
+ 0x2,
OPTIX_RAY_FLAG_NONE,
+ 0, // SBT offset for PG_HITD
0,
0,
- 0, // SBT offset for PG_HITD
p0,
p1,
p2,
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h
index c04dbee52cc..06d2c016f5b 100644
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ b/intern/cycles/kernel/geom/geom_curve_intersect.h
@@ -734,7 +734,6 @@ ccl_device_inline void curve_shader_setup(KernelGlobals *kg,
}
sd->u = isect->u;
- sd->v = isect->v;
P = P + D * t;
@@ -750,6 +749,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals *kg,
sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent)));
sd->Ng = -D;
+ sd->v = isect->v;
# if 0
/* This approximates the position and geometric normal of a thick curve too,
@@ -764,8 +764,11 @@ ccl_device_inline void curve_shader_setup(KernelGlobals *kg,
* This could be optimized by recording the normal in the intersection,
* however for Optix this would go beyond the size of the payload. */
const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, isect->u));
- sd->Ng = normalize(P - P_inside);
- sd->N = sd->Ng;
+ const float3 Ng = normalize(P - P_inside);
+
+ sd->N = Ng;
+ sd->Ng = Ng;
+ sd->v = 0.0f;
}
# ifdef __DPDU__
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index 445cf9eb44b..efe46d5b0dd 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -379,7 +379,7 @@ ccl_device_inline void camera_sample(KernelGlobals *kg,
const int shutter_table_offset = kernel_data.cam.shutter_table_offset;
ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE);
/* TODO(sergey): Currently single rolling shutter effect type only
- * where scan-lines are acquired from top to bottom and whole scanline
+ * where scan-lines are acquired from top to bottom and whole scan-line
* is acquired at once (no delay in acquisition happens between pixels
* of single scan-line).
*
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index ba46d84d158..eb6c94fe104 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -284,19 +284,11 @@ ccl_device_forceinline bool kernel_path_shader_apply(KernelGlobals *kg,
#ifdef __HOLDOUT__
if (((sd->flag & SD_HOLDOUT) || (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
(state->flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
+ const float3 holdout_weight = shader_holdout_apply(kg, sd);
if (kernel_data.background.transparent) {
- float3 holdout_weight;
- if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
- holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
- }
- else {
- holdout_weight = shader_holdout_eval(kg, sd);
- }
- /* any throughput is ok, should all be identical here */
L->transparent += average(holdout_weight * throughput);
}
-
- if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
+ if (isequal_float3(holdout_weight, make_float3(1.0f, 1.0f, 1.0f))) {
return false;
}
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 3d9f787f267..e461e1642b6 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -1017,15 +1017,36 @@ ccl_device float3 shader_emissive_eval(ShaderData *sd)
/* Holdout */
-ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
+ccl_device float3 shader_holdout_apply(KernelGlobals *kg, ShaderData *sd)
{
float3 weight = make_float3(0.0f, 0.0f, 0.0f);
- for (int i = 0; i < sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ /* For objects marked as holdout, preserve transparency and remove all other
+ * closures, replacing them with a holdout weight. */
+ if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
+ if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) {
+ weight = make_float3(1.0f, 1.0f, 1.0f) - sd->closure_transparent_extinction;
- if (CLOSURE_IS_HOLDOUT(sc->type))
- weight += sc->weight;
+ for (int i = 0; i < sd->num_closure; i++) {
+ ShaderClosure *sc = &sd->closure[i];
+ if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) {
+ sc->type = NBUILTIN_CLOSURES;
+ }
+ }
+
+ sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF));
+ }
+ else {
+ weight = make_float3(1.0f, 1.0f, 1.0f);
+ }
+ }
+ else {
+ for (int i = 0; i < sd->num_closure; i++) {
+ ShaderClosure *sc = &sd->closure[i];
+ if (CLOSURE_IS_HOLDOUT(sc->type)) {
+ weight += sc->weight;
+ }
+ }
}
return weight;
diff --git a/intern/cycles/kernel/kernels/optix/kernel_optix.cu b/intern/cycles/kernel/kernels/optix/kernel_optix.cu
index c730d952ed4..3b166e59dfd 100644
--- a/intern/cycles/kernel/kernels/optix/kernel_optix.cu
+++ b/intern/cycles/kernel/kernels/optix/kernel_optix.cu
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+// clang-format off
#include "kernel/kernel_compat_optix.h"
#include "util/util_atomic.h"
#include "kernel/kernel_types.h"
@@ -23,6 +24,7 @@
#include "kernel/kernel_path.h"
#include "kernel/kernel_bake.h"
+// clang-format on
template<typename T> ccl_device_forceinline T *get_payload_ptr_0()
{
@@ -139,8 +141,8 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
}
else {
if (local_isect->num_hits && optixGetRayTmax() > local_isect->hits[0].t) {
- // Record closest intersection only (do not terminate ray here, since there is no guarantee
- // about distance ordering in anyhit)
+ // Record closest intersection only
+ // Do not terminate ray here, since there is no guarantee about distance ordering in any-hit
return optixIgnoreIntersection();
}
@@ -153,15 +155,9 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
isect->object = get_object_id();
isect->type = kernel_tex_fetch(__prim_type, isect->prim);
- if (optixIsTriangleHit()) {
- const float2 barycentrics = optixGetTriangleBarycentrics();
- isect->u = 1.0f - barycentrics.y - barycentrics.x;
- isect->v = barycentrics.x;
- }
- else {
- isect->u = __uint_as_float(optixGetAttribute_0());
- isect->v = __uint_as_float(optixGetAttribute_1());
- }
+ const float2 barycentrics = optixGetTriangleBarycentrics();
+ isect->u = 1.0f - barycentrics.y - barycentrics.x;
+ isect->v = barycentrics.x;
// Record geometric normal
const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
@@ -198,10 +194,18 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
isect->u = 1.0f - barycentrics.y - barycentrics.x;
isect->v = barycentrics.x;
}
+# ifdef __HAIR__
else {
- isect->u = __uint_as_float(optixGetAttribute_0());
+ const float u = __uint_as_float(optixGetAttribute_0());
+ isect->u = u;
isect->v = __uint_as_float(optixGetAttribute_1());
+
+ // Filter out curve endcaps
+ if (u == 0.0f || u == 1.0f) {
+ return optixIgnoreIntersection();
+ }
}
+# endif
# ifdef __TRANSPARENT_SHADOWS__
// Detect if this surface has a shader with transparent shadows
@@ -213,7 +217,6 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
# ifdef __TRANSPARENT_SHADOWS__
}
- // TODO(pmours): Do we need REQUIRE_UNIQUE_ANYHIT for this to work?
optixSetPayload_2(optixGetPayload_2() + 1); // num_hits++
// Continue tracing
@@ -227,13 +230,25 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
uint visibility = optixGetPayload_4();
#ifdef __VISIBILITY_FLAG__
const uint prim = optixGetPrimitiveIndex();
- if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0)
+ if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0) {
return optixIgnoreIntersection();
+ }
+#endif
+
+#ifdef __HAIR__
+ if (!optixIsTriangleHit()) {
+ // Filter out curve endcaps
+ const float u = __uint_as_float(optixGetAttribute_0());
+ if (u == 0.0f || u == 1.0f) {
+ return optixIgnoreIntersection();
+ }
+ }
#endif
// Shadow ray early termination
- if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ if (visibility & PATH_RAY_SHADOW_OPAQUE) {
return optixTerminateRay();
+ }
}
extern "C" __global__ void __closesthit__kernel_optix_hit()
@@ -250,7 +265,7 @@ extern "C" __global__ void __closesthit__kernel_optix_hit()
optixSetPayload_2(__float_as_uint(barycentrics.x));
}
else {
- optixSetPayload_1(optixGetAttribute_0());
+ optixSetPayload_1(optixGetAttribute_0()); // Same as 'optixGetCurveParameter()'
optixSetPayload_2(optixGetAttribute_1());
}
}
@@ -286,7 +301,6 @@ ccl_device_inline void optix_intersection_curve(const uint prim, const uint type
__float_as_int(isect.u), // Attribute_0
__float_as_int(isect.v)); // Attribute_1
}
-
}
extern "C" __global__ void __intersection__curve_ribbon()
diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/shaders/node_sky_texture.osl
index 08bc8f85120..acb198a9852 100644
--- a/intern/cycles/kernel/shaders/node_sky_texture.osl
+++ b/intern/cycles/kernel/shaders/node_sky_texture.osl
@@ -122,12 +122,18 @@ vector geographical_to_direction(float lat, float lon)
return vector(cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat));
}
-color sky_radiance_nishita(vector dir, float nishita_data[9], string filename)
+float precise_angle(vector a, vector b)
+{
+ return 2.0 * atan2(length(a - b), length(a + b));
+}
+
+color sky_radiance_nishita(vector dir, float nishita_data[10], string filename)
{
/* definitions */
float sun_elevation = nishita_data[6];
float sun_rotation = nishita_data[7];
float angular_diameter = nishita_data[8];
+ float sun_intensity = nishita_data[9];
int sun_disc = angular_diameter > 0;
float alpha = 1.0;
color xyz;
@@ -138,13 +144,13 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename)
if (dir[2] >= 0.0) {
/* definitions */
vector sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2);
- float sun_dir_angle = acos(dot(dir, sun_dir));
+ float sun_dir_angle = precise_angle(dir, sun_dir);
float half_angular = angular_diameter / 2.0;
float dir_elevation = M_PI_2 - direction[0];
/* if ray inside sun disc render it, otherwise render sky */
if (sun_dir_angle < half_angular && sun_disc == 1) {
- /* get 3 pixels data */
+ /* get 2 pixels data */
color pixel_bottom = color(nishita_data[0], nishita_data[1], nishita_data[2]);
color pixel_top = color(nishita_data[3], nishita_data[4], nishita_data[5]);
float y;
@@ -153,13 +159,13 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename)
if (sun_elevation - half_angular > 0.0) {
if ((sun_elevation + half_angular) > 0.0) {
y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5;
- xyz = mix(pixel_bottom, pixel_top, y);
+ xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity;
}
}
else {
if (sun_elevation + half_angular > 0.0) {
y = dir_elevation / (sun_elevation + half_angular);
- xyz = mix(pixel_bottom, pixel_top, y);
+ xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity;
}
}
/* limb darkening, coefficient is 0.6f */
@@ -171,7 +177,8 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename)
else {
/* sky interpolation */
float x = (direction[1] + M_PI + sun_rotation) / M_2PI;
- float y = 1.0 - (dir_elevation / M_PI_2);
+ /* more pixels toward horizon compensation */
+ float y = 1.0 - sqrt(dir_elevation / M_PI_2);
if (x > 1.0) {
x = x - 1.0;
}
@@ -201,19 +208,20 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename)
return xyz_to_rgb(xyz[0], xyz[1], xyz[2]) * 120000.0;
}
-shader node_sky_texture(int use_mapping = 0,
- matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- vector Vector = P,
- string type = "hosek_wilkie",
- float theta = 0.0,
- float phi = 0.0,
- string filename = "",
- color radiance = color(0.0, 0.0, 0.0),
- float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- float nishita_data[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- output color Color = color(0.0, 0.0, 0.0))
+shader node_sky_texture(
+ int use_mapping = 0,
+ matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ vector Vector = P,
+ string type = "hosek_wilkie",
+ float theta = 0.0,
+ float phi = 0.0,
+ string filename = "",
+ color radiance = color(0.0, 0.0, 0.0),
+ float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ float nishita_data[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ output color Color = color(0.0, 0.0, 0.0))
{
vector p = Vector;
diff --git a/intern/cycles/kernel/svm/svm_sky.h b/intern/cycles/kernel/svm/svm_sky.h
index e877bd9a5c8..be2c8ccdacf 100644
--- a/intern/cycles/kernel/svm/svm_sky.h
+++ b/intern/cycles/kernel/svm/svm_sky.h
@@ -136,6 +136,7 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
float sun_elevation = nishita_data[6];
float sun_rotation = nishita_data[7];
float angular_diameter = nishita_data[8];
+ float sun_intensity = nishita_data[9];
bool sun_disc = (angular_diameter > 0.0f);
float3 xyz;
/* convert dir to spherical coordinates */
@@ -145,13 +146,13 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
if (dir.z >= 0.0f) {
/* definitions */
float3 sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2_F);
- float sun_dir_angle = acos(dot(dir, sun_dir));
+ float sun_dir_angle = precise_angle(dir, sun_dir);
float half_angular = angular_diameter / 2.0f;
float dir_elevation = M_PI_2_F - direction.x;
/* if ray inside sun disc render it, otherwise render sky */
if (sun_disc && sun_dir_angle < half_angular) {
- /* get 3 pixels data */
+ /* get 2 pixels data */
float3 pixel_bottom = make_float3(nishita_data[0], nishita_data[1], nishita_data[2]);
float3 pixel_top = make_float3(nishita_data[3], nishita_data[4], nishita_data[5]);
float y;
@@ -160,13 +161,13 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
if (sun_elevation - half_angular > 0.0f) {
if (sun_elevation + half_angular > 0.0f) {
y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
- xyz = interp(pixel_bottom, pixel_top, y);
+ xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
}
}
else {
if (sun_elevation + half_angular > 0.0f) {
y = dir_elevation / (sun_elevation + half_angular);
- xyz = interp(pixel_bottom, pixel_top, y);
+ xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
}
}
/* limb darkening, coefficient is 0.6f */
@@ -178,7 +179,8 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
else {
/* sky interpolation */
float x = (direction.y + M_PI_F + sun_rotation) / M_2PI_F;
- float y = dir_elevation / M_PI_2_F;
+ /* more pixels toward horizon compensation */
+ float y = safe_sqrtf(dir_elevation / M_PI_2_F);
if (x > 1.0f) {
x -= 1.0f;
}
@@ -301,7 +303,7 @@ ccl_device void svm_node_tex_sky(
/* Nishita */
else {
/* Define variables */
- float nishita_data[9];
+ float nishita_data[10];
float4 data = read_node_float(kg, offset);
nishita_data[0] = data.x;
@@ -317,7 +319,8 @@ ccl_device void svm_node_tex_sky(
data = read_node_float(kg, offset);
nishita_data[8] = data.x;
- uint texture_id = __float_as_uint(data.y);
+ nishita_data[9] = data.y;
+ uint texture_id = __float_as_uint(data.z);
/* Compute Sky */
f = sky_radiance_nishita(kg, dir, nishita_data, texture_id);
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index e37a0407976..6a1335dc5dd 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -2,6 +2,7 @@
set(INC
..
../../glew-mx
+ ../../sky/include
)
set(INC_SYS
@@ -92,6 +93,7 @@ set(LIB
cycles_device
cycles_subd
cycles_util
+ bf_intern_sky
)
if(WITH_CYCLES_OSL)
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 975bae2239c..06b6094e6c9 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -52,7 +52,7 @@ class BufferParams {
/* passes */
vector<Pass> passes;
bool denoising_data_pass;
- /* If only some light path types should be denoised, an additional pass is needed. */
+ /* If only some light path types should be target, an additional pass is needed. */
bool denoising_clean_pass;
/* When we're prefiltering the passes during rendering, we need to keep both the
* original and the prefiltered data around because neighboring tiles might still
@@ -149,6 +149,50 @@ class RenderTile {
RenderBuffers *buffers;
RenderTile();
+
+ int4 bounds() const
+ {
+ return make_int4(x, /* xmin */
+ y, /* ymin */
+ x + w, /* xmax */
+ y + h); /* ymax */
+ }
+};
+
+/* Render Tile Neighbors
+ * Set of neighboring tiles used for denoising. Tile order:
+ * 0 1 2
+ * 3 4 5
+ * 6 7 8 */
+
+class RenderTileNeighbors {
+ public:
+ static const int SIZE = 9;
+ static const int CENTER = 4;
+
+ RenderTile tiles[SIZE];
+ RenderTile target;
+
+ RenderTileNeighbors(const RenderTile &center)
+ {
+ tiles[CENTER] = center;
+ }
+
+ int4 bounds() const
+ {
+ return make_int4(tiles[3].x, /* xmin */
+ tiles[1].y, /* ymin */
+ tiles[5].x + tiles[5].w, /* xmax */
+ tiles[7].y + tiles[7].h); /* ymax */
+ }
+
+ void set_bounds_from_center()
+ {
+ tiles[3].x = tiles[CENTER].x;
+ tiles[1].y = tiles[CENTER].y;
+ tiles[5].x = tiles[CENTER].x + tiles[CENTER].w;
+ tiles[7].y = tiles[CENTER].y + tiles[CENTER].h;
+ }
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index 74953afae9d..bbc111cb798 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -26,6 +26,7 @@
#include "util/util_function.h"
#include "util/util_logging.h"
#include "util/util_math_cdf.h"
+#include "util/util_task.h"
#include "util/util_vector.h"
/* needed for calculating differentials */
@@ -496,20 +497,35 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
if (!need_device_update && !need_flags_update) {
return;
}
- KernelCamera *kcam = &dscene->data.cam;
- BoundBox viewplane_boundbox = viewplane_bounds_get();
- for (size_t i = 0; i < scene->objects.size(); ++i) {
- Object *object = scene->objects[i];
- if (object->geometry->has_volume && viewplane_boundbox.intersects(object->bounds)) {
- /* TODO(sergey): Consider adding more grained check. */
- VLOG(1) << "Detected camera inside volume.";
- kcam->is_inside_volume = 1;
- break;
+
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ if (kintegrator->use_volumes) {
+ KernelCamera *kcam = &dscene->data.cam;
+ BoundBox viewplane_boundbox = viewplane_bounds_get();
+
+ /* Parallel object update, with grain size to avoid too much threading overhead
+ * for individual objects. */
+ static const int OBJECTS_PER_TASK = 32;
+ parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
+ [&](const blocked_range<size_t> &r) {
+ for (size_t i = r.begin(); i != r.end(); i++) {
+ Object *object = scene->objects[i];
+ if (object->geometry->has_volume &&
+ viewplane_boundbox.intersects(object->bounds)) {
+ /* TODO(sergey): Consider adding more grained check. */
+ VLOG(1) << "Detected camera inside volume.";
+ kcam->is_inside_volume = 1;
+ parallel_for_cancel();
+ break;
+ }
+ }
+ });
+
+ if (!kcam->is_inside_volume) {
+ VLOG(1) << "Camera is outside of the volume.";
}
}
- if (!kcam->is_inside_volume) {
- VLOG(1) << "Camera is outside of the volume.";
- }
+
need_device_update = false;
need_flags_update = false;
}
diff --git a/intern/cycles/render/denoising.cpp b/intern/cycles/render/denoising.cpp
index 4055bc4773b..76408ca4849 100644
--- a/intern/cycles/render/denoising.cpp
+++ b/intern/cycles/render/denoising.cpp
@@ -271,42 +271,45 @@ bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile &
*
* However, since there is only one large memory, the denoised result has to be written to
* a different buffer to avoid having to copy an entire horizontal slice of the image. */
-void DenoiseTask::map_neighboring_tiles(RenderTile *tiles, Device *tile_device)
+void DenoiseTask::map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
{
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+ RenderTile &target_tile = neighbors.target;
+
/* Fill tile information. */
- for (int i = 0; i < 9; i++) {
- if (i == 4) {
+ for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
+ if (i == RenderTileNeighbors::CENTER) {
continue;
}
+ RenderTile &tile = neighbors.tiles[i];
int dx = (i % 3) - 1;
int dy = (i / 3) - 1;
- tiles[i].x = clamp(tiles[4].x + dx * denoiser->tile_size.x, 0, image.width);
- tiles[i].w = clamp(tiles[4].x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tiles[i].x;
- tiles[i].y = clamp(tiles[4].y + dy * denoiser->tile_size.y, 0, image.height);
- tiles[i].h = clamp(tiles[4].y + (dy + 1) * denoiser->tile_size.y, 0, image.height) -
- tiles[i].y;
+ tile.x = clamp(center_tile.x + dx * denoiser->tile_size.x, 0, image.width);
+ tile.w = clamp(center_tile.x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tile.x;
+ tile.y = clamp(center_tile.y + dy * denoiser->tile_size.y, 0, image.height);
+ tile.h = clamp(center_tile.y + (dy + 1) * denoiser->tile_size.y, 0, image.height) - tile.y;
- tiles[i].buffer = tiles[4].buffer;
- tiles[i].offset = tiles[4].offset;
- tiles[i].stride = image.width;
+ tile.buffer = center_tile.buffer;
+ tile.offset = center_tile.offset;
+ tile.stride = image.width;
}
/* Allocate output buffer. */
device_vector<float> *output_mem = new device_vector<float>(
tile_device, "denoising_output", MEM_READ_WRITE);
- output_mem->alloc(OUTPUT_NUM_CHANNELS * tiles[4].w * tiles[4].h);
+ output_mem->alloc(OUTPUT_NUM_CHANNELS * center_tile.w * center_tile.h);
/* Fill output buffer with noisy image, assumed by kernel_filter_finalize
* when skipping denoising of some pixels. */
float *result = output_mem->data();
- float *in = &image.pixels[image.num_channels * (tiles[4].y * image.width + tiles[4].x)];
+ float *in = &image.pixels[image.num_channels * (center_tile.y * image.width + center_tile.x)];
const DenoiseImageLayer &layer = image.layers[current_layer];
const int *input_to_image_channel = layer.input_to_image_channel.data();
- for (int y = 0; y < tiles[4].h; y++) {
- for (int x = 0; x < tiles[4].w; x++, result += OUTPUT_NUM_CHANNELS) {
+ for (int y = 0; y < center_tile.h; y++) {
+ for (int x = 0; x < center_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
result[i] = in[image.num_channels * x + input_to_image_channel[INPUT_NOISY_IMAGE + i]];
}
@@ -317,35 +320,38 @@ void DenoiseTask::map_neighboring_tiles(RenderTile *tiles, Device *tile_device)
output_mem->copy_to_device();
/* Fill output tile info. */
- tiles[9] = tiles[4];
- tiles[9].buffer = output_mem->device_pointer;
- tiles[9].stride = tiles[9].w;
- tiles[9].offset -= tiles[9].x + tiles[9].y * tiles[9].stride;
+ target_tile = center_tile;
+ target_tile.buffer = output_mem->device_pointer;
+ target_tile.stride = target_tile.w;
+ target_tile.offset -= target_tile.x + target_tile.y * target_tile.stride;
thread_scoped_lock output_lock(output_mutex);
- assert(output_pixels.count(tiles[4].tile_index) == 0);
- output_pixels[tiles[9].tile_index] = output_mem;
+ assert(output_pixels.count(center_tile.tile_index) == 0);
+ output_pixels[target_tile.tile_index] = output_mem;
}
-void DenoiseTask::unmap_neighboring_tiles(RenderTile *tiles)
+void DenoiseTask::unmap_neighboring_tiles(RenderTileNeighbors &neighbors)
{
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+ RenderTile &target_tile = neighbors.target;
+
thread_scoped_lock output_lock(output_mutex);
- assert(output_pixels.count(tiles[4].tile_index) == 1);
- device_vector<float> *output_mem = output_pixels[tiles[9].tile_index];
- output_pixels.erase(tiles[4].tile_index);
+ assert(output_pixels.count(center_tile.tile_index) == 1);
+ device_vector<float> *output_mem = output_pixels[target_tile.tile_index];
+ output_pixels.erase(center_tile.tile_index);
output_lock.unlock();
/* Copy denoised pixels from device. */
- output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * tiles[9].w, tiles[9].h);
+ output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * target_tile.w, target_tile.h);
float *result = output_mem->data();
- float *out = &image.pixels[image.num_channels * (tiles[9].y * image.width + tiles[9].x)];
+ float *out = &image.pixels[image.num_channels * (target_tile.y * image.width + target_tile.x)];
const DenoiseImageLayer &layer = image.layers[current_layer];
const int *output_to_image_channel = layer.output_to_image_channel.data();
- for (int y = 0; y < tiles[9].h; y++) {
- for (int x = 0; x < tiles[9].w; x++, result += OUTPUT_NUM_CHANNELS) {
+ for (int y = 0; y < target_tile.h; y++) {
+ for (int x = 0; x < target_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
out[image.num_channels * x + output_to_image_channel[i]] = result[i];
}
diff --git a/intern/cycles/render/denoising.h b/intern/cycles/render/denoising.h
index 5c6f913cb38..c1b4d0a5596 100644
--- a/intern/cycles/render/denoising.h
+++ b/intern/cycles/render/denoising.h
@@ -196,8 +196,8 @@ class DenoiseTask {
/* Device task callbacks */
bool acquire_tile(Device *device, Device *tile_device, RenderTile &tile);
- void map_neighboring_tiles(RenderTile *tiles, Device *tile_device);
- void unmap_neighboring_tiles(RenderTile *tiles);
+ void map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
+ void unmap_neighboring_tiles(RenderTileNeighbors &neighbors);
void release_tile();
bool get_cancel();
};
diff --git a/intern/cycles/render/image_sky.cpp b/intern/cycles/render/image_sky.cpp
index 442e1d7941f..0560907c63e 100644
--- a/intern/cycles/render/image_sky.cpp
+++ b/intern/cycles/render/image_sky.cpp
@@ -16,16 +16,20 @@
#include "render/image_sky.h"
+#include "sky_model.h"
+
#include "util/util_image.h"
#include "util/util_logging.h"
#include "util/util_path.h"
-#include "util/util_sky_model.h"
#include "util/util_task.h"
CCL_NAMESPACE_BEGIN
-SkyLoader::SkyLoader(
- float sun_elevation, int altitude, float air_density, float dust_density, float ozone_density)
+SkyLoader::SkyLoader(float sun_elevation,
+ float altitude,
+ float air_density,
+ float dust_density,
+ float ozone_density)
: sun_elevation(sun_elevation),
altitude(altitude),
air_density(air_density),
@@ -56,23 +60,22 @@ bool SkyLoader::load_pixels(const ImageMetaData &metadata,
int width = metadata.width;
int height = metadata.height;
float *pixel_data = (float *)pixels;
- float altitude_f = (float)altitude;
/* precompute sky texture */
const int rows_per_task = divide_up(1024, width);
parallel_for(blocked_range<size_t>(0, height, rows_per_task),
[&](const blocked_range<size_t> &r) {
- nishita_skymodel_precompute_texture(pixel_data,
- metadata.channels,
- r.begin(),
- r.end(),
- width,
- height,
- sun_elevation,
- altitude_f,
- air_density,
- dust_density,
- ozone_density);
+ SKY_nishita_skymodel_precompute_texture(pixel_data,
+ metadata.channels,
+ r.begin(),
+ r.end(),
+ width,
+ height,
+ sun_elevation,
+ altitude,
+ air_density,
+ dust_density,
+ ozone_density);
});
return true;
diff --git a/intern/cycles/render/image_sky.h b/intern/cycles/render/image_sky.h
index cf4a3e8942c..686f4e5b885 100644
--- a/intern/cycles/render/image_sky.h
+++ b/intern/cycles/render/image_sky.h
@@ -21,14 +21,14 @@ CCL_NAMESPACE_BEGIN
class SkyLoader : public ImageLoader {
private:
float sun_elevation;
- int altitude;
+ float altitude;
float air_density;
float dust_density;
float ozone_density;
public:
SkyLoader(float sun_elevation,
- int altitude,
+ float altitude,
float air_density,
float dust_density,
float ozone_density);
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index c0615c6217b..183c02cb6b9 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -625,13 +625,19 @@ void LightManager::device_update_background(Device *device,
}
}
+ /* Determine sun direction from lat/long and texture mapping. */
float latitude = sky->sun_elevation;
float longitude = M_2PI_F - sky->sun_rotation + M_PI_2_F;
+ float3 sun_direction = make_float3(
+ cosf(latitude) * cosf(longitude), cosf(latitude) * sinf(longitude), sinf(latitude));
+ Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform());
+ sun_direction = transform_direction(&sky_transform, sun_direction);
+
+ /* Pack sun direction and size. */
float half_angle = sky->sun_size * 0.5f;
- kbackground->sun = make_float4(cosf(latitude) * cosf(longitude),
- cosf(latitude) * sinf(longitude),
- sinf(latitude),
- half_angle);
+ kbackground->sun = make_float4(
+ sun_direction.x, sun_direction.y, sun_direction.z, half_angle);
+
kbackground->sun_weight = 4.0f;
environment_res.x = max(environment_res.x, 512);
environment_res.y = max(environment_res.y, 256);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index ab392839e52..1a29663ec5e 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -27,9 +27,10 @@
#include "render/scene.h"
#include "render/svm.h"
+#include "sky_model.h"
+
#include "util/util_foreach.h"
#include "util/util_logging.h"
-#include "util/util_sky_model.h"
#include "util/util_transform.h"
#include "kernel/svm/svm_color_util.h"
@@ -631,7 +632,7 @@ typedef struct SunSky {
/* Parameter */
float radiance_x, radiance_y, radiance_z;
- float config_x[9], config_y[9], config_z[9], nishita_data[9];
+ float config_x[9], config_y[9], config_z[9], nishita_data[10];
} SunSky;
/* Preetham model */
@@ -726,8 +727,8 @@ static void sky_texture_precompute_hosek(SunSky *sunsky,
float solarElevation = M_PI_2_F - theta;
/* Initialize Sky Model */
- ArHosekSkyModelState *sky_state;
- sky_state = arhosek_xyz_skymodelstate_alloc_init(
+ SKY_ArHosekSkyModelState *sky_state;
+ sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init(
(double)turbidity, (double)ground_albedo, (double)solarElevation);
/* Copy values from sky_state to SunSky */
@@ -741,25 +742,31 @@ static void sky_texture_precompute_hosek(SunSky *sunsky,
sunsky->radiance_z = (float)sky_state->radiances[2];
/* Free sky_state */
- arhosekskymodelstate_free(sky_state);
+ SKY_arhosekskymodelstate_free(sky_state);
}
/* Nishita improved */
static void sky_texture_precompute_nishita(SunSky *sunsky,
bool sun_disc,
float sun_size,
+ float sun_intensity,
float sun_elevation,
float sun_rotation,
- int altitude,
+ float altitude,
float air_density,
float dust_density)
{
/* sample 2 sun pixels */
float pixel_bottom[3];
float pixel_top[3];
- float altitude_f = (float)altitude;
- nishita_skymodel_precompute_sun(
- sun_elevation, sun_size, altitude_f, air_density, dust_density, pixel_bottom, pixel_top);
+ SKY_nishita_skymodel_precompute_sun(
+ sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top);
+ /* limit sun rotation between 0 and 360 degrees */
+ sun_rotation = fmodf(sun_rotation, M_2PI_F);
+ if (sun_rotation < 0.0f) {
+ sun_rotation += M_2PI_F;
+ }
+ sun_rotation = M_2PI_F - sun_rotation;
/* send data to svm_sky */
sunsky->nishita_data[0] = pixel_bottom[0];
sunsky->nishita_data[1] = pixel_bottom[1];
@@ -768,8 +775,9 @@ static void sky_texture_precompute_nishita(SunSky *sunsky,
sunsky->nishita_data[4] = pixel_top[1];
sunsky->nishita_data[5] = pixel_top[2];
sunsky->nishita_data[6] = sun_elevation;
- sunsky->nishita_data[7] = M_2PI_F - sun_rotation;
+ sunsky->nishita_data[7] = sun_rotation;
sunsky->nishita_data[8] = sun_disc ? sun_size : 0.0f;
+ sunsky->nishita_data[9] = sun_intensity;
}
NODE_DEFINE(SkyTextureNode)
@@ -789,9 +797,10 @@ NODE_DEFINE(SkyTextureNode)
SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
SOCKET_BOOLEAN(sun_disc, "Sun Disc", true);
SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f);
+ SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f);
SOCKET_FLOAT(sun_elevation, "Sun Elevation", M_PI_2_F);
SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f);
- SOCKET_INT(altitude, "Altitude", 0);
+ SOCKET_FLOAT(altitude, "Altitude", 1.0f);
SOCKET_FLOAT(air_density, "Air", 1.0f);
SOCKET_FLOAT(dust_density, "Dust", 1.0f);
SOCKET_FLOAT(ozone_density, "Ozone", 1.0f);
@@ -819,12 +828,17 @@ void SkyTextureNode::compile(SVMCompiler &compiler)
else if (type == NODE_SKY_HOSEK)
sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
else if (type == NODE_SKY_NISHITA) {
+ /* Clamp altitude to reasonable values.
+ * Below 1m causes numerical issues and above 60km is space. */
+ float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
+
sky_texture_precompute_nishita(&sunsky,
sun_disc,
sun_size,
+ sun_intensity,
sun_elevation,
sun_rotation,
- altitude,
+ clamped_altitude,
air_density,
dust_density);
/* precomputed texture image parameters */
@@ -836,7 +850,7 @@ void SkyTextureNode::compile(SVMCompiler &compiler)
/* precompute sky texture */
if (handle.empty()) {
SkyLoader *loader = new SkyLoader(
- sun_elevation, altitude, air_density, dust_density, ozone_density);
+ sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
handle = image_manager->add_image(loader, impar);
}
}
@@ -891,7 +905,10 @@ void SkyTextureNode::compile(SVMCompiler &compiler)
__float_as_uint(sunsky.nishita_data[5]),
__float_as_uint(sunsky.nishita_data[6]),
__float_as_uint(sunsky.nishita_data[7]));
- compiler.add_node(__float_as_uint(sunsky.nishita_data[8]), handle.svm_slot(), 0, 0);
+ compiler.add_node(__float_as_uint(sunsky.nishita_data[8]),
+ __float_as_uint(sunsky.nishita_data[9]),
+ handle.svm_slot(),
+ 0);
}
tex_mapping.compile_end(compiler, vector_in, vector_offset);
@@ -907,12 +924,17 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
else if (type == NODE_SKY_HOSEK)
sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
else if (type == NODE_SKY_NISHITA) {
+ /* Clamp altitude to reasonable values.
+ * Below 1m causes numerical issues and above 60km is space. */
+ float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
+
sky_texture_precompute_nishita(&sunsky,
sun_disc,
sun_size,
+ sun_intensity,
sun_elevation,
sun_rotation,
- altitude,
+ clamped_altitude,
air_density,
dust_density);
/* precomputed texture image parameters */
@@ -924,7 +946,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
/* precompute sky texture */
if (handle.empty()) {
SkyLoader *loader = new SkyLoader(
- sun_elevation, altitude, air_density, dust_density, ozone_density);
+ sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
handle = image_manager->add_image(loader, impar);
}
}
@@ -939,7 +961,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
compiler.parameter_array("config_x", sunsky.config_x, 9);
compiler.parameter_array("config_y", sunsky.config_y, 9);
compiler.parameter_array("config_z", sunsky.config_z, 9);
- compiler.parameter_array("nishita_data", sunsky.nishita_data, 9);
+ compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
/* nishita texture */
if (type == NODE_SKY_NISHITA) {
compiler.parameter_texture("filename", handle.svm_slot());
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 846ba7423e5..326f1d14168 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -170,9 +170,10 @@ class SkyTextureNode : public TextureNode {
float ground_albedo;
bool sun_disc;
float sun_size;
+ float sun_intensity;
float sun_elevation;
float sun_rotation;
- int altitude;
+ float altitude;
float air_density;
float dust_density;
float ozone_density;
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index c45ae5553a8..f200e409b9e 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -823,6 +823,12 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
Mesh *mesh = static_cast<Mesh *>(geom);
apply = apply && mesh->subdivision_type == Mesh::SUBDIVISION_NONE;
}
+ else if (geom->type == Geometry::HAIR) {
+ /* Can't apply non-uniform scale to curves, this can't be represented by
+ * control points and radius alone. */
+ float scale;
+ apply = apply && transform_uniform_scale(object->tfm, scale);
+ }
if (apply) {
if (!(motion_blur && object->use_motion())) {
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 1a94d3e9db7..c5033359c6b 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -536,7 +536,7 @@ void Session::release_tile(RenderTile &rtile, const bool need_denoise)
denoising_cond.notify_all();
}
-void Session::map_neighbor_tiles(RenderTile *tiles, Device *tile_device)
+void Session::map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
{
thread_scoped_lock tile_lock(tile_mutex);
@@ -546,75 +546,77 @@ void Session::map_neighbor_tiles(RenderTile *tiles, Device *tile_device)
tile_manager.state.buffer.full_x + tile_manager.state.buffer.width,
tile_manager.state.buffer.full_y + tile_manager.state.buffer.height);
+ RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
+
if (!tile_manager.schedule_denoising) {
/* Fix up tile slices with overlap. */
if (tile_manager.slice_overlap != 0) {
- int y = max(tiles[4].y - tile_manager.slice_overlap, image_region.y);
- tiles[4].h = min(tiles[4].y + tiles[4].h + tile_manager.slice_overlap, image_region.w) - y;
- tiles[4].y = y;
+ int y = max(center_tile.y - tile_manager.slice_overlap, image_region.y);
+ center_tile.h = min(center_tile.y + center_tile.h + tile_manager.slice_overlap,
+ image_region.w) -
+ y;
+ center_tile.y = y;
}
/* Tiles are not being denoised individually, which means the entire image is processed. */
- tiles[3].x = tiles[4].x;
- tiles[1].y = tiles[4].y;
- tiles[5].x = tiles[4].x + tiles[4].w;
- tiles[7].y = tiles[4].y + tiles[4].h;
+ neighbors.set_bounds_from_center();
}
else {
- int center_idx = tiles[4].tile_index;
+ int center_idx = center_tile.tile_index;
assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE);
for (int dy = -1, i = 0; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++, i++) {
+ RenderTile &rtile = neighbors.tiles[i];
int nindex = tile_manager.get_neighbor_index(center_idx, i);
if (nindex >= 0) {
Tile *tile = &tile_manager.state.tiles[nindex];
- tiles[i].x = image_region.x + tile->x;
- tiles[i].y = image_region.y + tile->y;
- tiles[i].w = tile->w;
- tiles[i].h = tile->h;
+ rtile.x = image_region.x + tile->x;
+ rtile.y = image_region.y + tile->y;
+ rtile.w = tile->w;
+ rtile.h = tile->h;
if (buffers) {
- tile_manager.state.buffer.get_offset_stride(tiles[i].offset, tiles[i].stride);
+ tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
- tiles[i].buffer = buffers->buffer.device_pointer;
- tiles[i].buffers = buffers;
+ rtile.buffer = buffers->buffer.device_pointer;
+ rtile.buffers = buffers;
}
else {
assert(tile->buffers);
- tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride);
+ tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride);
- tiles[i].buffer = tile->buffers->buffer.device_pointer;
- tiles[i].buffers = tile->buffers;
+ rtile.buffer = tile->buffers->buffer.device_pointer;
+ rtile.buffers = tile->buffers;
}
}
else {
- int px = tiles[4].x + dx * params.tile_size.x;
- int py = tiles[4].y + dy * params.tile_size.y;
+ int px = center_tile.x + dx * params.tile_size.x;
+ int py = center_tile.y + dy * params.tile_size.y;
- tiles[i].x = clamp(px, image_region.x, image_region.z);
- tiles[i].y = clamp(py, image_region.y, image_region.w);
- tiles[i].w = tiles[i].h = 0;
+ rtile.x = clamp(px, image_region.x, image_region.z);
+ rtile.y = clamp(py, image_region.y, image_region.w);
+ rtile.w = rtile.h = 0;
- tiles[i].buffer = (device_ptr)NULL;
- tiles[i].buffers = NULL;
+ rtile.buffer = (device_ptr)NULL;
+ rtile.buffers = NULL;
}
}
}
}
- assert(tiles[4].buffers);
- device->map_neighbor_tiles(tile_device, tiles);
+ assert(center_tile.buffers);
+ device->map_neighbor_tiles(tile_device, neighbors);
/* The denoised result is written back to the original tile. */
- tiles[9] = tiles[4];
+ neighbors.target = center_tile;
}
-void Session::unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device)
+void Session::unmap_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
{
thread_scoped_lock tile_lock(tile_mutex);
- device->unmap_neighbor_tiles(tile_device, tiles);
+ device->unmap_neighbor_tiles(tile_device, neighbors);
}
void Session::run_cpu()
@@ -1003,7 +1005,7 @@ bool Session::update_scene()
int height = tile_manager.state.buffer.full_height;
int resolution = tile_manager.state.resolution_divider;
- if (width != cam->width || height != cam->height) {
+ if (width != cam->width || height != cam->height || resolution != cam->resolution) {
cam->width = width;
cam->height = height;
cam->resolution = resolution;
@@ -1126,6 +1128,11 @@ bool Session::render_need_denoise(bool &delayed)
{
delayed = false;
+ /* Not supported yet for baking. */
+ if (read_bake_tile_cb) {
+ return false;
+ }
+
/* Denoising enabled? */
if (!params.denoising.need_denoising_task()) {
return false;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 0141629762c..e3ac054ead3 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -198,8 +198,8 @@ class Session {
void update_tile_sample(RenderTile &tile);
void release_tile(RenderTile &tile, const bool need_denoise);
- void map_neighbor_tiles(RenderTile *tiles, Device *tile_device);
- void unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device);
+ void map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
+ void unmap_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
bool device_use_gl;
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index ad4ea9c86e0..23a47e064e2 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -98,10 +98,6 @@ set(SRC_HEADERS
util_rect.h
util_set.h
util_simd.h
- util_sky_model.cpp
- util_sky_model.h
- util_sky_model_data.h
- util_sky_nishita.cpp
util_avxf.h
util_avxb.h
util_semaphore.h
diff --git a/intern/cycles/util/util_debug.cpp b/intern/cycles/util/util_debug.cpp
index 6ad4f709ab5..74ecefa1917 100644
--- a/intern/cycles/util/util_debug.cpp
+++ b/intern/cycles/util/util_debug.cpp
@@ -83,6 +83,7 @@ DebugFlags::OptiX::OptiX()
void DebugFlags::OptiX::reset()
{
cuda_streams = 1;
+ curves_api = false;
}
DebugFlags::OpenCL::OpenCL() : device_type(DebugFlags::OpenCL::DEVICE_ALL), debug(false)
diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h
index da9f5408b59..6ac4beb55b8 100644
--- a/intern/cycles/util/util_debug.h
+++ b/intern/cycles/util/util_debug.h
@@ -108,6 +108,9 @@ class DebugFlags {
/* Number of CUDA streams to launch kernels concurrently from. */
int cuda_streams;
+
+ /* Use OptiX curves API for hair instead of custom implementation. */
+ bool curves_api;
};
/* Descriptor of OpenCL feature-set to be used. */
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 737c834e073..8caabf6eac3 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -787,6 +787,16 @@ ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp
return (abs(__float_as_int(a) - __float_as_int(b)) < ulp_diff);
}
+/* Calculate the angle between the two vectors a and b.
+ * The usual approach acos(dot(a, b)) has severe precision issues for small angles,
+ * which are avoided by this method.
+ * Based on "Mangled Angles" from https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf
+ */
+ccl_device_inline float precise_angle(float3 a, float3 b)
+{
+ return 2.0f * atan2f(len(a - b), len(a + b));
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_H__ */
diff --git a/intern/cycles/util/util_tbb.h b/intern/cycles/util/util_tbb.h
index 301cb80c5b0..206ba106ca6 100644
--- a/intern/cycles/util/util_tbb.h
+++ b/intern/cycles/util/util_tbb.h
@@ -34,6 +34,11 @@ using tbb::blocked_range;
using tbb::enumerable_thread_specific;
using tbb::parallel_for;
+static inline void parallel_for_cancel()
+{
+ tbb::task::self().cancel_group_execution();
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_TBB_H__ */
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index c7737392e7b..92061f55128 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -362,8 +362,8 @@ extern GHOST_TSuccess GHOST_HasCursorShape(GHOST_WindowHandle windowhandle,
* \param mask The mask data for the cursor.
* \param sizex The width of the cursor
* \param sizey The height of the cursor
- * \param hotX The X coordinate of the cursor hotspot.
- * \param hotY The Y coordinate of the cursor hotspot.
+ * \param hotX The X coordinate of the cursor hot-spot.
+ * \param hotY The Y coordinate of the cursor hot-spot.
* \param canInvertColor Let macOS invert cursor color to match platform convention.
* \return Indication of success.
*/
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 62290d20f1c..9c72b6f07f9 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -287,8 +287,8 @@ class GHOST_IWindow {
* Set the shape of the cursor to a custom cursor.
* \param bitmap The bitmap data for the cursor.
* \param mask The mask data for the cursor.
- * \param hotX The X coordinate of the cursor hotspot.
- * \param hotY The Y coordinate of the cursor hotspot.
+ * \param hotX The X coordinate of the cursor hot-spot.
+ * \param hotY The Y coordinate of the cursor hot-spot.
* \return Indication of success.
*/
virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap,
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 5c1f34e3a63..96073c21e79 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -1324,7 +1324,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
int revert_to;
/* as ICCCM say, we need reply this event
- * with a SetInputFocus, the data[1] have
+ * with a #SetInputFocus, the data[1] have
* the valid timestamp (send by the wm).
*
* Some WM send this event before the
@@ -1345,7 +1345,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
else {
#ifdef WITH_XDND
/* try to handle drag event
- * (if there's no such events, GHOST_HandleClientMessage will return zero) */
+ * (if there's no such events, #GHOST_HandleClientMessage will return zero) */
if (window->getDropTarget()->GHOST_HandleClientMessage(xe) == false) {
/* Unknown client message, ignore */
}
@@ -1366,12 +1366,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case EnterNotify:
case LeaveNotify: {
- /* XCrossingEvents pointer leave enter window.
- * also do cursor move here, MotionNotify only
+ /* #XCrossingEvents pointer leave enter window.
+ * also do cursor move here, #MotionNotify only
* happens when motion starts & ends inside window.
* we only do moves when the crossing mode is 'normal'
- * (really crossing between windows) since some windowmanagers
- * also send grab/ungrab crossings for mousewheel events.
+ * (really crossing between windows) since some window-managers
+ * also send grab/un-grab crossings for mouse-wheel events.
*/
XCrossingEvent &xce = xe->xcrossing;
if (xce.mode == NotifyNormal) {
@@ -1396,11 +1396,11 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case MapNotify:
/*
* From ICCCM:
- * [ Clients can select for StructureNotify on their
+ * [ Clients can select for #StructureNotify on their
* top-level windows to track transition between
- * Normal and Iconic states. Receipt of a MapNotify
+ * Normal and Iconic states. Receipt of a #MapNotify
* event will indicate a transition to the Normal
- * state, and receipt of an UnmapNotify event will
+ * state, and receipt of an #UnmapNotify event will
* indicate a transition to the Iconic state. ]
*/
if (window->m_post_init == True) {
@@ -1441,7 +1441,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
nxe.xselection.target = xse->target;
nxe.xselection.time = xse->time;
- /* Check to see if the requestor is asking for String */
+ /* Check to see if the requester is asking for String */
if (xse->target == utf8_string || xse->target == string || xse->target == compound_text ||
xse->target == c_string) {
if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
@@ -1487,7 +1487,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
nxe.xselection.property = None;
}
- /* Send the event to the client 0 0 == False, SelectionNotify */
+ /* Send the event to the client 0 0 == False, #SelectionNotify */
XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
XFlush(m_display);
break;
@@ -1513,7 +1513,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* Note: This event might be generated with incomplete data-set
* (don't exactly know why, looks like in some cases, if the value does not change,
- * it is not included in subsequent XDeviceMotionEvent events).
+ * it is not included in subsequent #XDeviceMotionEvent events).
* So we have to check which values this event actually contains!
*/
@@ -1569,14 +1569,13 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_TSuccess GHOST_SystemX11::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- /* Analyze the masks returned from XQueryPointer. */
+ /* Analyze the masks returned from #XQueryPointer. */
memset((void *)m_keyboard_vector, 0, sizeof(m_keyboard_vector));
XQueryKeymap(m_display, (char *)m_keyboard_vector);
- /* now translate key symbols into keycodes and
- * test with vector. */
+ /* Now translate key symbols into key-codes and test with vector. */
const static KeyCode shift_l = XKeysymToKeycode(m_display, XK_Shift_L);
const static KeyCode shift_r = XKeysymToKeycode(m_display, XK_Shift_R);
@@ -1671,7 +1670,7 @@ GHOST_TSuccess GHOST_SystemX11::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y
{
/* This is a brute force move in screen coordinates
- * XWarpPointer does relative moves so first determine the
+ * #XWarpPointer does relative moves so first determine the
* current pointer position. */
int cx, cy;
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 6738aa850ce..7cfea5110c5 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -124,8 +124,8 @@ class GHOST_Window : public GHOST_IWindow {
* Set the shape of the cursor to a custom cursor.
* \param bitmap The bitmap data for the cursor.
* \param mask The mask data for the cursor.
- * \param hotX The X coordinate of the cursor hotspot.
- * \param hotY The Y coordinate of the cursor hotspot.
+ * \param hotX The X coordinate of the cursor hot-spot.
+ * \param hotY The Y coordinate of the cursor hot-spot.
* \return Indication of success.
*/
GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap,
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 55ea1d0bb70..1318aa10697 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -243,6 +243,11 @@ void MEM_use_guarded_allocator(void);
void *operator new(size_t /*count*/, void *ptr) \
{ \
return ptr; \
+ } \
+ /* This is the matching delete operator to the placement-new operator above. Both parameters \
+ * will have the same value. Without this, we get the warning C4291 on windows. */ \
+ void operator delete(void * /*ptr_to_free*/, void * /*ptr*/) \
+ { \
}
/* Needed when type includes a namespace, then the namespace should not be
diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c
index 5c37ceb5b24..f7a9a785f5a 100644
--- a/intern/guardedalloc/test/simpletest/memtest.c
+++ b/intern/guardedalloc/test/simpletest/memtest.c
@@ -148,7 +148,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "|\n|--* Errors were detected\n");
}
else {
- fprintf(stderr, "|\n|--* Test exited succesfully\n");
+ fprintf(stderr, "|\n|--* Test exited successfully\n");
}
fprintf(stderr, "|\n*** Finished test\n\n");
diff --git a/intern/libc_compat/libc_compat.c b/intern/libc_compat/libc_compat.c
index 8da3ca218af..78e387e3117 100644
--- a/intern/libc_compat/libc_compat.c
+++ b/intern/libc_compat/libc_compat.c
@@ -28,6 +28,7 @@
# if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 31)
double __exp_finite(double x);
+double __exp2_finite(double x);
double __acos_finite(double x);
double __asin_finite(double x);
double __log2_finite(double x);
@@ -35,6 +36,7 @@ double __log10_finite(double x);
double __log_finite(double x);
double __pow_finite(double x, double y);
float __expf_finite(float x);
+float __exp2f_finite(float x);
float __acosf_finite(float x);
float __asinf_finite(float x);
float __log2f_finite(float x);
@@ -47,6 +49,11 @@ double __exp_finite(double x)
return exp(x);
}
+double __exp2_finite(double x)
+{
+ return exp2(x);
+}
+
double __acos_finite(double x)
{
return acos(x);
@@ -82,6 +89,11 @@ float __expf_finite(float x)
return expf(x);
}
+float __exp2f_finite(float x)
+{
+ return exp2f(x);
+}
+
float __acosf_finite(float x)
{
return acosf(x);
diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.cc b/intern/libmv/libmv/simple_pipeline/pipeline.cc
index 6c8592baa00..728601f3732 100644
--- a/intern/libmv/libmv/simple_pipeline/pipeline.cc
+++ b/intern/libmv/libmv/simple_pipeline/pipeline.cc
@@ -316,8 +316,8 @@ double InternalReprojectionError(
}
LG << "Skipped " << num_skipped << " markers.";
LG << "Reprojected " << num_reprojected << " markers.";
- LG << "Total error: " << total_error;
- LG << "Average error: " << (total_error / num_reprojected) << " [pixels].";
+ LG << "Total error: " << total_error << " px";
+ LG << "Average error: " << (total_error / num_reprojected) << " px";
return total_error / num_reprojected;
}
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index 43121f08f2d..676a2fd785e 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -870,9 +870,9 @@ void MANTA::initializeRNAMap(FluidModifierData *fmd)
mRNAMap["GUIDING_ALPHA"] = to_string(fds->guide_alpha);
mRNAMap["GUIDING_BETA"] = to_string(fds->guide_beta);
mRNAMap["GUIDING_FACTOR"] = to_string(fds->guide_vel_factor);
- mRNAMap["GRAVITY_X"] = to_string(fds->gravity[0]);
- mRNAMap["GRAVITY_Y"] = to_string(fds->gravity[1]);
- mRNAMap["GRAVITY_Z"] = to_string(fds->gravity[2]);
+ mRNAMap["GRAVITY_X"] = to_string(fds->gravity_final[0]);
+ mRNAMap["GRAVITY_Y"] = to_string(fds->gravity_final[1]);
+ mRNAMap["GRAVITY_Z"] = to_string(fds->gravity_final[2]);
mRNAMap["CACHE_DIR"] = cacheDirectory;
mRNAMap["COMPRESSION_OPENVDB"] = vdbCompressionMethod;
mRNAMap["PRECISION_OPENVDB"] = vdbPrecisionHalf;
@@ -1256,6 +1256,7 @@ bool MANTA::readData(FluidModifierData *fmd, int framenr, bool resumable)
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
result &= runPythonString(pythonCommands);
+ return (mSmokeFromFile = result);
}
if (mUsingLiquid) {
ss.str("");
@@ -1263,6 +1264,7 @@ bool MANTA::readData(FluidModifierData *fmd, int framenr, bool resumable)
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
result &= runPythonString(pythonCommands);
+ return (mFlipFromFile = result);
}
return result;
}
@@ -1296,7 +1298,7 @@ bool MANTA::readNoise(FluidModifierData *fmd, int framenr, bool resumable)
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
- return runPythonString(pythonCommands);
+ return (mNoiseFromFile = runPythonString(pythonCommands));
}
bool MANTA::readMesh(FluidModifierData *fmd, int framenr)
@@ -1331,7 +1333,7 @@ bool MANTA::readMesh(FluidModifierData *fmd, int framenr)
pythonCommands.push_back(ss.str());
}
- return runPythonString(pythonCommands);
+ return (mMeshFromFile = runPythonString(pythonCommands));
}
bool MANTA::readParticles(FluidModifierData *fmd, int framenr, bool resumable)
@@ -1365,7 +1367,7 @@ bool MANTA::readParticles(FluidModifierData *fmd, int framenr, bool resumable)
<< framenr << ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
- return runPythonString(pythonCommands);
+ return (mParticlesFromFile = runPythonString(pythonCommands));
}
bool MANTA::readGuiding(FluidModifierData *fmd, int framenr, bool sourceDomain)
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
index 977b99e7759..4ee3ae59957 100644
--- a/intern/mantaflow/intern/strings/fluid_script.h
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -146,19 +146,19 @@ mantaMsg('1 Mantaflow cell is ' + str(ratioMetersToRes_s$ID$) + ' Blender length
ratioResToBLength_s$ID$ = float(res_s$ID$) / float(domainSize_s$ID$) # [cells / blength] (blength: cm, m, or km, ... )\n\
mantaMsg('1 Blender length unit is ' + str(ratioResToBLength_s$ID$) + ' Mantaflow cells long.')\n\
\n\
-ratioBTimeToTimstep_s$ID$ = float(1) / float(frameLengthRaw_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\
-mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimstep_s$ID$) + ' Mantaflow time units long.')\n\
+ratioBTimeToTimestep_s$ID$ = float(1) / float(frameLengthRaw_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\
+mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimestep_s$ID$) + ' Mantaflow time units long.')\n\
\n\
ratioFrameToFramelength_s$ID$ = float(1) / float(frameLengthUnscaled_s$ID$ ) # the time within 1 frame\n\
mantaMsg('frame / frameLength is ' + str(ratioFrameToFramelength_s$ID$) + ' Mantaflow time units long.')\n\
\n\
-scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimstep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\
+scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimestep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\
mantaMsg('scaleAcceleration is ' + str(scaleAcceleration_s$ID$))\n\
\n\
scaleSpeedFrames_s$ID$ = ratioResToBLength_s$ID$ * ratioFrameToFramelength_s$ID$ # [blength/frame] to [cells/frameLength]\n\
mantaMsg('scaleSpeed is ' + str(scaleSpeedFrames_s$ID$))\n\
\n\
-scaleSpeedTime_s$ID$ = ratioResToBLength_s$ID$ * ratioBTimeToTimstep_s$ID$ # [blength/btime] to [cells/frameLength]\n\
+scaleSpeedTime_s$ID$ = ratioResToBLength_s$ID$ * ratioBTimeToTimestep_s$ID$ # [blength/btime] to [cells/frameLength]\n\
mantaMsg('scaleSpeedTime is ' + str(scaleSpeedTime_s$ID$))\n\
\n\
gravity_s$ID$ *= scaleAcceleration_s$ID$ # scale from world acceleration to cell based acceleration\n\
diff --git a/intern/sky/CMakeLists.txt b/intern/sky/CMakeLists.txt
new file mode 100644
index 00000000000..d46880367dc
--- /dev/null
+++ b/intern/sky/CMakeLists.txt
@@ -0,0 +1,35 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ include
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ source/sky_model.cpp
+ source/sky_nishita.cpp
+)
+
+set(LIB
+)
+
+blender_add_lib(bf_intern_sky "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/cycles/util/util_sky_model.h b/intern/sky/include/sky_model.h
index 36f1079a16d..021086e1e02 100644
--- a/intern/cycles/util/util_sky_model.h
+++ b/intern/sky/include/sky_model.h
@@ -298,14 +298,14 @@ HINT #1: if you want to model the sky of an earth-like planet that orbits
previous paragraph.
*/
-#include "util/util_types.h"
+#ifndef __SKY_MODEL_H__
+#define __SKY_MODEL_H__
-CCL_NAMESPACE_BEGIN
+#ifdef __cplusplus
+extern "C" {
+#endif
-#ifndef _SKY_MODEL_H_
-# define _SKY_MODEL_H_
-
-typedef double ArHosekSkyModelConfiguration[9];
+typedef double SKY_ArHosekSkyModelConfiguration[9];
// Spectral version of the model
@@ -335,8 +335,8 @@ typedef double ArHosekSkyModelConfiguration[9];
---------------------------------------------------------------------------- */
-typedef struct ArHosekSkyModelState {
- ArHosekSkyModelConfiguration configs[11];
+typedef struct SKY_ArHosekSkyModelState {
+ SKY_ArHosekSkyModelConfiguration configs[11];
double radiances[11];
double turbidity;
double solar_radius;
@@ -344,7 +344,7 @@ typedef struct ArHosekSkyModelState {
double emission_correction_factor_sun[11];
double albedo;
double elevation;
-} ArHosekSkyModelState;
+} SKY_ArHosekSkyModelState;
/* ----------------------------------------------------------------------------
@@ -355,9 +355,9 @@ typedef struct ArHosekSkyModelState {
---------------------------------------------------------------------------- */
-ArHosekSkyModelState *arhosekskymodelstate_alloc_init(const double solar_elevation,
- const double atmospheric_turbidity,
- const double ground_albedo);
+SKY_ArHosekSkyModelState *SKY_arhosekskymodelstate_alloc_init(const double solar_elevation,
+ const double atmospheric_turbidity,
+ const double ground_albedo);
/* ----------------------------------------------------------------------------
@@ -388,66 +388,68 @@ ArHosekSkyModelState *arhosekskymodelstate_alloc_init(const double solar_elevati
---------------------------------------------------------------------------- */
-ArHosekSkyModelState *arhosekskymodelstate_alienworld_alloc_init(
+SKY_ArHosekSkyModelState *SKY_arhosekskymodelstate_alienworld_alloc_init(
const double solar_elevation,
const double solar_intensity,
const double solar_surface_temperature_kelvin,
const double atmospheric_turbidity,
const double ground_albedo);
-void arhosekskymodelstate_free(ArHosekSkyModelState *state);
+void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state);
-double arhosekskymodel_radiance(ArHosekSkyModelState *state,
- double theta,
- double gamma,
- double wavelength);
+double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ double wavelength);
// CIE XYZ and RGB versions
-ArHosekSkyModelState *arhosek_xyz_skymodelstate_alloc_init(const double turbidity,
- const double albedo,
- const double elevation);
+SKY_ArHosekSkyModelState *SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity,
+ const double albedo,
+ const double elevation);
-ArHosekSkyModelState *arhosek_rgb_skymodelstate_alloc_init(const double turbidity,
- const double albedo,
- const double elevation);
+SKY_ArHosekSkyModelState *SKY_arhosek_rgb_skymodelstate_alloc_init(const double turbidity,
+ const double albedo,
+ const double elevation);
-double arhosek_tristim_skymodel_radiance(ArHosekSkyModelState *state,
- double theta,
- double gamma,
- int channel);
+double SKY_arhosek_tristim_skymodel_radiance(SKY_ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ int channel);
// Delivers the complete function: sky + sun, including limb darkening.
// Please read the above description before using this - there are several
// caveats!
-double arhosekskymodel_solar_radiance(ArHosekSkyModelState *state,
- double theta,
- double gamma,
- double wavelength);
-
-#endif // _SKY_MODEL_H_
+double SKY_arhosekskymodel_solar_radiance(SKY_ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ double wavelength);
/* Nishita improved sky model */
-void nishita_skymodel_precompute_texture(float *pixels,
- int stride,
- int start_y,
- int end_y,
- int width,
- int height,
- float sun_elevation,
+void SKY_nishita_skymodel_precompute_texture(float *pixels,
+ int stride,
+ int start_y,
+ int end_y,
+ int width,
+ int height,
+ float sun_elevation,
+ float altitude,
+ float air_density,
+ float dust_density,
+ float ozone_density);
+
+void SKY_nishita_skymodel_precompute_sun(float sun_elevation,
+ float angular_diameter,
float altitude,
float air_density,
float dust_density,
- float ozone_density);
+ float *r_pixel_bottom,
+ float *r_pixel_top);
-void nishita_skymodel_precompute_sun(float sun_elevation,
- float angular_diameter,
- float altitude,
- float air_density,
- float dust_density,
- float *pixel_bottom,
- float *pixel_top);
+#ifdef __cplusplus
+}
+#endif
-CCL_NAMESPACE_END
+#endif // __SKY_MODEL_H__
diff --git a/intern/sky/source/sky_float3.h b/intern/sky/source/sky_float3.h
new file mode 100644
index 00000000000..2a9b9c89623
--- /dev/null
+++ b/intern/sky/source/sky_float3.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#ifndef __SKY_FLOAT3_H__
+#define __SKY_FLOAT3_H__
+
+// minimal float3 + util_math.h implementation for nishita sky model
+
+#include <math.h>
+
+#ifndef M_PI_F
+# define M_PI_F (3.1415926535897932f) /* pi */
+#endif
+#ifndef M_PI_2_F
+# define M_PI_2_F (1.5707963267948966f) /* pi/2 */
+#endif
+#ifndef M_2PI_F
+# define M_2PI_F (6.2831853071795864f) /* 2*pi */
+#endif
+
+struct float3 {
+ float x, y, z;
+
+ float3() = default;
+
+ float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
+ {
+ }
+
+ float3(const float (*ptr)[3]) : float3((const float *)ptr)
+ {
+ }
+
+ explicit float3(float value) : x(value), y(value), z(value)
+ {
+ }
+
+ explicit float3(int value) : x(value), y(value), z(value)
+ {
+ }
+
+ float3(float x, float y, float z) : x{x}, y{y}, z{z}
+ {
+ }
+
+ operator const float *() const
+ {
+ return &x;
+ }
+
+ operator float *()
+ {
+ return &x;
+ }
+
+ friend float3 operator*(const float3 &a, float b)
+ {
+ return {a.x * b, a.y * b, a.z * b};
+ }
+
+ friend float3 operator*(float b, const float3 &a)
+ {
+ return {a.x * b, a.y * b, a.z * b};
+ }
+
+ friend float3 operator-(const float3 &a, const float3 &b)
+ {
+ return {a.x - b.x, a.y - b.y, a.z - b.z};
+ }
+
+ friend float3 operator-(const float3 &a)
+ {
+ return {-a.x, -a.y, -a.z};
+ }
+
+ float length_squared() const
+ {
+ return x * x + y * y + z * z;
+ }
+
+ float length() const
+ {
+ return sqrt(length_squared());
+ }
+
+ static float distance(const float3 &a, const float3 &b)
+ {
+ return (a - b).length();
+ }
+
+ friend float3 operator+(const float3 &a, const float3 &b)
+ {
+ return {a.x + b.x, a.y + b.y, a.z + b.z};
+ }
+
+ void operator+=(const float3 &b)
+ {
+ this->x += b.x;
+ this->y += b.y;
+ this->z += b.z;
+ }
+
+ friend float3 operator*(const float3 &a, const float3 &b)
+ {
+ return {a.x * b.x, a.y * b.y, a.z * b.z};
+ }
+};
+
+inline float sqr(float a)
+{
+ return a * a;
+}
+
+inline float3 make_float3(float x, float y, float z)
+{
+ return float3(x, y, z);
+}
+
+inline float dot(const float3 &a, const float3 &b)
+{
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+}
+
+inline float distance(const float3 &a, const float3 &b)
+{
+ return float3::distance(a, b);
+}
+
+inline float len_squared(float3 f)
+{
+ return f.length_squared();
+}
+
+inline float len(float3 f)
+{
+ return f.length();
+}
+
+inline float reduce_add(float3 f)
+{
+ return f.x + f.y + f.z;
+}
+
+#endif /* __SKY_FLOAT3_H__ */
diff --git a/intern/cycles/util/util_sky_model.cpp b/intern/sky/source/sky_model.cpp
index 8cdad8a90a4..64cf14ec030 100644
--- a/intern/cycles/util/util_sky_model.cpp
+++ b/intern/sky/source/sky_model.cpp
@@ -97,16 +97,14 @@ All instructions on how to use this code are in the accompanying header file.
*/
-#include "util/util_sky_model.h"
-#include "util/util_sky_model_data.h"
+#include "sky_model.h"
+#include "sky_model_data.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
-CCL_NAMESPACE_BEGIN
-
// Some macro definitions that occur elsewhere in ART, and that have to be
// replicated to make this a stand-alone module.
@@ -138,7 +136,7 @@ typedef const double *ArHosekSkyModel_Radiance_Dataset;
// internal functions
static void ArHosekSkyModel_CookConfiguration(ArHosekSkyModel_Dataset dataset,
- ArHosekSkyModelConfiguration config,
+ SKY_ArHosekSkyModelConfiguration config,
double turbidity,
double albedo,
double solar_elevation)
@@ -272,7 +270,7 @@ static double ArHosekSkyModel_CookRadianceConfiguration(ArHosekSkyModel_Radiance
return res;
}
-static double ArHosekSkyModel_GetRadianceInternal(ArHosekSkyModelConfiguration configuration,
+static double ArHosekSkyModel_GetRadianceInternal(SKY_ArHosekSkyModelConfiguration configuration,
double theta,
double gamma)
{
@@ -288,15 +286,15 @@ static double ArHosekSkyModel_GetRadianceInternal(ArHosekSkyModelConfiguration c
configuration[6] * mieM + configuration[7] * zenith);
}
-void arhosekskymodelstate_free(ArHosekSkyModelState *state)
+void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state)
{
free(state);
}
-double arhosekskymodel_radiance(ArHosekSkyModelState *state,
- double theta,
- double gamma,
- double wavelength)
+double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ double wavelength)
{
int low_wl = (int)((wavelength - 320.0) / 40.0);
@@ -324,11 +322,11 @@ double arhosekskymodel_radiance(ArHosekSkyModelState *state,
// xyz and rgb versions
-ArHosekSkyModelState *arhosek_xyz_skymodelstate_alloc_init(const double turbidity,
- const double albedo,
- const double elevation)
+SKY_ArHosekSkyModelState *SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity,
+ const double albedo,
+ const double elevation)
{
- ArHosekSkyModelState *state = ALLOC(ArHosekSkyModelState);
+ SKY_ArHosekSkyModelState *state = ALLOC(SKY_ArHosekSkyModelState);
state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
state->turbidity = turbidity;
@@ -345,5 +343,3 @@ ArHosekSkyModelState *arhosek_xyz_skymodelstate_alloc_init(const double turbidit
return state;
}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_sky_model_data.h b/intern/sky/source/sky_model_data.h
index a2a3935eb84..8d98f84cdae 100644
--- a/intern/cycles/util/util_sky_model_data.h
+++ b/intern/sky/source/sky_model_data.h
@@ -91,8 +91,6 @@ an updated version of this code has been published!
============================================================================ */
-CCL_NAMESPACE_BEGIN
-
/*
This file contains the coefficient data for the XYZ colour space version of
@@ -3843,5 +3841,3 @@ static const double datasetXYZRad3[] = {
static const double *datasetsXYZ[] = {datasetXYZ1, datasetXYZ2, datasetXYZ3};
static const double *datasetsXYZRad[] = {datasetXYZRad1, datasetXYZRad2, datasetXYZRad3};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_sky_nishita.cpp b/intern/sky/source/sky_nishita.cpp
index 92397804d43..eae95dc73fe 100644
--- a/intern/cycles/util/util_sky_nishita.cpp
+++ b/intern/sky/source/sky_nishita.cpp
@@ -14,21 +14,23 @@
* limitations under the License.
*/
-#include "util/util_math.h"
-#include "util/util_sky_model.h"
-
-CCL_NAMESPACE_BEGIN
+#include "sky_float3.h"
+#include "sky_model.h"
/* Constants */
static const float rayleigh_scale = 8000.0f; // Rayleigh scale height (m)
static const float mie_scale = 1200.0f; // Mie scale height (m)
static const float mie_coeff = 2e-5f; // Mie scattering coefficient
static const float mie_G = 0.76f; // aerosols anisotropy
+static const float sqr_G = mie_G * mie_G; // squared aerosols anisotropy
static const float earth_radius = 6360000.0f; // radius of Earth (m)
static const float atmosphere_radius = 6420000.0f; // radius of atmosphere (m)
static const int steps = 32; // segments per primary ray
static const int steps_light = 16; // segments per sun connection ray
static const int num_wavelengths = 21; // number of wavelengths
+static const int max_luminous_efficacy = 683; // maximum luminous efficacy
+static const float step_lambda = (num_wavelengths - 1) *
+ 1e-9f; // step between each sampled wavelength
/* irradiance at top of atmosphere */
static const float irradiance[] = {
1.45756829855592995315f, 1.56596305559738380175f, 1.65148449067670455293f,
@@ -92,7 +94,7 @@ static float3 spec_to_xyz(float *spectrum)
xyz.y += cmf_xyz[i][1] * spectrum[i];
xyz.z += cmf_xyz[i][2] * spectrum[i];
}
- return xyz * (20 * 683 * 1e-9f);
+ return xyz * step_lambda * max_luminous_efficacy;
}
/* Atmosphere volume models */
@@ -124,8 +126,6 @@ static float phase_rayleigh(float mu)
static float phase_mie(float mu)
{
- static const float sqr_G = mie_G * mie_G;
-
return (3.0f * (1.0f - sqr_G) * (1.0f + sqr(mu))) /
(8.0f * M_PI_F * (2.0f + sqr_G) * powf((1.0f + sqr_G - 2.0f * mie_G * mu), 1.5));
}
@@ -169,6 +169,7 @@ static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir)
/* The density of each segment is evaluated at its middle. */
float3 P = ray_origin + 0.5f * segment;
+
for (int i = 0; i < steps_light; i++) {
/* Compute height above sea level. */
float height = len(P) - earth_radius;
@@ -176,13 +177,13 @@ static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir)
/* Accumulate optical depth of this segment (density is assumed to be constant along it). */
float3 density = make_float3(
density_rayleigh(height), density_mie(height), density_ozone(height));
- optical_depth += segment_length * density;
+ optical_depth += density;
/* Advance along ray. */
P += segment;
}
- return optical_depth;
+ return optical_depth * segment_length;
}
/* Single Scattering implementation */
@@ -221,6 +222,7 @@ static void single_scattering(float3 ray_dir,
/* The density and in-scattering of each segment is evaluated at its middle. */
float3 P = ray_origin + 0.5f * segment;
+
for (int i = 0; i < steps; i++) {
/* Compute height above sea level. */
float height = len(P) - earth_radius;
@@ -269,17 +271,17 @@ static void single_scattering(float3 ray_dir,
}
/* calculate texture array */
-void nishita_skymodel_precompute_texture(float *pixels,
- int stride,
- int start_y,
- int end_y,
- int width,
- int height,
- float sun_elevation,
- float altitude,
- float air_density,
- float dust_density,
- float ozone_density)
+void SKY_nishita_skymodel_precompute_texture(float *pixels,
+ int stride,
+ int start_y,
+ int end_y,
+ int width,
+ int height,
+ float sun_elevation,
+ float altitude,
+ float air_density,
+ float dust_density,
+ float ozone_density)
{
/* calculate texture pixels */
float spectrum[num_wavelengths];
@@ -289,11 +291,13 @@ void nishita_skymodel_precompute_texture(float *pixels,
float latitude_step = M_PI_2_F / height;
float longitude_step = M_2PI_F / width;
+ float half_lat_step = latitude_step / 2.0f;
for (int y = start_y; y < end_y; y++) {
- float latitude = latitude_step * y;
+ /* sample more pixels toward the horizon */
+ float latitude = (M_PI_2_F + half_lat_step) * sqr((float)y / height);
- float *pixel_row = pixels + (y * width) * stride;
+ float *pixel_row = pixels + (y * width * stride);
for (int x = 0; x < half_width; x++) {
float longitude = longitude_step * x - M_PI_F;
@@ -301,13 +305,15 @@ void nishita_skymodel_precompute_texture(float *pixels,
single_scattering(dir, sun_dir, cam_pos, air_density, dust_density, ozone_density, spectrum);
float3 xyz = spec_to_xyz(spectrum);
- pixel_row[x * stride + 0] = xyz.x;
- pixel_row[x * stride + 1] = xyz.y;
- pixel_row[x * stride + 2] = xyz.z;
- int mirror_x = width - x - 1;
- pixel_row[mirror_x * stride + 0] = xyz.x;
- pixel_row[mirror_x * stride + 1] = xyz.y;
- pixel_row[mirror_x * stride + 2] = xyz.z;
+ int pos_x = x * stride;
+ pixel_row[pos_x] = xyz.x;
+ pixel_row[pos_x + 1] = xyz.y;
+ pixel_row[pos_x + 2] = xyz.z;
+ /* mirror sky */
+ int mirror_x = (width - x - 1) * stride;
+ pixel_row[mirror_x] = xyz.x;
+ pixel_row[mirror_x + 1] = xyz.y;
+ pixel_row[mirror_x + 2] = xyz.z;
}
}
}
@@ -328,17 +334,17 @@ static void sun_radiation(float3 cam_dir,
/* Combine spectra and the optical depth into transmittance. */
float transmittance = rayleigh_coeff[i] * optical_depth.x * air_density +
1.11f * mie_coeff * optical_depth.y * dust_density;
- r_spectrum[i] = (irradiance[i] / solid_angle) * expf(-transmittance);
+ r_spectrum[i] = irradiance[i] * expf(-transmittance) / solid_angle;
}
}
-void nishita_skymodel_precompute_sun(float sun_elevation,
- float angular_diameter,
- float altitude,
- float air_density,
- float dust_density,
- float *pixel_bottom,
- float *pixel_top)
+void SKY_nishita_skymodel_precompute_sun(float sun_elevation,
+ float angular_diameter,
+ float altitude,
+ float air_density,
+ float dust_density,
+ float *r_pixel_bottom,
+ float *r_pixel_top)
{
/* definitions */
float half_angular = angular_diameter / 2.0f;
@@ -360,12 +366,10 @@ void nishita_skymodel_precompute_sun(float sun_elevation,
pix_top = spec_to_xyz(spectrum);
/* store pixels */
- pixel_bottom[0] = pix_bottom.x;
- pixel_bottom[1] = pix_bottom.y;
- pixel_bottom[2] = pix_bottom.z;
- pixel_top[0] = pix_top.x;
- pixel_top[1] = pix_top.y;
- pixel_top[2] = pix_top.z;
+ r_pixel_bottom[0] = pix_bottom.x;
+ r_pixel_bottom[1] = pix_bottom.y;
+ r_pixel_bottom[2] = pix_bottom.z;
+ r_pixel_top[0] = pix_top.x;
+ r_pixel_top[1] = pix_top.y;
+ r_pixel_top[2] = pix_top.z;
}
-
-CCL_NAMESPACE_END
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index e522ec3fcf9..a6101474aa9 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -601,8 +601,11 @@ class I18nSettings:
return json.dumps(export_dict)
def load(self, fname, reset=False):
+ reset = reset or fname is None
if reset:
self.__dict__ = {uid: data for uid, data in globals().items() if not uid.startswith("_")}
+ if fname is None:
+ return
if isinstance(fname, str):
if not os.path.isfile(fname):
# Assume it is already real JSon string...
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index b76f57c4545..832f9c1f7a4 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -43,6 +43,7 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.sndparticle_sampling_trappedair*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-trappedair"),
("bpy.types.fluiddomainsettings.sndparticle_sampling_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-wavecrest"),
("bpy.types.fluiddomainsettings.sndparticle_potential_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-radius"),
+ ("bpy.types.fluiddomainsettings.openvdb_cache_compress_type*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-openvdb-cache-compress-type"),
("bpy.types.fluiddomainsettings.sndparticle_bubble_buoyancy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-bubble-buoyancy"),
("bpy.types.fluiddomainsettings.sndparticle_combined_export*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-combined-export"),
("bpy.types.fluiddomainsettings.use_collision_border_bottom*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-bottom"),
@@ -68,7 +69,6 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_polygonalization*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/polygonization.html#bpy-types-linestylegeometrymodifier-polygonalization"),
("bpy.ops.view3d.edit_mesh_extrude_move_shrink_fatten*", "modeling/meshes/editing/face/extrude_faces_normal.html#bpy-ops-view3d-edit-mesh-extrude-move-shrink-fatten"),
("bpy.types.cyclesrendersettings.distance_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-distance-cull-margin"),
- ("bpy.types.fluiddomainsettings.cache_particle_format*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-particle-format"),
("bpy.types.fluiddomainsettings.display_interpolation*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-display-interpolation"),
("bpy.types.materialgpencilstyle.use_fill_texture_mix*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-use-fill-texture-mix"),
("bpy.types.rendersettings_simplify_gpencil_shader_fx*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-shader-fx"),
@@ -91,15 +91,18 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.particle_band_width*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-particle-band-width"),
("bpy.types.fluiddomainsettings.particle_randomness*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-particle-randomness"),
("bpy.types.fluiddomainsettings.use_adaptive_domain*", "physics/fluid/type/domain/gas/adaptive_domain.html#bpy-types-fluiddomainsettings-use-adaptive-domain"),
+ ("bpy.types.fluiddomainsettings.use_resumable_cache*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-use-resumable-cache"),
("bpy.types.fluiddomainsettings.use_spray_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-use-spray-particles"),
("bpy.types.fluiddomainsettings.vector_display_type*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-display-type"),
("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"),
("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"),
("bpy.types.rendersettings.use_high_quality_normals*", "render/eevee/render_settings/performance.html#bpy-types-rendersettings-use-high-quality-normals"),
("bpy.types.cyclesrendersettings.use_distance_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-distance-cull"),
+ ("bpy.types.fluiddomainsettings.cache_frame_offset*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-frame-offset"),
("bpy.types.fluiddomainsettings.delete_in_obstacle*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-delete-in-obstacle"),
("bpy.types.fluiddomainsettings.mesh_concave_lower*", "physics/fluid/type/domain/liquid/mesh.html#bpy-types-fluiddomainsettings-mesh-concave-lower"),
("bpy.types.fluiddomainsettings.mesh_concave_upper*", "physics/fluid/type/domain/liquid/mesh.html#bpy-types-fluiddomainsettings-mesh-concave-upper"),
+ ("bpy.types.fluiddomainsettings.openvdb_data_depth*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-openvdb-data-depth"),
("bpy.types.fluiddomainsettings.use_dissolve_smoke*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-dissolve-smoke"),
("bpy.types.fluiddomainsettings.use_flip_particles*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-flip-particles"),
("bpy.types.fluiddomainsettings.use_foam_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-use-foam-particles"),
@@ -132,6 +135,7 @@ url_manual_mapping = (
("bpy.types.linestyle*modifier_distancefromobject*", "render/freestyle/parameter_editor/line_style/modifiers/color/distance_from_object.html#bpy-types-linestyle-modifier-distancefromobject"),
("bpy.types.linestylegeometrymodifier_2dtransform*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/2d_transform.html#bpy-types-linestylegeometrymodifier-2dtransform"),
("bpy.types.linestylegeometrymodifier_beziercurve*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/bezier_curve.html#bpy-types-linestylegeometrymodifier-beziercurve"),
+ ("bpy.types.particlesettings.use_parent_particles*", "physics/particles/emitter/render.html#bpy-types-particlesettings-use-parent-particles"),
("bpy.types.rendersettings_simplify_gpencil_blend*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-blend"),
("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"),
("bpy.types.cyclesrendersettings.use_camera_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-camera-cull"),
@@ -140,6 +144,7 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
("bpy.types.toolsettings.use_gpencil_draw_onback*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-onback"),
+ ("bpy.ops.sequencer.deinterlace_selected_movies*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-deinterlace-selected-movies"),
("bpy.types.brush.surface_smooth_current_vertex*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-current-vertex"),
("bpy.types.brush.use_multiplane_scrape_dynamic*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-use-multiplane-scrape-dynamic"),
("bpy.types.clothsettings.vertex_group_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-pressure"),
@@ -267,6 +272,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.use_placeholder*", "render/output/settings.html#bpy-types-rendersettings-use-placeholder"),
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
("bpy.types.spacedopesheeteditor.auto_snap*", "editors/dope_sheet/editing.html#bpy-types-spacedopesheeteditor-auto-snap"),
+ ("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"),
("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"),
("bpy.ops.object.vertex_group_limit_total*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-limit-total"),
("bpy.ops.object.vertex_group_remove_from*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-remove-from"),
@@ -276,7 +282,6 @@ url_manual_mapping = (
("bpy.types.clothsettings.pressure_factor*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-pressure-factor"),
("bpy.types.compositornodecolorcorrection*", "compositing/types/color/color_correction.html#bpy-types-compositornodecolorcorrection"),
("bpy.types.compositornodemoviedistortion*", "compositing/types/distort/movie_distortion.html#bpy-types-compositornodemoviedistortion"),
- ("bpy.types.ffmpegsettings.audio_channels*", "scene_layout/scene/properties.html#bpy-types-ffmpegsettings-audio-channels"),
("bpy.types.fluiddomainsettings.use_guide*", "physics/fluid/type/domain/guides.html#bpy-types-fluiddomainsettings-use-guide"),
("bpy.types.fluiddomainsettings.use_noise*", "physics/fluid/type/domain/gas/noise.html#bpy-types-fluiddomainsettings-use-noise"),
("bpy.types.fluiddomainsettings.vorticity*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-vorticity"),
@@ -288,6 +293,8 @@ url_manual_mapping = (
("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
("bpy.types.sceneeevee.taa_render_samples*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-taa-render-samples"),
+ ("bpy.types.spacetexteditor.margin_column*", "editors/text_editor.html#bpy-types-spacetexteditor-margin-column"),
+ ("bpy.types.spacetexteditor.use_find_wrap*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-wrap"),
("bpy.types.spaceuveditor.pixel_snap_mode*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-pixel-snap-mode"),
("bpy.types.spaceuveditor.use_live_unwrap*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-use-live-unwrap"),
("bpy.types.vertexweightproximitymodifier*", "modeling/modifiers/modify/weight_proximity.html#bpy-types-vertexweightproximitymodifier"),
@@ -296,7 +303,6 @@ url_manual_mapping = (
("bpy.types.brush.use_grab_active_vertex*", "sculpt_paint/sculpting/tools/grab.html#bpy-types-brush-use-grab-active-vertex"),
("bpy.types.compositornodebrightcontrast*", "compositing/types/color/bright_contrast.html#bpy-types-compositornodebrightcontrast"),
("bpy.types.compositornodedoubleedgemask*", "compositing/types/matte/double_edge_mask.html#bpy-types-compositornodedoubleedgemask"),
- ("bpy.types.ffmpegsettings.audio_mixrate*", "scene_layout/scene/properties.html#bpy-types-ffmpegsettings-audio-mixrate"),
("bpy.types.fluiddomainsettings.clipping*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-clipping"),
("bpy.types.fluiddomainsettings.use_mesh*", "physics/fluid/type/domain/liquid/mesh.html#bpy-types-fluiddomainsettings-use-mesh"),
("bpy.types.material.preview_render_type*", "render/materials/preview.html#bpy-types-material-preview-render-type"),
@@ -309,12 +315,15 @@ url_manual_mapping = (
("bpy.types.shadernodevectordisplacement*", "render/shader_nodes/vector/vector_displacement.html#bpy-types-shadernodevectordisplacement"),
("bpy.types.spacegrapheditor.show_cursor*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-show-cursor"),
("bpy.types.spaceimageeditor.show_repeat*", "editors/image/view_tab.html#bpy-types-spaceimageeditor-show-repeat"),
+ ("bpy.types.spacetexteditor.replace_text*", "editors/text_editor.html#bpy-types-spacetexteditor-replace-text"),
+ ("bpy.types.spacetexteditor.use_find_all*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-all"),
("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"),
("bpy.ops.curve.normals_make_consistent*", "modeling/curves/editing/control_points.html#bpy-ops-curve-normals-make-consistent"),
("bpy.ops.gpencil.stroke_simplify_fixed*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify-fixed"),
("bpy.ops.object.gpencil_modifier_apply*", "grease_pencil/modifiers/introduction.html#bpy-ops-object-gpencil-modifier-apply"),
("bpy.ops.object.vertex_group_normalize*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-normalize"),
("bpy.ops.object.visual_transform_apply*", "scene_layout/object/editing/apply.html#bpy-ops-object-visual-transform-apply"),
+ ("bpy.ops.sequencer.change_effect_input*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-effect-input"),
("bpy.types.brush.texture_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-texture-overlay-alpha"),
("bpy.types.brushgpencilsettings.random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-random"),
("bpy.types.clothsettings.target_volume*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-target-volume"),
@@ -327,16 +336,20 @@ url_manual_mapping = (
("bpy.types.linestyle*modifier_material*", "render/freestyle/parameter_editor/line_style/modifiers/color/material.html#bpy-types-linestyle-modifier-material"),
("bpy.types.particlesettingstextureslot*", "physics/particles/texture_influence.html#bpy-types-particlesettingstextureslot"),
("bpy.types.posebone.ik_rotation_weight*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-ik-rotation-weight"),
+ ("bpy.types.regionview3d.show_sync_view*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-show-sync-view"),
("bpy.types.sceneeevee.volumetric_light*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric-light"),
("bpy.types.sculpt.symmetrize_direction*", "sculpt_paint/sculpting/tool_settings/symmetry.html#bpy-types-sculpt-symmetrize-direction"),
("bpy.types.sequenceeditor.show_overlay*", "video_editing/preview/properties.html#bpy-types-sequenceeditor-show-overlay"),
+ ("bpy.types.spacetexteditor.show_margin*", "editors/text_editor.html#bpy-types-spacetexteditor-show-margin"),
("bpy.types.spline.radius_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-radius-interpolation"),
("bpy.types.viewlayer.material_override*", "render/layers/layers.html#bpy-types-viewlayer-material-override"),
("bpy.ops.gpencil.interpolate_sequence*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-interpolate-sequence"),
("bpy.ops.mesh.normals_make_consistent*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-normals-make-consistent"),
+ ("bpy.ops.mesh.offset_edge_loops_slide*", "modeling/meshes/editing/edge/offset_edge_slide.html#bpy-ops-mesh-offset-edge-loops-slide"),
("bpy.ops.object.duplicate_move_linked*", "scene_layout/object/editing/duplicate_linked.html#bpy-ops-object-duplicate-move-linked"),
("bpy.ops.object.vertex_group_quantize*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-quantize"),
- ("bpy.ops.view3d.localview_remove_from*", "editors/3dview/navigate/views.html#bpy-ops-view3d-localview-remove-from"),
+ ("bpy.ops.sequencer.change_effect_type*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-effect-type"),
+ ("bpy.ops.view3d.localview_remove_from*", "editors/3dview/navigate/local_view.html#bpy-ops-view3d-localview-remove-from"),
("bpy.types.animdata.action_blend_type*", "editors/nla/properties_modifiers.html#bpy-types-animdata-action-blend-type"),
("bpy.types.brush.cursor_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-overlay-alpha"),
("bpy.types.brush.normal_radius_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-normal-radius-factor"),
@@ -354,6 +367,9 @@ url_manual_mapping = (
("bpy.types.materialgpencilstyle.color*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-color"),
("bpy.types.movietrackingstabilization*", "movie_clip/tracking/clip/properties/stabilization/index.html#bpy-types-movietrackingstabilization"),
("bpy.types.object.display_bounds_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-bounds-type"),
+ ("bpy.types.regionview3d.lock_rotation*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-lock-rotation"),
+ ("bpy.types.scene.audio_distance_model*", "scene_layout/scene/properties.html#bpy-types-scene-audio-distance-model"),
+ ("bpy.types.scene.audio_doppler_factor*", "scene_layout/scene/properties.html#bpy-types-scene-audio-doppler-factor"),
("bpy.types.shadernodeambientocclusion*", "render/shader_nodes/input/ao.html#bpy-types-shadernodeambientocclusion"),
("bpy.types.shadernodevolumeabsorption*", "render/shader_nodes/shader/volume_absorption.html#bpy-types-shadernodevolumeabsorption"),
("bpy.types.shadernodevolumeprincipled*", "render/shader_nodes/shader/volume_principled.html#bpy-types-shadernodevolumeprincipled"),
@@ -373,6 +389,7 @@ url_manual_mapping = (
("bpy.types.brush.crease_pinch_factor*", "sculpt_paint/sculpting/tools/snake_hook.html#bpy-types-brush-crease-pinch-factor"),
("bpy.types.brush.elastic_deform_type*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-type"),
("bpy.types.brush.use_primary_overlay*", "sculpt_paint/brush/cursor.html#bpy-types-brush-use-primary-overlay"),
+ ("bpy.types.camera.passepartout_alpha*", "render/cameras.html#bpy-types-camera-passepartout-alpha"),
("bpy.types.compositornodechromamatte*", "compositing/types/matte/chroma_key.html#bpy-types-compositornodechromamatte"),
("bpy.types.compositornodedilateerode*", "compositing/types/filter/dilate_erode.html#bpy-types-compositornodedilateerode"),
("bpy.types.compositornodeellipsemask*", "compositing/types/matte/ellipse_mask.html#bpy-types-compositornodeellipsemask"),
@@ -385,12 +402,17 @@ url_manual_mapping = (
("bpy.types.materialgpencilstyle.mode*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-mode"),
("bpy.types.object.empty_display_size*", "modeling/empties.html#bpy-types-object-empty-display-size"),
("bpy.types.object.empty_display_type*", "modeling/empties.html#bpy-types-object-empty-display-type"),
+ ("bpy.types.regionview3d.use_box_clip*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-use-box-clip"),
("bpy.types.rendersettings.use_border*", "render/output/settings.html#bpy-types-rendersettings-use-border"),
+ ("bpy.types.scene.audio_doppler_speed*", "scene_layout/scene/properties.html#bpy-types-scene-audio-doppler-speed"),
("bpy.types.sceneeevee.bokeh_max_size*", "render/eevee/render_settings/depth_of_field.html#bpy-types-sceneeevee-bokeh-max-size"),
("bpy.types.shadernodebsdfanisotropic*", "render/shader_nodes/shader/anisotropic.html#bpy-types-shadernodebsdfanisotropic"),
("bpy.types.shadernodebsdftranslucent*", "render/shader_nodes/shader/translucent.html#bpy-types-shadernodebsdftranslucent"),
("bpy.types.shadernodebsdftransparent*", "render/shader_nodes/shader/transparent.html#bpy-types-shadernodebsdftransparent"),
("bpy.types.shadernodevectortransform*", "render/shader_nodes/vector/transform.html#bpy-types-shadernodevectortransform"),
+ ("bpy.types.spacetexteditor.find_text*", "editors/text_editor.html#bpy-types-spacetexteditor-find-text"),
+ ("bpy.types.spacetexteditor.font_size*", "editors/text_editor.html#bpy-types-spacetexteditor-font-size"),
+ ("bpy.types.spacetexteditor.tab_width*", "editors/text_editor.html#bpy-types-spacetexteditor-tab-width"),
("bpy.types.spaceuveditor.lock_bounds*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-lock-bounds"),
("bpy.types.spline.tilt_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-tilt-interpolation"),
("bpy.ops.mesh.customdata_mask_clear*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-mesh-customdata-mask-clear"),
@@ -414,6 +436,7 @@ url_manual_mapping = (
("bpy.types.brush.auto_smooth_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-auto-smooth-factor"),
("bpy.types.brush.smooth_deform_type*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-smooth-deform-type"),
("bpy.types.brush.use_cursor_overlay*", "sculpt_paint/brush/cursor.html#bpy-types-brush-use-cursor-overlay"),
+ ("bpy.types.camera.show_passepartout*", "render/cameras.html#bpy-types-camera-show-passepartout"),
("bpy.types.compositornodebokehimage*", "compositing/types/input/bokeh_image.html#bpy-types-compositornodebokehimage"),
("bpy.types.compositornodecolormatte*", "compositing/types/matte/color_key.html#bpy-types-compositornodecolormatte"),
("bpy.types.compositornodecolorspill*", "compositing/types/matte/color_spill.html#bpy-types-compositornodecolorspill"),
@@ -430,7 +453,7 @@ url_manual_mapping = (
("bpy.types.linestyle*modifier_noise*", "render/freestyle/parameter_editor/line_style/modifiers/color/noise.html#bpy-types-linestyle-modifier-noise"),
("bpy.types.maintainvolumeconstraint*", "animation/constraints/transform/maintain_volume.html#bpy-types-maintainvolumeconstraint"),
("bpy.types.mesh.use_mirror_topology*", "modeling/meshes/tools/tool_settings.html#bpy-types-mesh-use-mirror-topology"),
- ("bpy.types.particleinstancemodifier*", "modeling/modifiers/simulate/particle_instance.html#bpy-types-particleinstancemodifier"),
+ ("bpy.types.particleinstancemodifier*", "modeling/modifiers/physics/particle_instance.html#bpy-types-particleinstancemodifier"),
("bpy.types.shadernodebrightcontrast*", "render/shader_nodes/color/bright_contrast.html#bpy-types-shadernodebrightcontrast"),
("bpy.types.shadernodebsdfprincipled*", "render/shader_nodes/shader/principled.html#bpy-types-shadernodebsdfprincipled"),
("bpy.types.shadernodebsdfrefraction*", "render/shader_nodes/shader/refraction.html#bpy-types-shadernodebsdfrefraction"),
@@ -448,6 +471,8 @@ url_manual_mapping = (
("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"),
("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-set-pivot-position"),
+ ("bpy.ops.sequencer.reassign_inputs*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-reassign-inputs"),
+ ("bpy.ops.view3d.view_center_camera*", "editors/3dview/navigate/camera_view.html#bpy-ops-view3d-view-center-camera"),
("bpy.types.armaturegpencilmodifier*", "grease_pencil/modifiers/deform/armature.html#bpy-types-armaturegpencilmodifier"),
("bpy.types.camera.show_composition*", "render/cameras.html#bpy-types-camera-show-composition"),
("bpy.types.compositornodealphaover*", "compositing/types/color/alpha_over.html#bpy-types-compositornodealphaover"),
@@ -462,6 +487,7 @@ url_manual_mapping = (
("bpy.types.compositornodestabilize*", "compositing/types/distort/stabilize_2d.html#bpy-types-compositornodestabilize"),
("bpy.types.compositornodetransform*", "compositing/types/distort/transform.html#bpy-types-compositornodetransform"),
("bpy.types.compositornodetranslate*", "compositing/types/distort/translate.html#bpy-types-compositornodetranslate"),
+ ("bpy.types.constraint.target_space*", "animation/constraints/interface/common.html#bpy-types-constraint-target-space"),
("bpy.types.freestylemodulesettings*", "render/freestyle/python.html#bpy-types-freestylemodulesettings"),
("bpy.types.gpencillayer.blend_mode*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-blend-mode"),
("bpy.types.gpencillayer.mask_layer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-mask-layer"),
@@ -498,6 +524,7 @@ url_manual_mapping = (
("bpy.ops.object.vertex_parent_set*", "modeling/meshes/editing/vertex/make_vertex_parent.html#bpy-ops-object-vertex-parent-set"),
("bpy.ops.paint.mask_lasso_gesture*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-paint-mask-lasso-gesture"),
("bpy.ops.screen.spacedata_cleanup*", "advanced/operators.html#bpy-ops-screen-spacedata-cleanup"),
+ ("bpy.ops.sequencer.duplicate_move*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-duplicate-move"),
("bpy.ops.uv.average_islands_scale*", "modeling/meshes/uv/editing.html#bpy-ops-uv-average-islands-scale"),
("bpy.types.brightcontrastmodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-brightcontrastmodifier"),
("bpy.types.brush.cursor_color_add*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-color-add"),
@@ -516,6 +543,7 @@ url_manual_mapping = (
("bpy.types.compositornodesunbeams*", "compositing/types/filter/sun_beams.html#bpy-types-compositornodesunbeams"),
("bpy.types.compositornodetrackpos*", "compositing/types/input/track_position.html#bpy-types-compositornodetrackpos"),
("bpy.types.compositornodezcombine*", "compositing/types/color/z_combine.html#bpy-types-compositornodezcombine"),
+ ("bpy.types.constraint.owner_space*", "animation/constraints/interface/common.html#bpy-types-constraint-owner-space"),
("bpy.types.copylocationconstraint*", "animation/constraints/transform/copy_location.html#bpy-types-copylocationconstraint"),
("bpy.types.copyrotationconstraint*", "animation/constraints/transform/copy_rotation.html#bpy-types-copyrotationconstraint"),
("bpy.types.cyclesmaterialsettings*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings"),
@@ -585,6 +613,7 @@ url_manual_mapping = (
("bpy.types.particlefluidsettings*", "physics/particles/emitter/physics/fluid.html#bpy-types-particlefluidsettings"),
("bpy.types.posebone.custom_shape*", "animation/armatures/bones/properties/display.html#bpy-types-posebone-custom-shape"),
("bpy.types.sceneeevee.volumetric*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric"),
+ ("bpy.types.sculpt.gravity_object*", "sculpt_paint/sculpting/tool_settings/options.html#bpy-types-sculpt-gravity-object"),
("bpy.types.shadernodebsdfdiffuse*", "render/shader_nodes/shader/diffuse.html#bpy-types-shadernodebsdfdiffuse"),
("bpy.types.shadernodelayerweight*", "render/shader_nodes/input/layer_weight.html#bpy-types-shadernodelayerweight"),
("bpy.types.shadernodeoutputlight*", "render/shader_nodes/output/light.html#bpy-types-shadernodeoutputlight"),
@@ -611,6 +640,7 @@ url_manual_mapping = (
("bpy.ops.outliner.lib_operation*", "files/linked_libraries/introduction.html#bpy-ops-outliner-lib-operation"),
("bpy.ops.outliner.orphans_purge*", "editors/outliner.html#bpy-ops-outliner-orphans-purge"),
("bpy.ops.screen.region_quadview*", "editors/3dview/navigate/views.html#bpy-ops-screen-region-quadview"),
+ ("bpy.ops.sequencer.offset_clear*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-offset-clear"),
("bpy.ops.uv.follow_active_quads*", "modeling/meshes/editing/uv.html#bpy-ops-uv-follow-active-quads"),
("bpy.types.arraygpencilmodifier*", "grease_pencil/modifiers/generate/array.html#bpy-types-arraygpencilmodifier"),
("bpy.types.brush.use_persistent*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-use-persistent"),
@@ -677,8 +707,12 @@ url_manual_mapping = (
("bpy.ops.object.select_pattern*", "scene_layout/object/selecting.html#bpy-ops-object-select-pattern"),
("bpy.ops.paint.mask_flood_fill*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-paint-mask-flood-fill"),
("bpy.ops.screen.repeat_history*", "interface/undo_redo.html#bpy-ops-screen-repeat-history"),
+ ("bpy.ops.sculpt.face_sets_init*", "sculpt_paint/sculpting/editing.html#bpy-ops-sculpt-face-sets-init"),
+ ("bpy.ops.sequencer.change_path*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-path"),
("bpy.ops.sequencer.refresh_all*", "video_editing/sequencer/navigating.html#bpy-ops-sequencer-refresh-all"),
+ ("bpy.ops.sequencer.swap_inputs*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-swap-inputs"),
("bpy.ops.surface.primitive*add*", "modeling/surfaces/primitives.html#bpy-ops-surface-primitive-add"),
+ ("bpy.ops.text.resolve_conflict*", "editors/text_editor.html#bpy-ops-text-resolve-conflict"),
("bpy.ops.transform.edge_crease*", "modeling/meshes/editing/edge/edge_data.html#bpy-ops-transform-edge-crease"),
("bpy.ops.transform.skin_resize*", "modeling/meshes/editing/mesh/transform/skin_resize.html#bpy-ops-transform-skin-resize"),
("bpy.ops.uv.seams_from_islands*", "modeling/meshes/uv/unwrapping/seams.html#bpy-ops-uv-seams-from-islands"),
@@ -731,6 +765,7 @@ url_manual_mapping = (
("bpy.types.windowmanager.addon*", "editors/preferences/addons.html#bpy-types-windowmanager-addon"),
("bpy.ops.anim.keyframe_delete*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-delete"),
("bpy.ops.anim.keyframe_insert*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-insert"),
+ ("bpy.ops.clip.detect_features*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-detect-features"),
("bpy.ops.console.autocomplete*", "editors/python_console.html#bpy-ops-console-autocomplete"),
("bpy.ops.curve.dissolve_verts*", "modeling/curves/editing/curve.html#bpy-ops-curve-dissolve-verts"),
("bpy.ops.curve.duplicate_move*", "modeling/curves/editing/curve.html#bpy-ops-curve-duplicate-move"),
@@ -752,6 +787,9 @@ url_manual_mapping = (
("bpy.ops.object.select_random*", "scene_layout/object/selecting.html#bpy-ops-object-select-random"),
("bpy.ops.paint.add_simple_uvs*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-ops-paint-add-simple-uvs"),
("bpy.ops.scene.view_layer_add*", "render/layers/layers.html#bpy-ops-scene-view-layer-add"),
+ ("bpy.ops.sequencer.gap_insert*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-gap-insert"),
+ ("bpy.ops.sequencer.gap_remove*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-gap-remove"),
+ ("bpy.ops.sequencer.rendersize*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-rendersize"),
("bpy.ops.sound.bake_animation*", "scene_layout/scene/properties.html#bpy-ops-sound-bake-animation"),
("bpy.ops.transform.edge_slide*", "modeling/meshes/editing/edge/edge_slide.html#bpy-ops-transform-edge-slide"),
("bpy.ops.transform.vert_slide*", "modeling/meshes/editing/vertex/slide_vertices.html#bpy-ops-transform-vert-slide"),
@@ -769,7 +807,7 @@ url_manual_mapping = (
("bpy.types.compositornodetime*", "compositing/types/input/time.html#bpy-types-compositornodetime"),
("bpy.types.curve.resolution_u*", "modeling/curves/properties/shape.html#bpy-types-curve-resolution-u"),
("bpy.types.curve.resolution_v*", "modeling/surfaces/properties/shape.html#bpy-types-curve-resolution-v"),
- ("bpy.types.curvepaintsettings*", "modeling/curves/editing/other.html#bpy-types-curvepaintsettings"),
+ ("bpy.types.curvepaintsettings*", "modeling/curves/tools/draw.html#bpy-types-curvepaintsettings"),
("bpy.types.fmodifiergenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiergenerator"),
("bpy.types.freestylelinestyle*", "render/freestyle/parameter_editor/line_style/index.html#bpy-types-freestylelinestyle"),
("bpy.types.gammacrosssequence*", "video_editing/sequencer/strips/transitions/cross.html#bpy-types-gammacrosssequence"),
@@ -825,7 +863,9 @@ url_manual_mapping = (
("bpy.ops.object.parent_clear*", "scene_layout/object/editing/parent.html#bpy-ops-object-parent-clear"),
("bpy.ops.object.shade_smooth*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-smooth"),
("bpy.ops.object.voxel_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-voxel-remesh"),
+ ("bpy.ops.sequencer.swap_data*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-swap-data"),
("bpy.ops.transform.push_pull*", "modeling/meshes/editing/mesh/transform/push_pull.html#bpy-ops-transform-push-pull"),
+ ("bpy.ops.transform.seq_slide*", "video_editing/sequencer/editing.html#bpy-ops-transform-seq-slide"),
("bpy.ops.transform.trackball*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-trackball"),
("bpy.ops.transform.transform*", "scene_layout/object/editing/transform/align_transform_orientation.html#bpy-ops-transform-transform"),
("bpy.ops.transform.translate*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-translate"),
@@ -888,7 +928,7 @@ url_manual_mapping = (
("bpy.ops.mesh.edge_collapse*", "modeling/meshes/editing/mesh/delete.html#bpy-ops-mesh-edge-collapse"),
("bpy.ops.mesh.edge_face_add*", "modeling/meshes/editing/vertex/make_face_edge.html#bpy-ops-mesh-edge-face-add"),
("bpy.ops.mesh.knife_project*", "modeling/meshes/editing/mesh/knife_project.html#bpy-ops-mesh-knife-project"),
- ("bpy.ops.mesh.loopcut_slide*", "modeling/meshes/tools/loop.html#bpy-ops-mesh-loopcut-slide"),
+ ("bpy.ops.mesh.loopcut_slide*", "modeling/meshes/editing/edge/loopcut_slide.html#bpy-ops-mesh-loopcut-slide"),
("bpy.ops.mesh.merge_normals*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-merge-normals"),
("bpy.ops.mesh.normals_tools*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-normals-tools"),
("bpy.ops.mesh.point_normals*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-point-normals"),
@@ -905,6 +945,7 @@ url_manual_mapping = (
("bpy.ops.sculpt.mask_expand*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-sculpt-mask-expand"),
("bpy.ops.sculpt.mask_filter*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-sculpt-mask-filter"),
("bpy.ops.transform.tosphere*", "modeling/meshes/editing/mesh/transform/to_sphere.html#bpy-ops-transform-tosphere"),
+ ("bpy.ops.view3d.clip_border*", "editors/3dview/navigate/regions.html#bpy-ops-view3d-clip-border"),
("bpy.ops.wm.previews_ensure*", "files/blend/previews.html#bpy-ops-wm-previews-ensure"),
("bpy.types.actionconstraint*", "animation/constraints/relationship/action.html#bpy-types-actionconstraint"),
("bpy.types.addonpreferences*", "editors/preferences/addons.html#bpy-types-addonpreferences"),
@@ -944,6 +985,7 @@ url_manual_mapping = (
("bpy.types.spacepreferences*", "editors/preferences/index.html#bpy-types-spacepreferences"),
("bpy.types.spaceview3d.lock*", "editors/3dview/properties/sidebar.html#bpy-types-spaceview3d-lock"),
("bpy.types.subtractsequence*", "video_editing/sequencer/strips/effects/subtract.html#bpy-types-subtractsequence"),
+ ("bpy.types.text.indentation*", "editors/text_editor.html#bpy-types-text-indentation"),
("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"),
("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"),
("bpy.types.viewlayer.use_ao*", "render/layers/layers.html#bpy-types-viewlayer-use-ao"),
@@ -977,7 +1019,7 @@ url_manual_mapping = (
("bpy.types.booleanmodifier*", "modeling/modifiers/generate/booleans.html#bpy-types-booleanmodifier"),
("bpy.types.brush.mask_tool*", "sculpt_paint/sculpting/tools/mask.html#bpy-types-brush-mask-tool"),
("bpy.types.constraint.mute*", "animation/constraints/interface/header.html#bpy-types-constraint-mute"),
- ("bpy.types.explodemodifier*", "modeling/modifiers/simulate/explode.html#bpy-types-explodemodifier"),
+ ("bpy.types.explodemodifier*", "modeling/modifiers/physics/explode.html#bpy-types-explodemodifier"),
("bpy.types.fcurvemodifiers*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fcurvemodifiers"),
("bpy.types.floorconstraint*", "animation/constraints/relationship/floor.html#bpy-types-floorconstraint"),
("bpy.types.fmodifiercycles*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiercycles"),
@@ -1021,12 +1063,17 @@ url_manual_mapping = (
("bpy.ops.object.hide_view*", "scene_layout/object/editing/show_hide.html#bpy-ops-object-hide-view"),
("bpy.ops.object.track_set*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-set"),
("bpy.ops.scene.view_layer*", "render/layers/layers.html#bpy-ops-scene-view-layer"),
+ ("bpy.ops.sequencer.delete*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-delete"),
+ ("bpy.ops.sequencer.reload*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-reload"),
+ ("bpy.ops.sequencer.unlock*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-unlock"),
+ ("bpy.ops.sequencer.unmute*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-unmute"),
("bpy.ops.transform.mirror*", "scene_layout/object/editing/mirror.html#bpy-ops-transform-mirror"),
("bpy.ops.transform.resize*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-resize"),
("bpy.ops.transform.rotate*", "scene_layout/object/editing/transform/basics.html#bpy-ops-transform-rotate"),
("bpy.ops.uv.lightmap_pack*", "modeling/meshes/editing/uv.html#bpy-ops-uv-lightmap-pack"),
("bpy.ops.uv.smart_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-smart-project"),
- ("bpy.ops.view3d.localview*", "editors/3dview/navigate/views.html#bpy-ops-view3d-localview"),
+ ("bpy.ops.view3d.localview*", "editors/3dview/navigate/local_view.html#bpy-ops-view3d-localview"),
+ ("bpy.ops.view3d.view_axis*", "editors/3dview/navigate/viewpoint.html#bpy-ops-view3d-view-axis"),
("bpy.types.bone.show_wire*", "animation/armatures/bones/properties/display.html#bpy-types-bone-show-wire"),
("bpy.types.brush.hardness*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-hardness"),
("bpy.types.curvesmodifier*", "video_editing/sequencer/properties/modifiers.html#bpy-types-curvesmodifier"),
@@ -1043,6 +1090,7 @@ url_manual_mapping = (
("bpy.types.rigidbodyworld*", "physics/rigid_body/world.html#bpy-types-rigidbodyworld"),
("bpy.types.sceneeevee.ssr*", "render/eevee/render_settings/screen_space_reflections.html#bpy-types-sceneeevee-ssr"),
("bpy.types.sceneeevee.sss*", "render/eevee/render_settings/subsurface_scattering.html#bpy-types-sceneeevee-sss"),
+ ("bpy.types.sculpt.gravity*", "sculpt_paint/sculpting/tool_settings/options.html#bpy-types-sculpt-gravity"),
("bpy.types.shaderfxshadow*", "grease_pencil/visual_effects/shadow.html#bpy-types-shaderfxshadow"),
("bpy.types.shadernodebump*", "render/shader_nodes/vector/bump.html#bpy-types-shadernodebump"),
("bpy.types.shadernodemath*", "render/shader_nodes/converter/math.html#bpy-types-shadernodemath"),
@@ -1076,6 +1124,7 @@ url_manual_mapping = (
("bpy.ops.object.armature*", "animation/armatures/index.html#bpy-ops-object-armature"),
("bpy.ops.object.face_map*", "modeling/meshes/properties/object_data.html#bpy-ops-object-face-map"),
("bpy.ops.rigidbody.world*", "physics/rigid_body/world.html#bpy-ops-rigidbody-world"),
+ ("bpy.ops.sequencer.split*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-split"),
("bpy.ops.transform.shear*", "modeling/meshes/editing/mesh/transform/shear.html#bpy-ops-transform-shear"),
("bpy.ops.uv.cube_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cube-project"),
("bpy.ops.uv.pack_islands*", "modeling/meshes/uv/editing.html#bpy-ops-uv-pack-islands"),
@@ -1103,7 +1152,7 @@ url_manual_mapping = (
("bpy.types.nlastrip.mute*", "editors/nla/properties_modifiers.html#bpy-types-nlastrip-mute"),
("bpy.types.nlastrip.name*", "editors/nla/properties_modifiers.html#bpy-types-nlastrip-name"),
("bpy.types.object.parent*", "scene_layout/object/editing/parent.html#bpy-types-object-parent"),
- ("bpy.types.oceanmodifier*", "modeling/modifiers/simulate/ocean.html#bpy-types-oceanmodifier"),
+ ("bpy.types.oceanmodifier*", "modeling/modifiers/physics/ocean.html#bpy-types-oceanmodifier"),
("bpy.types.particlebrush*", "physics/particles/mode.html#bpy-types-particlebrush"),
("bpy.types.scene.gravity*", "physics/forces/gravity.html#bpy-types-scene-gravity"),
("bpy.types.sceneeevee.gi*", "render/eevee/render_settings/indirect_lighting.html#bpy-types-sceneeevee-gi"),
@@ -1135,6 +1184,11 @@ url_manual_mapping = (
("bpy.ops.object.convert*", "scene_layout/object/editing/convert.html#bpy-ops-object-convert"),
("bpy.ops.object.gpencil*", "grease_pencil/index.html#bpy-ops-object-gpencil"),
("bpy.ops.object.speaker*", "render/output/audio/speaker.html#bpy-ops-object-speaker"),
+ ("bpy.ops.sequencer.lock*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-lock"),
+ ("bpy.ops.sequencer.mute*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-mute"),
+ ("bpy.ops.sequencer.slip*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-slip"),
+ ("bpy.ops.sequencer.snap*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-snap"),
+ ("bpy.ops.sequencer.swap*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-swap"),
("bpy.ops.transform.bend*", "modeling/meshes/editing/mesh/transform/bend.html#bpy-ops-transform-bend"),
("bpy.ops.transform.tilt*", "modeling/curves/editing/control_points.html#bpy-ops-transform-tilt"),
("bpy.ops.wm.search_menu*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search-menu"),
@@ -1219,6 +1273,7 @@ url_manual_mapping = (
("bpy.ops.object.align*", "scene_layout/object/editing/transform/align_objects.html#bpy-ops-object-align"),
("bpy.ops.object.empty*", "modeling/empties.html#bpy-ops-object-empty"),
("bpy.ops.object.quick*", "physics/introduction.html#bpy-ops-object-quick"),
+ ("bpy.ops.text.replace*", "editors/text_editor.html#bpy-ops-text-replace"),
("bpy.ops.uv.mark_seam*", "modeling/meshes/uv/unwrapping/seams.html#bpy-ops-uv-mark-seam"),
("bpy.ops.view3d.ruler*", "editors/3dview/toolbar/measure.html#bpy-ops-view3d-ruler"),
("bpy.types.areaspaces*", "interface/window_system/areas.html#bpy-types-areaspaces"),
@@ -1264,7 +1319,7 @@ url_manual_mapping = (
("bpy.types.viewlayer*", "render/layers/layers.html#bpy-types-viewlayer"),
("bpy.ops.collection*", "scene_layout/collections/collections.html#bpy-ops-collection"),
("bpy.ops.constraint*", "animation/constraints/index.html#bpy-ops-constraint"),
- ("bpy.ops.curve.draw*", "modeling/curves/editing/other.html#bpy-ops-curve-draw"),
+ ("bpy.ops.curve.draw*", "modeling/curves/tools/draw.html#bpy-ops-curve-draw"),
("bpy.ops.curve.hide*", "modeling/curves/editing/curve.html#bpy-ops-curve-hide"),
("bpy.ops.curve.spin*", "modeling/surfaces/editing/surface.html#bpy-ops-curve-spin"),
("bpy.ops.graph.bake*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-bake"),
@@ -1303,6 +1358,7 @@ url_manual_mapping = (
("bpy.ops.nla.split*", "editors/nla/editing.html#bpy-ops-nla-split"),
("bpy.ops.rigidbody*", "physics/rigid_body/index.html#bpy-ops-rigidbody"),
("bpy.ops.sequencer*", "video_editing/index.html#bpy-ops-sequencer"),
+ ("bpy.ops.text.find*", "editors/text_editor.html#bpy-ops-text-find"),
("bpy.ops.transform*", "scene_layout/object/editing/transform/index.html#bpy-ops-transform"),
("bpy.ops.uv.select*", "editors/uv/selecting.html#bpy-ops-uv-select"),
("bpy.ops.uv.stitch*", "modeling/meshes/uv/editing.html#bpy-ops-uv-stitch"),
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 4b037f209bb..3a885837444 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -738,6 +738,9 @@ def km_property_editor(_params):
("object.gpencil_modifier_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),
("object.gpencil_modifier_copy", {"type": 'D', "value": 'PRESS', "shift": True}, None),
("object.gpencil_modifier_apply", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("report", True)]}),
+ # ShaderFX panels
+ ("object.shaderfx_remove", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}),
+ ("object.shaderfx_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),
])
return keymap
@@ -847,6 +850,7 @@ def km_uv_editor(params):
{"properties": [("extend", False)]}),
("uv.select_loop", {"type": params.select_mouse, "value": params.select_mouse_value, "shift": True, "alt": True},
{"properties": [("extend", True)]}),
+ ("uv.shortest_path_pick", {"type": params.select_mouse, "value": params.select_mouse_value, "ctrl": True}, None),
("uv.select_split", {"type": 'Y', "value": 'PRESS'}, None),
("uv.select_box", {"type": 'B', "value": 'PRESS'},
{"properties": [("pinned", False)]}),
@@ -866,8 +870,11 @@ def km_uv_editor(params):
("uv.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None),
*_template_items_select_actions(params, "uv.select_all"),
("uv.select_pinned", {"type": 'P', "value": 'PRESS', "shift": True}, None),
- op_menu("IMAGE_MT_uvs_weldalign", {"type": 'W', "value": 'PRESS', "shift": True}),
- ("uv.stitch", {"type": 'V', "value": 'PRESS'}, None),
+ op_menu("IMAGE_MT_uvs_merge", {"type": 'M', "value": 'PRESS'}),
+ op_menu("IMAGE_MT_uvs_split", {"type": 'M', "value": 'PRESS', "alt": True}),
+ op_menu("IMAGE_MT_uvs_align", {"type": 'W', "value": 'PRESS', "shift": True}),
+ ("uv.stitch", {"type": 'V', "value": 'PRESS', "alt": True}, None),
+ ("uv.rip_move", {"type": 'V', "value": 'PRESS'}, None),
("uv.pin", {"type": 'P', "value": 'PRESS'},
{"properties": [("clear", False)]}),
("uv.pin", {"type": 'P', "value": 'PRESS', "alt": True},
@@ -5589,6 +5596,17 @@ def km_image_editor_tool_uv_select_lasso(params):
)
+def km_image_editor_tool_uv_rip_region(params):
+ return (
+ "Image Editor Tool: Uv, Rip Region",
+ {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
+ {"items": [
+ ("uv.rip_move", {"type": params.tool_tweak, "value": 'ANY'},
+ {"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
+ ]},
+ )
+
+
def km_image_editor_tool_uv_sculpt_stroke(params):
return (
"Image Editor Tool: Uv, Sculpt Stroke",
@@ -6791,6 +6809,7 @@ def generate_keymaps(params=None):
km_image_editor_tool_uv_select_box(params),
km_image_editor_tool_uv_select_circle(params),
km_image_editor_tool_uv_select_lasso(params),
+ km_image_editor_tool_uv_rip_region(params),
km_image_editor_tool_uv_sculpt_stroke(params),
km_image_editor_tool_uv_move(params),
km_image_editor_tool_uv_rotate(params),
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index a8e04eb2f24..02bfebbdc0c 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -159,6 +159,33 @@ class VIEW3D_OT_edit_mesh_extrude_shrink_fatten(Operator):
return self.execute(context)
+class VIEW3D_OT_edit_mesh_extrude_manifold_normal(Operator):
+ """Extrude manifold region along normals"""
+ bl_label = "Extrude Manifold Along Normals"
+ bl_idname = "view3d.edit_mesh_extrude_manifold_normal"
+
+ @classmethod
+ def poll(cls, context):
+ obj = context.active_object
+ return (obj is not None and obj.mode == 'EDIT')
+
+ def execute(self, context):
+ bpy.ops.mesh.extrude_manifold(
+ 'INVOKE_REGION_WIN',
+ MESH_OT_extrude_region={
+ "use_dissolve_ortho_edges": True,
+ },
+ TRANSFORM_OT_translate={
+ "orient_type": 'NORMAL',
+ "constraint_axis": (False, False, True),
+ },
+ )
+ return {'FINISHED'}
+
+ def invoke(self, context, _event):
+ return self.execute(context)
+
+
class VIEW3D_OT_transform_gizmo_set(Operator):
"""Set the current transform gizmo"""
bl_label = "Transform Gizmo Set"
@@ -208,5 +235,6 @@ classes = (
VIEW3D_OT_edit_mesh_extrude_individual_move,
VIEW3D_OT_edit_mesh_extrude_move,
VIEW3D_OT_edit_mesh_extrude_shrink_fatten,
+ VIEW3D_OT_edit_mesh_extrude_manifold_normal,
VIEW3D_OT_transform_gizmo_set,
)
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index a543ea6685c..fc11e4a0a87 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1466,8 +1466,7 @@ class WM_OT_properties_edit(Operator):
row = layout.row()
row.prop(self, "use_soft_limits")
- if bpy.app.use_override_library:
- row.prop(self, "is_overridable_library")
+ row.prop(self, "is_overridable_library")
row = layout.row(align=True)
row.enabled = self.use_soft_limits
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 8bae32775a9..215c96a5975 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -971,7 +971,7 @@ class ConstraintButtonsSubPanel(Panel):
self.layout.context_pointer_set("constraint", con)
return con
- def draw_transform_source(self, context):
+ def draw_transform_from(self, context):
layout = self.layout
con = self.get_constraint(context)
@@ -980,36 +980,29 @@ class ConstraintButtonsSubPanel(Panel):
layout.use_property_split = True
layout.use_property_decorate = True
+ from_axes = [con.map_to_x_from, con.map_to_y_from, con.map_to_z_from]
+
if con.map_from == 'ROTATION':
layout.prop(con, "from_rotation_mode", text="Mode")
ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
col = layout.column(align=True)
+ col.active = "X" in from_axes
col.prop(con, "from_min_x" + ext, text="X Min")
col.prop(con, "from_max_x" + ext, text="Max")
col = layout.column(align=True)
+ col.active = "Y" in from_axes
col.prop(con, "from_min_y" + ext, text="Y Min")
col.prop(con, "from_max_y" + ext, text="Max")
col = layout.column(align=True)
+ col.active = "Z" in from_axes
col.prop(con, "from_min_z" + ext, text="Z Min")
col.prop(con, "from_max_z" + ext, text="Max")
- def draw_transform_mapping(self, context):
- layout = self.layout
- con = self.get_constraint(context)
- layout.use_property_split = True
- layout.use_property_decorate = True
-
- layout.prop(con, "map_to_x_from", expand=False, text="Source Axis X")
-
- layout.prop(con, "map_to_y_from", expand=False, text="Y")
-
- layout.prop(con, "map_to_z_from", expand=False, text="Z")
-
- def draw_transform_destination(self, context):
+ def draw_transform_to(self, context):
layout = self.layout
con = self.get_constraint(context)
@@ -1024,15 +1017,18 @@ class ConstraintButtonsSubPanel(Panel):
ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
col = layout.column(align=True)
- col.prop(con, "to_min_x" + ext, text="X Min")
+ col.prop(con, "map_to_x_from", expand=False, text="X Source Axis")
+ col.prop(con, "to_min_x" + ext, text="Min")
col.prop(con, "to_max_x" + ext, text="Max")
col = layout.column(align=True)
- col.prop(con, "to_min_y" + ext, text="Y Min")
+ col.prop(con, "map_to_y_from", expand=False, text="Y Source Axis")
+ col.prop(con, "to_min_y" + ext, text="Min")
col.prop(con, "to_max_y" + ext, text="Max")
col = layout.column(align=True)
- col.prop(con, "to_min_z" + ext, text="Z Min")
+ col.prop(con, "map_to_z_from", expand=False, text="Z Source Axis")
+ col.prop(con, "to_min_z" + ext, text="Min")
col.prop(con, "to_max_z" + ext, text="Max")
layout.prop(con, "mix_mode" + ext, text="Mix")
@@ -1387,50 +1383,34 @@ class BONE_PT_bTransformConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
class OBJECT_PT_bTransformConstraint_source(ObjectConstraintPanel, ConstraintButtonsSubPanel):
bl_parent_id = "OBJECT_PT_bTransformConstraint"
- bl_label = "Source"
+ bl_label = "Map From"
def draw(self, context):
- self.draw_transform_source(context)
+ self.draw_transform_from(context)
-class BONE_PT_bTransformConstraint_source(BoneConstraintPanel, ConstraintButtonsSubPanel):
+class BONE_PT_bTransformConstraint_from(BoneConstraintPanel, ConstraintButtonsSubPanel):
bl_parent_id = "BONE_PT_bTransformConstraint"
- bl_label = "Source"
+ bl_label = "Map From"
def draw(self, context):
- self.draw_transform_source(context)
-
-
-class OBJECT_PT_bTransformConstraint_mapping(ObjectConstraintPanel, ConstraintButtonsSubPanel):
- bl_parent_id = "OBJECT_PT_bTransformConstraint"
- bl_label = "Mapping"
-
- def draw(self, context):
- self.draw_transform_mapping(context)
-
-
-class BONE_PT_bTransformConstraint_mapping(BoneConstraintPanel, ConstraintButtonsSubPanel):
- bl_parent_id = "BONE_PT_bTransformConstraint"
- bl_label = "Mapping"
-
- def draw(self, context):
- self.draw_transform_mapping(context)
+ self.draw_transform_from(context)
class OBJECT_PT_bTransformConstraint_destination(ObjectConstraintPanel, ConstraintButtonsSubPanel):
bl_parent_id = "OBJECT_PT_bTransformConstraint"
- bl_label = "Destination"
+ bl_label = "Map To"
def draw(self, context):
- self.draw_transform_destination(context)
+ self.draw_transform_to(context)
-class BONE_PT_bTransformConstraint_destination(BoneConstraintPanel, ConstraintButtonsSubPanel):
+class BONE_PT_bTransformConstraint_to(BoneConstraintPanel, ConstraintButtonsSubPanel):
bl_parent_id = "BONE_PT_bTransformConstraint"
- bl_label = "Destination"
+ bl_label = "Map To"
def draw(self, context):
- self.draw_transform_destination(context)
+ self.draw_transform_to(context)
# Shrinkwrap Constraint
@@ -1619,7 +1599,6 @@ classes = (
OBJECT_PT_bClampToConstraint,
OBJECT_PT_bTransformConstraint,
OBJECT_PT_bTransformConstraint_source,
- OBJECT_PT_bTransformConstraint_mapping,
OBJECT_PT_bTransformConstraint_destination,
OBJECT_PT_bShrinkwrapConstraint,
OBJECT_PT_bDampTrackConstraint,
@@ -1653,9 +1632,8 @@ classes = (
BONE_PT_bMinMaxConstraint,
BONE_PT_bClampToConstraint,
BONE_PT_bTransformConstraint,
- BONE_PT_bTransformConstraint_source,
- BONE_PT_bTransformConstraint_mapping,
- BONE_PT_bTransformConstraint_destination,
+ BONE_PT_bTransformConstraint_from,
+ BONE_PT_bTransformConstraint_to,
BONE_PT_bShrinkwrapConstraint,
BONE_PT_bDampTrackConstraint,
BONE_PT_bSplineIKConstraint,
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index fbd8e2d7cff..27df265d013 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -464,6 +464,10 @@ class DATA_PT_sculpt_vertex_colors(MeshButtonsPanel, Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+ @classmethod
+ def poll(cls, context):
+ return context.preferences.experimental.use_sculpt_vertex_colors
+
def draw(self, context):
layout = self.layout
@@ -508,7 +512,8 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel):
col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
col.prop(mesh, "use_remesh_preserve_paint_mask", text="Paint Mask")
col.prop(mesh, "use_remesh_preserve_sculpt_face_sets", text="Face Sets")
- col.prop(mesh, "use_remesh_preserve_vertex_colors", text="Vertex Colors")
+ if context.preferences.experimental.use_sculpt_vertex_colors:
+ col.prop(mesh, "use_remesh_preserve_vertex_colors", text="Vertex Colors")
col.operator("object.voxel_remesh", text="Voxel Remesh")
else:
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index f70789ebeed..54b1ca3d910 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -115,6 +115,15 @@ class VIEWLAYER_PT_freestyle(ViewLayerFreestyleButtonsPanel, Panel):
bl_label = "Freestyle"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+ def draw_header(self, context):
+ view_layer = context.view_layer
+ rd = context.scene.render
+
+ layout = self.layout
+
+ layout.active = rd.use_freestyle
+ layout.prop(view_layer, "use_freestyle", text="")
+
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 209231cacb0..004bcaf819b 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -192,6 +192,10 @@ class ColorPalettePanel(BrushPanel):
elif context.vertex_paint_object:
capabilities = brush.vertex_paint_capabilities
return capabilities.has_color
+
+ elif context.sculpt_object:
+ capabilities = brush.sculpt_capabilities
+ return capabilities.has_color
return False
def draw(self, context):
@@ -678,6 +682,10 @@ def brush_settings(layout, context, brush, popover=False):
col.prop(brush, "tip_roundness")
col.prop(brush, "tip_scale_x")
+ if brush.sculpt_tool == 'SMEAR':
+ col = layout.column()
+ col.prop(brush, "smear_deform_type")
+
if brush.sculpt_tool == 'MULTIPLANE_SCRAPE':
col = layout.column()
col.prop(brush, "multiplane_scrape_angle")
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 73bc5fe5c29..032a4a612c8 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -183,7 +183,7 @@ class CLIP_HT_header(Header):
r = active_object.reconstruction
if r.is_valid and sc.view == 'CLIP':
- layout.label(text="Solve error: %.4f" %
+ layout.label(text="Solve error: %.2f px" %
(r.average_error))
row = layout.row()
@@ -741,7 +741,7 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
layout.prop(act_track, "weight_stab")
if act_track.has_bundle:
- label_text = "Average Error: %.4f" % (act_track.average_error)
+ label_text = "Average Error: %.2f px" % (act_track.average_error)
layout.label(text=label_text)
layout.use_property_split = False
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 76b7fc7f156..651866cf316 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -176,7 +176,7 @@ class IMAGE_MT_select(Menu):
layout.separator()
layout.operator("uv.select_pinned")
- layout.operator("uv.select_linked")
+ layout.menu("IMAGE_MT_select_linked")
layout.separator()
@@ -184,6 +184,16 @@ class IMAGE_MT_select(Menu):
layout.operator("uv.select_overlap")
+class IMAGE_MT_select_linked(Menu):
+ bl_label = "Select Linked"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("uv.select_linked", text="Linked")
+ layout.operator("uv.shortest_path_select", text="Shortest Path")
+
+
class IMAGE_MT_image(Menu):
bl_label = "Image"
@@ -321,15 +331,37 @@ class IMAGE_MT_uvs_mirror(Menu):
layout.operator("transform.mirror", text="Y Axis").constraint_axis[1] = True
-class IMAGE_MT_uvs_weldalign(Menu):
- bl_label = "Weld/Align"
+class IMAGE_MT_uvs_align(Menu):
+ bl_label = "Align"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator_enum("uv.align", "axis")
+
+
+class IMAGE_MT_uvs_merge(Menu):
+ bl_label = "Merge"
def draw(self, _context):
layout = self.layout
- layout.operator("uv.weld") # W, 1.
- layout.operator("uv.remove_doubles")
- layout.operator_enum("uv.align", "axis") # W, 2/3/4.
+ layout.operator("uv.weld", text="At Center")
+ # Mainly to match the mesh menu.
+ layout.operator("uv.snap_selected", text="At Cursor").target = 'CURSOR'
+
+ layout.separator()
+
+ layout.operator("uv.remove_doubles", text="By Distance")
+
+
+class IMAGE_MT_uvs_split(Menu):
+ bl_label = "Split"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("uv.select_split", text="Selection")
class IMAGE_MT_uvs(Menu):
@@ -350,6 +382,11 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
+ layout.menu("IMAGE_MT_uvs_merge")
+ layout.menu("IMAGE_MT_uvs_split")
+
+ layout.separator()
+
layout.prop(uv, "use_live_unwrap")
layout.operator("uv.unwrap")
@@ -373,7 +410,7 @@ class IMAGE_MT_uvs(Menu):
layout.operator("uv.minimize_stretch")
layout.operator("uv.stitch")
- layout.menu("IMAGE_MT_uvs_weldalign")
+ layout.menu("IMAGE_MT_uvs_align")
layout.separator()
@@ -462,7 +499,7 @@ class IMAGE_MT_uvs_context_menu(Menu):
layout.separator()
# Remove
- layout.operator("uv.remove_doubles", text="Remove Double UVs")
+ layout.operator("uv.remove_doubles", text="Merge By Distance")
layout.operator("uv.stitch")
layout.operator("uv.weld")
@@ -1452,6 +1489,7 @@ classes = (
IMAGE_MT_view,
IMAGE_MT_view_zoom,
IMAGE_MT_select,
+ IMAGE_MT_select_linked,
IMAGE_MT_image,
IMAGE_MT_image_invert,
IMAGE_MT_uvs,
@@ -1459,7 +1497,9 @@ classes = (
IMAGE_MT_uvs_transform,
IMAGE_MT_uvs_snap,
IMAGE_MT_uvs_mirror,
- IMAGE_MT_uvs_weldalign,
+ IMAGE_MT_uvs_align,
+ IMAGE_MT_uvs_merge,
+ IMAGE_MT_uvs_split,
IMAGE_MT_uvs_select_mode,
IMAGE_MT_uvs_context_menu,
IMAGE_MT_mask_context_menu,
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 87464451632..b7852eb92e0 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -50,11 +50,14 @@ def generate_from_enum_ex(
attr,
cursor='DEFAULT',
tooldef_keywords={},
+ exclude_filter = {}
):
tool_defs = []
for enum in type.bl_rna.properties[attr].enum_items_static:
name = enum.name
idname = enum.identifier
+ if idname in exclude_filter:
+ continue
tool_defs.append(
ToolDef.from_dict(
dict(
@@ -1178,12 +1181,18 @@ class _defs_sculpt:
@staticmethod
def generate_from_brushes(context):
+ if bpy.context.preferences.experimental.use_sculpt_vertex_colors:
+ exclude_filter = {}
+ else:
+ exclude_filter = {'PAINT', 'SMEAR'}
+
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
icon_prefix="brush.sculpt.",
type=bpy.types.Brush,
attr="sculpt_tool",
+ exclude_filter = exclude_filter,
)
@ToolDef.from_fn
@@ -1579,6 +1588,20 @@ class _defs_image_uv_select:
)
+class _defs_image_uv_edit:
+
+ @ToolDef.from_fn
+ def rip_region():
+ return dict(
+ idname="builtin.rip_region",
+ label="Rip Region",
+ icon="ops.mesh.rip",
+ # TODO: generic operator (UV version of `VIEW3D_GGT_tool_generic_handle_free`).
+ widget=None,
+ keymap=(),
+ )
+
+
class _defs_image_uv_sculpt:
@staticmethod
@@ -2173,6 +2196,8 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_annotate,
None,
+ _defs_image_uv_edit.rip_region,
+ None,
lambda context: (
_defs_image_uv_sculpt.generate_from_brushes(context)
if _defs_image_generic.poll_uvedit(context)
@@ -2469,9 +2494,19 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_sculpt.mesh_filter,
_defs_sculpt.cloth_filter,
- _defs_sculpt.color_filter,
+ lambda context: (
+ (_defs_sculpt.color_filter,)
+ if bpy.context.preferences.view.show_developer_ui and \
+ bpy.context.preferences.experimental.use_sculpt_vertex_colors
+ else ()
+ ),
None,
- _defs_sculpt.mask_by_color,
+ lambda context: (
+ (_defs_sculpt.mask_by_color,)
+ if bpy.context.preferences.view.show_developer_ui and \
+ bpy.context.preferences.experimental.use_sculpt_vertex_colors
+ else ()
+ ),
None,
_defs_transform.translate,
_defs_transform.rotate,
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index e5171df597a..5392ed9cc25 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2143,6 +2143,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
self._draw_items(
context, (
({"property": "use_new_particle_system"}, "T73324"),
+ ({"property": "use_sculpt_vertex_colors"}, "T71947"),
),
)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index df2b3fcdbeb..e4d0423cd76 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2256,8 +2256,7 @@ class VIEW3D_MT_object_relations(Menu):
layout.operator("object.proxy_make", text="Make Proxy...")
- if bpy.app.use_override_library:
- layout.operator("object.make_override_library", text="Make Library Override...")
+ layout.operator("object.make_override_library", text="Make Library Override...")
layout.operator("object.make_dupli_face")
@@ -3877,6 +3876,8 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"),
'FACE': lambda layout:
layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"),
+ 'MANIFOLD': lambda layout:
+ layout.operator("view3d.edit_mesh_extrude_manifold_normal", text="Extrude Manifold"),
}
@staticmethod
@@ -3887,7 +3888,7 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
menu = []
if mesh.total_face_sel:
- menu += ['REGION', 'REGION_VERT_NORMAL', 'FACE']
+ menu += ['REGION', 'REGION_VERT_NORMAL', 'FACE', 'MANIFOLD']
if mesh.total_edge_sel and (select_mode[0] or select_mode[1]):
menu += ['EDGE']
if mesh.total_vert_sel and select_mode[0]:
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 549b89938e0..39e4ee2beac 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -737,7 +737,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
@classmethod
def poll(cls, context):
- return (context.sculpt_object and context.tool_settings.sculpt)
+ paint_settings = cls.paint_settings(context)
+ return (context.sculpt_object and context.tool_settings.sculpt and paint_settings)
def draw_header(self, context):
is_popover = self.is_popover
@@ -811,7 +812,8 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
col.prop(mesh, "use_remesh_preserve_paint_mask", text="Paint Mask")
col.prop(mesh, "use_remesh_preserve_sculpt_face_sets", text="Face Sets")
- col.prop(mesh, "use_remesh_preserve_vertex_colors", text="Vertex Colors")
+ if context.preferences.experimental.use_sculpt_vertex_colors:
+ col.prop(mesh, "use_remesh_preserve_vertex_colors", text="Vertex Colors")
layout.operator("object.voxel_remesh", text="Remesh")
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 2dc6c6cd409..50c1a2e4e4e 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -484,6 +484,7 @@ simulation_node_categories = [
NodeItem("SimulationNodeTime"),
NodeItem("SimulationNodeParticleAttribute"),
NodeItem("FunctionNodeGroupInstanceID"),
+ NodeItem("ShaderNodeValue"),
]),
SimulationNodeCategory("SIM_EMITTERS", "Emitters", items=[
NodeItem("SimulationNodeParticleMeshEmitter"),
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index 5aeaf4405f5..48e95740b9d 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -71,7 +71,11 @@ bool BKE_animdata_copy_id(struct Main *bmain,
const int flag);
/* Copy AnimData Actions */
-void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
+void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id);
+
+void BKE_animdata_duplicate_id_action(struct Main *bmain,
+ struct ID *id,
+ const uint duplicate_flags);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index f25482570b1..cd78746a3f0 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -93,10 +93,10 @@ typedef struct Cloth {
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
struct EdgeSet *edgeset; /* used for selfcollisions */
int last_frame;
- float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
- float average_acceleration[3]; /* Moving average of overall acceleration. */
- struct MEdge *edges; /* Used for hair collisions. */
- struct GHash *sew_edge_graph; /* Sewing edges represented using a GHash */
+ float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
+ float average_acceleration[3]; /* Moving average of overall acceleration. */
+ struct MEdge *edges; /* Used for hair collisions. */
+ struct EdgeSet *sew_edge_graph; /* Sewing edges represented using a GHash */
} Cloth;
/**
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index d32ab474229..ca41e51984b 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -140,7 +140,7 @@ void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb,
float (*BKE_curve_nurbs_key_vert_coords_alloc(struct ListBase *lb,
float *key,
int *r_vert_len))[3];
-void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, float *key);
+void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, const float *key);
void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv);
void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 04b85aebb39..f59e796c98c 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -111,7 +111,7 @@ void BKE_defvert_sync_mapped(struct MDeformVert *dvert_dst,
const int *flip_map,
const int flip_map_len,
const bool use_ensure);
-void BKE_defvert_remap(struct MDeformVert *dvert, int *map, const int map_len);
+void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, const int map_len);
void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void BKE_defvert_flip_merged(struct MDeformVert *dvert,
const int *flip_map,
diff --git a/source/blender/blenkernel/BKE_derived_node_tree.hh b/source/blender/blenkernel/BKE_derived_node_tree.hh
index 2ed96f0c60d..083057835a5 100644
--- a/source/blender/blenkernel/BKE_derived_node_tree.hh
+++ b/source/blender/blenkernel/BKE_derived_node_tree.hh
@@ -140,6 +140,9 @@ class DNode : NonCopyable, NonMovable {
const DInputSocket &input(uint index) const;
const DOutputSocket &output(uint index) const;
+ const DInputSocket &input(uint index, StringRef expected_name) const;
+ const DOutputSocket &output(uint index, StringRef expected_name) const;
+
uint id() const;
PointerRNA *rna() const;
@@ -313,12 +316,12 @@ inline const InputSocketRef &DInputSocket::socket_ref() const
inline Span<const DOutputSocket *> DInputSocket::linked_sockets() const
{
- return linked_sockets_.as_span();
+ return linked_sockets_;
}
inline Span<const DGroupInput *> DInputSocket::linked_group_inputs() const
{
- return linked_group_inputs_.as_span();
+ return linked_group_inputs_;
}
inline bool DInputSocket::is_linked() const
@@ -337,7 +340,7 @@ inline const OutputSocketRef &DOutputSocket::socket_ref() const
inline Span<const DInputSocket *> DOutputSocket::linked_sockets() const
{
- return linked_sockets_.as_span();
+ return linked_sockets_;
}
/* --------------------------------------------------------------------
@@ -361,7 +364,7 @@ inline const DParentNode *DGroupInput::parent() const
inline Span<const DInputSocket *> DGroupInput::linked_sockets() const
{
- return linked_sockets_.as_span();
+ return linked_sockets_;
}
inline uint DGroupInput::id() const
@@ -408,6 +411,22 @@ inline const DOutputSocket &DNode::output(uint index) const
return *outputs_[index];
}
+inline const DInputSocket &DNode::input(uint index, StringRef expected_name) const
+{
+ const DInputSocket &socket = *inputs_[index];
+ BLI_assert(socket.name() == expected_name);
+ UNUSED_VARS_NDEBUG(expected_name);
+ return socket;
+}
+
+inline const DOutputSocket &DNode::output(uint index, StringRef expected_name) const
+{
+ const DOutputSocket &socket = *outputs_[index];
+ BLI_assert(socket.name() == expected_name);
+ UNUSED_VARS_NDEBUG(expected_name);
+ return socket;
+}
+
inline uint DNode::id() const
{
return id_;
@@ -453,7 +472,7 @@ inline uint DParentNode::id() const
inline Span<const DNode *> DerivedNodeTree::nodes() const
{
- return nodes_by_id_.as_span();
+ return nodes_by_id_;
}
inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const
@@ -469,28 +488,28 @@ inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodet
return {};
}
else {
- return nodes->as_span();
+ return *nodes;
}
}
inline Span<const DSocket *> DerivedNodeTree::sockets() const
{
- return sockets_by_id_.as_span();
+ return sockets_by_id_;
}
inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const
{
- return input_sockets_.as_span();
+ return input_sockets_;
}
inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const
{
- return output_sockets_.as_span();
+ return output_sockets_;
}
inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const
{
- return group_inputs_.as_span();
+ return group_inputs_;
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 71b6d06b450..13918dd4fb1 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -52,7 +52,7 @@ typedef struct DupliObject {
/* Persistent identifier for a dupli object, for inter-frame matching of
* objects with motion blur, or inter-update matching for syncing. */
- int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
+ int persistent_id[8]; /* MAX_DUPLI_RECUR */
/* Particle this dupli was generated from. */
struct ParticleSystem *particle_system;
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index c3a597e29b9..ddd0cc286ab 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -271,7 +271,7 @@ void testhandles_fcurve(struct FCurve *fcu, eBezTriple_Flag sel_flag, const bool
void sort_time_fcurve(struct FCurve *fcu);
short test_time_fcurve(struct FCurve *fcu);
-void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]);
+void correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* -------- Evaluation -------- */
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index c958afb212e..2392263181d 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -37,7 +37,7 @@ struct Main;
struct Scene;
typedef float (*BKE_Fluid_BresenhamFn)(
- float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
+ float *result, const float *input, int res[3], int *pixel, float *tRay, float correct);
struct Mesh *BKE_fluid_modifier_do(struct FluidModifierData *fmd,
struct Depsgraph *depsgraph,
@@ -56,9 +56,9 @@ bool BKE_fluid_reallocate_fluid(struct FluidDomainSettings *fds, int res[3], int
void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *fds,
int o_res[3],
int n_res[3],
- int o_min[3],
- int n_min[3],
- int o_max[3],
+ const int o_min[3],
+ const int n_min[3],
+ const int o_max[3],
int o_shift[3],
int n_shift[3]);
void BKE_fluid_cache_free_all(struct FluidDomainSettings *fds, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index a823693e126..38322427374 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -47,9 +47,9 @@ enum {
};
typedef struct IDCacheKey {
- /* The session uuid of the ID owning the cached data. */
+ /* The session UUID of the ID owning the cached data. */
unsigned int id_session_uuid;
- /* Value uniquely indentifying the cache whithin its ID.
+ /* Value uniquely identifying the cache within its ID.
* Typically the offset of its member in the data-block struct, but can be anything. */
size_t offset_in_ID;
/* Actual address of the cached data to save and restore. */
@@ -59,7 +59,7 @@ typedef struct IDCacheKey {
uint BKE_idtype_cache_key_hash(const void *key_v);
bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v);
-/* ********** Prototypes for IDTypeInfo callbacks. ********** */
+/* ********** Prototypes for #IDTypeInfo callbacks. ********** */
typedef void (*IDTypeInitDataFunction)(struct ID *id);
@@ -76,9 +76,15 @@ typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const
typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
+typedef enum eIDTypeInfoCacheCallbackFlags {
+ /** Indicates to the callback that that cache may be stored in the .blend file, so its pointer
+ * should not be cleared at read-time. */
+ IDTYPE_CACHE_CB_FLAGS_PERSISTENT = 1 << 0,
+} eIDTypeInfoCacheCallbackFlags;
typedef void (*IDTypeForeachCacheFunctionCallback)(struct ID *id,
const struct IDCacheKey *cache_key,
void **cache_p,
+ uint flags,
void *user_data);
typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
@@ -229,6 +235,14 @@ short BKE_idtype_idcode_from_index(const int index);
short BKE_idtype_idcode_iter_step(int *index);
+/* Some helpers/wrappers around callbacks defined in #IDTypeInfo, dealing e.g. with embedded IDs.
+ * XXX Ideally those would rather belong to #BKE_lib_id, but using callback function pointers makes
+ * this hard to do properly if we want to avoid headers includes in headers. */
+
+void BKE_idtype_id_foreach_cache(struct ID *id,
+ IDTypeForeachCacheFunctionCallback function_callback,
+ void *user_data);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index bc72afdd08d..76bae6fa909 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -229,7 +229,6 @@ bool BKE_id_copy(struct Main *bmain, const struct ID *id, struct ID **newid);
bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag);
struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
struct ID *id,
- const bool is_owner_id_liboverride,
const uint duplicate_flags);
void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 411df66fe36..8f6603e28ae 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -51,9 +51,6 @@ struct Main;
struct PointerRNA;
struct PropertyRNA;
-void BKE_lib_override_library_enable(const bool do_enable);
-bool BKE_lib_override_library_is_enabled(void);
-
struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_id,
struct ID *reference_id);
void BKE_lib_override_library_copy(struct ID *dst_id,
@@ -66,6 +63,10 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
const bool do_tagged_remap);
bool BKE_lib_override_library_create_from_tag(struct Main *bmain);
+void BKE_lib_override_library_dependencies_tag(struct Main *bmain,
+ struct ID *id_root,
+ const uint tag,
+ const bool do_create_main_relashionships);
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
struct IDOverrideLibrary *override, const char *rna_path);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 7d989bfcf69..b2510be656e 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -513,13 +513,13 @@ void BKE_mesh_loops_to_mface_corners(struct CustomData *fdata,
void BKE_mesh_loops_to_tessdata(struct CustomData *fdata,
struct CustomData *ldata,
struct MFace *mface,
- int *polyindices,
+ const int *polyindices,
unsigned int (*loopindices)[4],
const int num_faces);
void BKE_mesh_tangent_loops_to_tessdata(struct CustomData *fdata,
struct CustomData *ldata,
struct MFace *mface,
- int *polyindices,
+ const int *polyindices,
unsigned int (*loopindices)[4],
const int num_faces,
const char *layer_name);
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index 9864cc4d28d..5ad5238bbb5 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -199,7 +199,7 @@ void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_add(MeshIslandStore *islands,
const int item_num,
- int *item_indices,
+ const int *item_indices,
const int num_island_items,
int *island_item_indices,
const int num_innercut_items,
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index bdcbe2129c8..acd4c75befd 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -101,6 +101,30 @@ typedef struct bNodeSocketTemplate {
char identifier[64]; /* generated from name */
} bNodeSocketTemplate;
+/* Use `void *` for callbacks that require C++. This is rather ugly, but works well for now. This
+ * would not be necessary if we would use bNodeSocketType and bNodeType only in C++ code.
+ * However, achieving this requires quite a few changes currently. */
+#ifdef __cplusplus
+namespace blender {
+namespace bke {
+class SocketMFNetworkBuilder;
+class NodeMFNetworkBuilder;
+} // namespace bke
+namespace fn {
+class MFDataType;
+}
+} // namespace blender
+
+using NodeExpandInMFNetworkFunction = void (*)(blender::bke::NodeMFNetworkBuilder &builder);
+using SocketGetMFDataTypeFunction = blender::fn::MFDataType (*)();
+using SocketExpandInMFNetworkFunction = void (*)(blender::bke::SocketMFNetworkBuilder &builder);
+
+#else
+typedef void *NodeExpandInMFNetworkFunction;
+typedef void *SocketGetMFDataTypeFunction;
+typedef void *SocketExpandInMFNetworkFunction;
+#endif
+
/**
* \brief Defines a socket type.
*
@@ -153,6 +177,11 @@ typedef struct bNodeSocketType {
/* Callback to free the socket type. */
void (*free_self)(struct bNodeSocketType *stype);
+
+ /* Returns the multi-function data type of this socket type. */
+ SocketGetMFDataTypeFunction get_mf_data_type;
+ /* Expands the socket into a multi-function node that outputs the socket value. */
+ SocketExpandInMFNetworkFunction expand_in_mf_network;
} bNodeSocketType;
typedef void *(*NodeInitExecFunction)(struct bNodeExecContext *context,
@@ -267,6 +296,9 @@ typedef struct bNodeType {
/* gpu */
NodeGPUExecFunction gpufunc;
+ /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
+ NodeExpandInMFNetworkFunction expand_in_mf_network;
+
/* RNA integration */
ExtensionRNA rna_ext;
} bNodeType;
diff --git a/source/blender/blenkernel/BKE_node_tree_multi_function.hh b/source/blender/blenkernel/BKE_node_tree_multi_function.hh
new file mode 100644
index 00000000000..dcbd551591f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_tree_multi_function.hh
@@ -0,0 +1,374 @@
+/*
+ * 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.
+ */
+
+#ifndef __BKE_NODE_TREE_FUNCTION_HH__
+#define __BKE_NODE_TREE_FUNCTION_HH__
+
+/** \file
+ * \ingroup bke
+ *
+ * This file allows you to generate a multi-function network from a user-generated node tree.
+ */
+
+#include "FN_multi_function_builder.hh"
+#include "FN_multi_function_network.hh"
+
+#include "BKE_derived_node_tree.hh"
+
+#include "BLI_resource_collector.hh"
+
+namespace blender {
+namespace bke {
+
+/* Maybe this should be moved to BKE_node.h. */
+inline bool is_multi_function_data_socket(const bNodeSocket *bsocket)
+{
+ if (bsocket->typeinfo->get_mf_data_type != nullptr) {
+ BLI_assert(bsocket->typeinfo->expand_in_mf_network != nullptr);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * A MFNetworkTreeMap maps various components of a bke::DerivedNodeTree to components of a
+ * fn::MFNetwork. This is necessary for further processing of a multi-function network that has
+ * been generated from a node tree.
+ */
+class MFNetworkTreeMap {
+ private:
+ /**
+ * Store by id instead of using a hash table to avoid unnecessary hash table lookups.
+ *
+ * Input sockets in a node tree can have multiple corresponding sockets in the generated
+ * MFNetwork. This is because nodes are allowed to expand into multiple multi-function nodes.
+ */
+ const DerivedNodeTree &tree_;
+ fn::MFNetwork &network_;
+ Array<Vector<fn::MFSocket *, 1>> sockets_by_dsocket_id_;
+ Array<fn::MFOutputSocket *> socket_by_group_input_id_;
+
+ public:
+ MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network)
+ : tree_(tree),
+ network_(network),
+ sockets_by_dsocket_id_(tree.sockets().size()),
+ socket_by_group_input_id_(tree.group_inputs().size(), nullptr)
+ {
+ }
+
+ const DerivedNodeTree &tree() const
+ {
+ return tree_;
+ }
+
+ const fn::MFNetwork &network() const
+ {
+ return network_;
+ }
+
+ fn::MFNetwork &network()
+ {
+ return network_;
+ }
+
+ void add(const DSocket &dsocket, fn::MFSocket &socket)
+ {
+ BLI_assert(dsocket.is_input() == socket.is_input());
+ sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ }
+
+ void add(const DInputSocket &dsocket, fn::MFInputSocket &socket)
+ {
+ sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ }
+
+ void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket)
+ {
+ sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ }
+
+ void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
+ {
+ assert_same_size(dsockets, sockets);
+ for (uint i : dsockets.index_range()) {
+ this->add(*dsockets[i], *sockets[i]);
+ }
+ }
+
+ void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
+ {
+ assert_same_size(dsockets, sockets);
+ for (uint i : dsockets.index_range()) {
+ this->add(*dsockets[i], *sockets[i]);
+ }
+ }
+
+ void add(const DGroupInput &group_input, fn::MFOutputSocket &socket)
+ {
+ BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr);
+ socket_by_group_input_id_[group_input.id()] = &socket;
+ }
+
+ void add_try_match(const DNode &dnode, fn::MFNode &node)
+ {
+ this->add_try_match(dnode.inputs(), node.inputs());
+ this->add_try_match(dnode.outputs(), node.outputs());
+ }
+
+ void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets)
+ {
+ uint used_sockets = 0;
+ for (const DSocket *dsocket : dsockets) {
+ if (!dsocket->is_available()) {
+ continue;
+ }
+ if (!is_multi_function_data_socket(dsocket->bsocket())) {
+ continue;
+ }
+ fn::MFSocket *socket = sockets[used_sockets];
+ this->add(*dsocket, *socket);
+ used_sockets++;
+ }
+ }
+
+ fn::MFOutputSocket &lookup(const DGroupInput &group_input)
+ {
+ fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()];
+ BLI_assert(socket != nullptr);
+ return *socket;
+ }
+
+ fn::MFOutputSocket &lookup(const DOutputSocket &dsocket)
+ {
+ auto &sockets = sockets_by_dsocket_id_[dsocket.id()];
+ BLI_assert(sockets.size() == 1);
+ return sockets[0]->as_output();
+ }
+
+ Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket)
+ {
+ return sockets_by_dsocket_id_[dsocket.id()].as_span().cast<fn::MFInputSocket *>();
+ }
+
+ fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket)
+ {
+ Span<fn::MFInputSocket *> sockets = this->lookup(dsocket);
+ BLI_assert(sockets.size() == 1);
+ fn::MFInputSocket &socket = *sockets[0];
+ BLI_assert(socket.node().is_dummy());
+ return socket;
+ }
+
+ fn::MFOutputSocket &lookup_dummy(const DOutputSocket &dsocket)
+ {
+ fn::MFOutputSocket &socket = this->lookup(dsocket);
+ BLI_assert(socket.node().is_dummy());
+ return socket;
+ }
+
+ bool is_mapped(const DSocket &dsocket) const
+ {
+ return sockets_by_dsocket_id_[dsocket.id()].size() >= 1;
+ }
+};
+
+/**
+ * This data is necessary throughout the generation of a MFNetwork from a node tree.
+ */
+struct CommonMFNetworkBuilderData {
+ ResourceCollector &resources;
+ fn::MFNetwork &network;
+ MFNetworkTreeMap &network_map;
+ const DerivedNodeTree &tree;
+};
+
+class MFNetworkBuilderBase {
+ protected:
+ CommonMFNetworkBuilderData &common_;
+
+ public:
+ MFNetworkBuilderBase(CommonMFNetworkBuilderData &common) : common_(common)
+ {
+ }
+
+ /**
+ * Returns the network that is currently being built.
+ */
+ fn::MFNetwork &network()
+ {
+ return common_.network;
+ }
+
+ /**
+ * Returns the map between the node tree and the multi-function network that is being built.
+ */
+ MFNetworkTreeMap &network_map()
+ {
+ return common_.network_map;
+ }
+
+ /**
+ * Returns a resource collector that will only be destructed after the multi-function network is
+ * destructed.
+ */
+ ResourceCollector &resources()
+ {
+ return common_.resources;
+ }
+
+ /**
+ * Constructs a new function that will live at least as long as the MFNetwork.
+ */
+ template<typename T, typename... Args> T &construct_fn(Args &&... args)
+ {
+ BLI_STATIC_ASSERT((std::is_base_of_v<fn::MultiFunction, T>), "");
+ void *buffer = common_.resources.linear_allocator().allocate(sizeof(T), alignof(T));
+ T *fn = new (buffer) T(std::forward<Args>(args)...);
+ common_.resources.add(destruct_ptr<T>(fn), fn->name().data());
+ return *fn;
+ }
+};
+
+/**
+ * This class is used by socket implementations to define how an unlinked input socket is handled
+ * in a multi-function network.
+ */
+class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
+ private:
+ const DSocket *dsocket_ = nullptr;
+ const DGroupInput *group_input_ = nullptr;
+ bNodeSocket *bsocket_;
+ fn::MFOutputSocket *built_socket_ = nullptr;
+
+ public:
+ SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket)
+ : MFNetworkBuilderBase(common), dsocket_(&dsocket), bsocket_(dsocket.bsocket())
+ {
+ }
+
+ SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input)
+ : MFNetworkBuilderBase(common), group_input_(&group_input), bsocket_(group_input.bsocket())
+ {
+ }
+
+ /**
+ * Returns the socket that is currently being built.
+ */
+ bNodeSocket &bsocket()
+ {
+ return *bsocket_;
+ }
+
+ /**
+ * Utility method that returns bsocket->default_value for the current socket.
+ */
+ template<typename T> T *socket_default_value()
+ {
+ return (T *)bsocket_->default_value;
+ }
+
+ /**
+ * Builds a function node for that socket that outputs the given constant value.
+ */
+ template<typename T> void set_constant_value(T value)
+ {
+ const fn::MultiFunction &fn = this->construct_fn<fn::CustomMF_Constant<T>>(std::move(value));
+ this->set_generator_fn(fn);
+ }
+
+ /**
+ * Uses the first output of the given multi-function as value of the socket.
+ */
+ void set_generator_fn(const fn::MultiFunction &fn)
+ {
+ fn::MFFunctionNode &node = common_.network.add_function(fn);
+ this->set_socket(node.output(0));
+ }
+
+ /**
+ * Define a multi-function socket that outputs the value of the bsocket.
+ */
+ void set_socket(fn::MFOutputSocket &socket)
+ {
+ built_socket_ = &socket;
+ }
+
+ fn::MFOutputSocket *built_socket()
+ {
+ return built_socket_;
+ }
+};
+
+/**
+ * This class is used by node implementations to define how a user-level node expands into
+ * multi-function nodes internally.
+ */
+class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
+ private:
+ const DNode &node_;
+
+ public:
+ NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &node)
+ : MFNetworkBuilderBase(common), node_(node)
+ {
+ }
+
+ /**
+ * Tells the builder to build a function that corresponds to the node that is being built. It
+ * will try to match up sockets.
+ */
+ template<typename T, typename... Args> void construct_and_set_matching_fn(Args &&... args)
+ {
+ const fn::MultiFunction &function = this->construct_fn<T>(std::forward<Args>(args)...);
+ this->set_matching_fn(function);
+ }
+
+ /**
+ * Tells the builder that the given function corresponds to the node that is being built. It will
+ * try to match up sockets. For that it skips unavailable and non-data sockets.
+ */
+ void set_matching_fn(const fn::MultiFunction &function)
+ {
+ fn::MFFunctionNode &node = common_.network.add_function(function);
+ common_.network_map.add_try_match(node_, node);
+ }
+
+ /**
+ * Returns the node that is currently being built.
+ */
+ bNode &bnode()
+ {
+ return *node_.node_ref().bnode();
+ }
+
+ /**
+ * Returns the node that is currently being built.
+ */
+ const DNode &dnode() const
+ {
+ return node_;
+ }
+};
+
+MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
+ const DerivedNodeTree &tree,
+ ResourceCollector &resources);
+
+} // namespace bke
+} // namespace blender
+
+#endif /* __BKE_NODE_TREE_FUNCTION_HH__ */
diff --git a/source/blender/blenkernel/BKE_node_tree_ref.hh b/source/blender/blenkernel/BKE_node_tree_ref.hh
index e25849cb569..b1e8904d718 100644
--- a/source/blender/blenkernel/BKE_node_tree_ref.hh
+++ b/source/blender/blenkernel/BKE_node_tree_ref.hh
@@ -197,12 +197,12 @@ class NodeTreeRef : NonCopyable, NonMovable {
inline Span<const SocketRef *> SocketRef::linked_sockets() const
{
- return linked_sockets_.as_span();
+ return linked_sockets_;
}
inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const
{
- return directly_linked_sockets_.as_span();
+ return directly_linked_sockets_;
}
inline bool SocketRef::is_linked() const
@@ -326,12 +326,12 @@ inline const NodeTreeRef &NodeRef::tree() const
inline Span<const InputSocketRef *> NodeRef::inputs() const
{
- return inputs_.as_span();
+ return inputs_;
}
inline Span<const OutputSocketRef *> NodeRef::outputs() const
{
- return outputs_.as_span();
+ return outputs_;
}
inline const InputSocketRef &NodeRef::input(uint index) const
@@ -400,7 +400,7 @@ inline bool NodeRef::is_group_output_node() const
inline Span<const NodeRef *> NodeTreeRef::nodes() const
{
- return nodes_by_id_.as_span();
+ return nodes_by_id_;
}
inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(StringRefNull idname) const
@@ -416,23 +416,23 @@ inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(const bNodeType *nodetyp
return {};
}
else {
- return nodes->as_span();
+ return *nodes;
}
}
inline Span<const SocketRef *> NodeTreeRef::sockets() const
{
- return sockets_by_id_.as_span();
+ return sockets_by_id_;
}
inline Span<const InputSocketRef *> NodeTreeRef::input_sockets() const
{
- return input_sockets_.as_span();
+ return input_sockets_;
}
inline Span<const OutputSocketRef *> NodeTreeRef::output_sockets() const
{
- return output_sockets_.as_span();
+ return output_sockets_;
}
inline bNodeTree *NodeTreeRef::btree() const
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index d830a35dda0..f2a022c84a3 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -139,7 +139,7 @@ bool BKE_object_obdata_is_libdata(const struct Object *ob);
struct Object *BKE_object_duplicate(struct Main *bmain,
struct Object *ob,
- const uint dupflag,
+ uint dupflag,
const uint duplicate_options);
void BKE_object_obdata_size_init(struct Object *ob, const float scale);
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index 410cb862aa7..e4813aa2288 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -33,7 +33,7 @@ struct Object;
struct bDeformGroup;
/* General vgroup operations */
-void BKE_object_defgroup_remap_update_users(struct Object *ob, int *map);
+void BKE_object_defgroup_remap_update_users(struct Object *ob, const int *map);
bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index a22cb9ef126..7de588450d6 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -365,6 +365,10 @@ struct ModifierData *object_add_particle_system(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
const char *name);
+struct ModifierData *object_copy_particle_system(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ const struct ParticleSystem *psys_orig);
void object_remove_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob);
struct ParticleSettings *BKE_particlesettings_add(struct Main *bmain, const char *name);
struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain,
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 87875314aec..da9280148fd 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -224,7 +224,7 @@ void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]);
unsigned int **BKE_pbvh_grid_hidden(const PBVH *pbvh);
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
- int *grid_indices,
+ const int *grid_indices,
int totgrid,
int gridsize);
@@ -264,6 +264,7 @@ void BKE_pbvh_node_mark_redraw(PBVHNode *node);
void BKE_pbvh_node_mark_normals_update(PBVHNode *node);
void BKE_pbvh_node_mark_topology_update(PBVHNode *node);
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
+bool BKE_pbvh_node_fully_hidden_get(PBVHNode *node);
void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked);
bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index b0973ed458c..a9abe2d0f6d 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -147,7 +147,7 @@ typedef struct PTCacheID {
/* copies point data to cache data */
int (*write_point)(int index, void *calldata, void **data, int cfra);
/* copies cache cata to point data */
- void (*read_point)(int index, void *calldata, void **data, float cfra, float *old_data);
+ void (*read_point)(int index, void *calldata, void **data, float cfra, const float *old_data);
/* interpolated between previously read point data and cache data */
void (*interpolate_point)(int index,
void *calldata,
@@ -155,7 +155,7 @@ typedef struct PTCacheID {
float cfra,
float cfra1,
float cfra2,
- float *old_data);
+ const float *old_data);
/* copies point data to cache data */
int (*write_stream)(PTCacheFile *pf, void *calldata);
@@ -296,7 +296,9 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
struct Object *ob,
struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
-void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, struct ParticleSimulationState *state);
+void BKE_ptcache_id_from_sim_particles(PTCacheID *pid,
+ struct ParticleSimulationState *state_orig,
+ struct ParticleSimulationState *state_cow);
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
void BKE_ptcache_ids_from_object(struct ListBase *lb,
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index a50f9b24c61..107a27b00ab 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -285,6 +285,11 @@ void BKE_sequence_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
const bool lock_range);
+void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
+ struct Scene *scene,
+ struct Sequence *seq,
+ bool *r_was_reloaded,
+ bool *r_can_produce_frames);
int BKE_sequencer_evaluate_frame(struct Scene *scene, int cfra);
int BKE_sequencer_get_shown_sequences(struct ListBase *seqbasep,
int cfra,
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 78e91d3ad2f..5808f223f32 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -313,6 +313,22 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index);
+typedef enum SubdivCCGAdjacencyType {
+ SUBDIV_CCG_ADJACENT_NONE,
+ SUBDIV_CCG_ADJACENT_VERTEX,
+ SUBDIV_CCG_ADJACENT_EDGE,
+} SubdivCCGAdjacencyType;
+
+/* Returns if a grid coordinates is adjacent to a coarse mesh edge, vertex or nothing. If it is
+ * adjacent to an edge, r_v1 and r_v2 will be set to the two vertices of that edge. If it is
+ * adjacent to a vertex, r_v1 and r_v2 will be the index of that vertex. */
+SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const MLoop *mloop,
+ const MPoly *mpoly,
+ int *r_v1,
+ int *r_v2);
+
/* Get array which is indexed by face index and contains index of a first grid of the face.
*
* The "ensure" version allocates the mapping if it's not know yet and stores it in the subdiv_ccg
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index b9054d29752..b70476b8590 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../bmesh
../depsgraph
../draw
+ ../functions
../gpencil_modifiers
../gpu
../ikplugin
@@ -187,6 +188,7 @@ set(SRC
intern/multires_unsubdivide.c
intern/nla.c
intern/node.c
+ intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/object.c
intern/object_deform.c
@@ -356,6 +358,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_tree_multi_function.hh
BKE_node_tree_ref.hh
BKE_object.h
BKE_object_deform.h
@@ -424,6 +427,7 @@ set(LIB
bf_bmesh
bf_depsgraph
bf_draw
+ bf_functions
bf_gpencil_modifiers
bf_gpu
bf_ikplugin
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c
index 58d5f2e0495..bc63d8b97f7 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_util.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c
@@ -304,7 +304,7 @@ void ccgSubSurf__dumpCoords(CCGSubSurf *ss)
}
for (x = 0; x < gridSize; x++) {
float *co = FACE_getIECo(f, subdivLevels, S, x);
- printf("face index=%d. cornder=%d, ie_index=%d, coord=(%f, %f, %f)\n",
+ printf("face index=%d. corner=%d, ie_index=%d, coord=(%f, %f, %f)\n",
index,
S,
x,
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 3e2c69fbcea..61181278c60 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -375,17 +375,19 @@ bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
return true;
}
-void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
+static void animdata_copy_id_action(Main *bmain,
+ ID *id,
+ const bool set_newid,
+ const bool do_linked_id)
{
- const bool is_id_liboverride = ID_IS_OVERRIDE_LIBRARY(id);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
- if (adt->action && (!is_id_liboverride || !ID_IS_LINKED(adt->action))) {
+ if (adt->action && (do_linked_id || !ID_IS_LINKED(adt->action))) {
id_us_min((ID *)adt->action);
adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
BKE_action_copy(bmain, adt->action);
}
- if (adt->tmpact && (!is_id_liboverride || !ID_IS_LINKED(adt->tmpact))) {
+ if (adt->tmpact && (do_linked_id || !ID_IS_LINKED(adt->tmpact))) {
id_us_min((ID *)adt->tmpact);
adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
BKE_action_copy(bmain, adt->tmpact);
@@ -393,12 +395,27 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
}
bNodeTree *ntree = ntreeFromID(id);
if (ntree) {
- BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
+ animdata_copy_id_action(bmain, &ntree->id, set_newid, do_linked_id);
}
/* Note that collections are not animatable currently, so no need to handle scenes' master
* collection here. */
}
+void BKE_animdata_copy_id_action(Main *bmain, ID *id)
+{
+ const bool is_id_liboverride = ID_IS_OVERRIDE_LIBRARY(id);
+ animdata_copy_id_action(bmain, id, false, !is_id_liboverride);
+}
+
+void BKE_animdata_duplicate_id_action(struct Main *bmain,
+ struct ID *id,
+ const eDupli_ID_Flags duplicate_flags)
+{
+ if (duplicate_flags & USER_DUP_ACT) {
+ animdata_copy_id_action(bmain, id, true, (duplicate_flags & USER_DUP_LINKED_ID) != 0);
+ }
+}
+
/* Merge copies of the data from the src AnimData into the destination AnimData */
void BKE_animdata_merge_copy(
Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 58337bcf488..2cc715464ad 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -56,7 +56,7 @@
# ifdef WITH_BINRELOC
# include "binreloc.h"
# endif
-/* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
+/* #mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
# include <unistd.h>
#endif /* WIN32 */
@@ -120,7 +120,7 @@ static char *blender_version_decimal(const int ver)
}
/**
- * Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
+ * Concatenates path_base, (optional) path_sep and (optional) folder_name into \a targetpath,
* returning true if result points to a directory.
*/
static bool test_path(char *targetpath,
@@ -138,14 +138,14 @@ static bool test_path(char *targetpath,
BLI_strncpy(tmppath, path_base, sizeof(tmppath));
}
- /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
+ /* Rare cases folder_name is omitted (when looking for `~/.config/blender/2.xx` dir only). */
if (folder_name) {
BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
}
else {
BLI_strncpy(targetpath, tmppath, targetpath_len);
}
- /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
+ /* FIXME: why is "//" on front of \a tmppath expanded to "/" (by BLI_join_dirfile)
* if folder_name is specified but not otherwise? */
if (BLI_is_dir(targetpath)) {
@@ -190,7 +190,7 @@ static bool test_env_path(char *path, const char *envvar)
/**
* Constructs in \a targetpath the name of a directory relative to a version-specific
- * subdirectory in the parent directory of the Blender executable.
+ * sub-directory in the parent directory of the Blender executable.
*
* \param targetpath: String to return path
* \param folder_name: Optional folder name within version-specific directory
@@ -307,7 +307,7 @@ static bool get_path_environment_notest(char *targetpath,
* \param targetpath: String to return path
* \param folder_name: default name of folder within user area
* \param subfolder_name: optional name of subfolder within folder
- * \param ver: Blender version, used to construct a subdirectory name
+ * \param ver: Blender version, used to construct a sub-directory name
* \return true if it was able to construct such a path.
*/
static bool get_path_user(char *targetpath,
@@ -350,8 +350,8 @@ static bool get_path_user(char *targetpath,
*
* \param targetpath: String to return path
* \param folder_name: default name of folder within installation area
- * \param subfolder_name: optional name of subfolder within folder
- * \param ver: Blender version, used to construct a subdirectory name
+ * \param subfolder_name: optional name of sub-folder within folder
+ * \param ver: Blender version, used to construct a sub-directory name
* \return true if it was able to construct such a path.
*/
static bool get_path_system(char *targetpath,
@@ -635,7 +635,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
* adds the correct extension (.com .exe etc) from
* $PATHEXT if necessary. Also on Windows it translates
* the name to its 8.3 version to prevent problems with
- * spaces and stuff. Final result is returned in fullname.
+ * spaces and stuff. Final result is returned in \a fullname.
*
* \param fullname: The full path and full name of the executable
* (must be FILE_MAX minimum)
@@ -975,7 +975,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
/**
* Sets btempdir_base to userdir if specified and is a valid directory, otherwise
* chooses a suitable OS-specific temporary directory.
- * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base.
+ * Sets btempdir_session to a #mkdtemp generated sub-dir of btempdir_base.
*
* \note On Window userdir will be set to the temporary directory!
*/
@@ -1019,7 +1019,11 @@ void BKE_tempdir_session_purge(void)
}
/* Gets a good default directory for fonts */
-bool BKE_appdir_font_folder_default(char *dir)
+
+bool BKE_appdir_font_folder_default(
+ /* This parameter can only be `const` on non-windows platforms.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ char *dir)
{
bool success = false;
#ifdef WIN32
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 6b25095a87a..f45cd5b679a 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -30,7 +30,6 @@
#include "DNA_scene_types.h"
#include "BLI_edgehash.h"
-#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -587,7 +586,7 @@ void cloth_free_modifier(ClothModifierData *clmd)
}
if (cloth->sew_edge_graph) {
- BLI_ghash_free(cloth->sew_edge_graph, MEM_freeN, NULL);
+ BLI_edgeset_free(cloth->sew_edge_graph);
cloth->sew_edge_graph = NULL;
}
@@ -669,7 +668,7 @@ void cloth_free_modifier_extern(ClothModifierData *clmd)
}
if (cloth->sew_edge_graph) {
- BLI_ghash_free(cloth->sew_edge_graph, MEM_freeN, NULL);
+ BLI_edgeset_free(cloth->sew_edge_graph);
cloth->sew_edge_graph = NULL;
}
@@ -1038,7 +1037,7 @@ static void cloth_free_errorsprings(Cloth *cloth,
}
BLI_INLINE void cloth_bend_poly_dir(
- ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3])
+ ClothVertex *verts, int i, int j, const int *inds, int len, float r_dir[3])
{
float cent[3] = {0};
float fact = 1.0f / len;
@@ -1557,9 +1556,8 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
*r_tar_v_idx = vert_idx;
return true;
}
-
- return false;
-
+
+ return false;
}
static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
@@ -1693,8 +1691,7 @@ static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) {
/* cloth->sew_edge_graph should not exist before this */
BLI_assert(cloth->sew_edge_graph == NULL);
- cloth->sew_edge_graph = BLI_ghash_new(
- BLI_ghashutil_inthash_v2_p, BLI_ghashutil_inthash_v2_cmp, "cloth_sewing_edges_graph");
+ cloth->sew_edge_graph = BLI_edgeset_new("cloth_sewing_edges_graph");
}
/* Structural springs. */
@@ -1709,18 +1706,7 @@ static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
spring->lin_stiffness = 1.0f;
spring->type = CLOTH_SPRING_TYPE_SEWING;
- /* set indices of verts of the sewing edge symmetrically in sew_edge_graph */
- unsigned int *vertex_index_pair = MEM_mallocN(sizeof(unsigned int) * 2,
- "sewing_edge_index_pair_01");
- if (medge[i].v1 < medge[i].v2) {
- vertex_index_pair[0] = medge[i].v1;
- vertex_index_pair[1] = medge[i].v2;
- }
- else {
- vertex_index_pair[0] = medge[i].v2;
- vertex_index_pair[1] = medge[i].v1;
- }
- BLI_ghash_insert(cloth->sew_edge_graph, vertex_index_pair, NULL);
+ BLI_edgeset_insert(cloth->sew_edge_graph, medge[i].v1, medge[i].v2);
}
else {
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 080d61f1500..7e22048379b 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -333,7 +333,6 @@ static Collection *collection_duplicate_recursive(Main *bmain,
Collection *collection_new;
bool do_full_process = false;
const bool is_collection_master = (collection_old->flag & COLLECTION_IS_MASTER) != 0;
- const bool is_collection_liboverride = ID_IS_OVERRIDE_LIBRARY(collection_old);
const bool do_objects = (duplicate_flags & USER_DUP_OBJECT) != 0;
@@ -346,7 +345,12 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
else if (collection_old->id.newid == NULL) {
collection_new = (Collection *)BKE_id_copy_for_duplicate(
- bmain, (ID *)collection_old, is_collection_liboverride, duplicate_flags);
+ bmain, (ID *)collection_old, duplicate_flags);
+
+ if (collection_new == collection_old) {
+ return collection_new;
+ }
+
do_full_process = true;
}
else {
@@ -382,17 +386,15 @@ static Collection *collection_duplicate_recursive(Main *bmain,
Object *ob_old = cob->ob;
Object *ob_new = (Object *)ob_old->id.newid;
- /* If collection is an override, we do not want to duplicate any linked data-block, as that
- * would generate a purely local data. */
- if (is_collection_liboverride && ID_IS_LINKED(ob_old)) {
- continue;
- }
-
if (ob_new == NULL) {
ob_new = BKE_object_duplicate(
bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS);
}
+ if (ob_new == ob_old) {
+ continue;
+ }
+
collection_object_add(bmain, collection_new, ob_new, 0, true);
collection_object_remove(bmain, collection_new, ob_old, false);
}
@@ -403,13 +405,11 @@ static Collection *collection_duplicate_recursive(Main *bmain,
LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection_old->children) {
Collection *child_collection_old = child->collection;
- if (is_collection_liboverride && ID_IS_LINKED(child_collection_old)) {
- continue;
- }
-
- collection_duplicate_recursive(
+ Collection *child_collection_new = collection_duplicate_recursive(
bmain, collection_new, child_collection_old, duplicate_flags, duplicate_options);
- collection_child_remove(collection_new, child_collection_old);
+ if (child_collection_new != child_collection_old) {
+ collection_child_remove(collection_new, child_collection_old);
+ }
}
return collection_new;
@@ -434,6 +434,11 @@ Collection *BKE_collection_duplicate(Main *bmain,
if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
+ /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
+ * all expected linked data. */
+ if (ID_IS_LINKED(collection)) {
+ duplicate_flags |= USER_DUP_LINKED_ID;
+ }
}
Collection *collection_new = collection_duplicate_recursive(
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index daf1602319f..31d49dd4508 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -32,7 +32,7 @@
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
+#include "BLI_edgehash.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -1153,17 +1153,7 @@ static bool cloth_bvh_selfcollision_is_active(const Cloth *cloth,
}
if (sewing_active) {
- unsigned int vertex_index_pair[2];
- /* The indices pair are ordered, thus must ensure the same here as well */
- if (tri_a->tri[i] < tri_b->tri[j]) {
- vertex_index_pair[0] = tri_a->tri[i];
- vertex_index_pair[1] = tri_b->tri[j];
- }
- else {
- vertex_index_pair[0] = tri_b->tri[j];
- vertex_index_pair[1] = tri_a->tri[i];
- }
- if (BLI_ghash_haskey(cloth->sew_edge_graph, vertex_index_pair)) {
+ if (BLI_edgeset_haskey(cloth->sew_edge_graph, tri_a->tri[i], tri_b->tri[j])) {
return false;
}
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index c894534c504..e9e44ac05e5 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1157,7 +1157,7 @@ void BKE_nurb_knot_calc_v(Nurb *nu)
}
static void basisNurb(
- float t, short order, int pnts, float *knots, float *basis, int *start, int *end)
+ float t, short order, int pnts, const float *knots, float *basis, int *start, int *end)
{
float d, e;
int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2;
@@ -3560,8 +3560,13 @@ static void free_arrays(void *buffer)
}
/* computes in which direction to change h[i] to satisfy conditions better */
-static float bezier_relax_direction(
- float *a, float *b, float *c, float *d, float *h, int i, int count)
+static float bezier_relax_direction(const float *a,
+ const float *b,
+ const float *c,
+ const float *d,
+ const float *h,
+ int i,
+ int count)
{
/* current deviation between sides of the equation */
float state = a[i] * h[(i + count - 1) % count] + b[i] * h[i] + c[i] * h[(i + 1) % count] - d[i];
@@ -3577,8 +3582,15 @@ static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, f
d[i] = value;
}
-static void bezier_restore_equation(
- float *a, float *b, float *c, float *d, float *a0, float *b0, float *c0, float *d0, int i)
+static void bezier_restore_equation(float *a,
+ float *b,
+ float *c,
+ float *d,
+ const float *a0,
+ const float *b0,
+ const float *c0,
+ const float *d0,
+ int i)
{
a[i] = a0[i];
b[i] = b0[i];
@@ -3586,8 +3598,14 @@ static void bezier_restore_equation(
d[i] = d0[i];
}
-static bool tridiagonal_solve_with_limits(
- float *a, float *b, float *c, float *d, float *h, float *hmin, float *hmax, int solve_count)
+static bool tridiagonal_solve_with_limits(float *a,
+ float *b,
+ float *c,
+ float *d,
+ float *h,
+ const float *hmin,
+ const float *hmax,
+ int solve_count)
{
float *a0, *b0, *c0, *d0;
float **arrays[] = {&a0, &b0, &c0, &d0, NULL};
@@ -3726,7 +3744,7 @@ static bool tridiagonal_solve_with_limits(
/* clang-format on */
static void bezier_eq_continuous(
- float *a, float *b, float *c, float *d, float *dy, float *l, int i)
+ float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
{
a[i] = l[i] * l[i];
b[i] = 2.0f * (l[i] + 1);
@@ -3735,7 +3753,7 @@ static void bezier_eq_continuous(
}
static void bezier_eq_noaccel_right(
- float *a, float *b, float *c, float *d, float *dy, float *l, int i)
+ float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
{
a[i] = 0.0f;
b[i] = 2.0f;
@@ -3744,7 +3762,7 @@ static void bezier_eq_noaccel_right(
}
static void bezier_eq_noaccel_left(
- float *a, float *b, float *c, float *d, float *dy, float *l, int i)
+ float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
{
a[i] = l[i] * l[i];
b[i] = 2.0f * l[i];
@@ -4823,7 +4841,7 @@ float (*BKE_curve_nurbs_key_vert_coords_alloc(ListBase *lb, float *key, int *r_v
return cos;
}
-void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, float *key)
+void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, const float *key)
{
Nurb *nu;
int i;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 2be61239ac6..c11fa69db76 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -300,7 +300,7 @@ static void layerInterp_mdeformvert(const void **sources,
/* now we know how many unique deform weights there are, so realloc */
if (dvert->dw && (dvert->totweight == totweight)) {
- /* pass (fastpath if we don't need to realloc) */
+ /* pass (fast-path if we don't need to realloc). */
}
else {
if (dvert->dw) {
@@ -1772,7 +1772,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 42: CD_SCULPT_FACE_SETS */
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 43: CD_LOCATION */
- {sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "vec3f", 1, "Location", NULL, NULL, NULL, NULL, NULL},
/* 44: CD_RADIUS */
{sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 45: CD_HAIRCURVE */
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 48e0ee50d43..9bdd80fd668 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -562,7 +562,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map
CustomData *cd_dst,
const bool use_dupref_dst,
const int tolayers,
- bool *use_layers_src,
+ const bool *use_layers_src,
const int num_layers_src,
cd_datatransfer_interp interp,
void *interp_data)
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index b97935d57f2..98fc5f9a23a 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -249,7 +249,7 @@ void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
/**
* be sure all flip_map values are valid
*/
-void BKE_defvert_remap(MDeformVert *dvert, int *map, const int map_len)
+void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
{
MDeformWeight *dw = dvert->dw;
unsigned int i;
@@ -1184,7 +1184,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
CustomData *cd_dst,
const bool UNUSED(use_dupref_dst),
const int tolayers,
- bool *use_layers_src,
+ const bool *use_layers_src,
const int num_layers_src)
{
int idx_src;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 2e1fa519284..b9279ace39f 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -588,7 +588,7 @@ static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
}
/* check whether bounds intersects a point with given radius */
-static bool boundIntersectPoint(Bounds3D *b, float point[3], const float radius)
+static bool boundIntersectPoint(Bounds3D *b, const float point[3], const float radius)
{
if (!b->valid) {
return false;
@@ -4780,13 +4780,16 @@ static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata,
}
}
-static int dynamicPaint_paintSinglePoint(Depsgraph *depsgraph,
- DynamicPaintSurface *surface,
- float *pointCoord,
- DynamicPaintBrushSettings *brush,
- Object *brushOb,
- Scene *scene,
- float timescale)
+static int dynamicPaint_paintSinglePoint(
+ Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
+ /* Cannot be const, because it is assigned to non-const variable.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ float *pointCoord,
+ DynamicPaintBrushSettings *brush,
+ Object *brushOb,
+ Scene *scene,
+ float timescale)
{
PaintSurfaceData *sData = surface->data;
float brush_radius = brush->paint_distance * surface->radius_scale;
@@ -5456,11 +5459,14 @@ static void dynamic_paint_effect_drip_cb(void *__restrict userdata,
}
}
-static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface,
- float *force,
- PaintPoint *prevPoint,
- float timescale,
- float steps)
+static void dynamicPaint_doEffectStep(
+ DynamicPaintSurface *surface,
+ /* Cannot be const, because it is assigned to non-const variable.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ float *force,
+ PaintPoint *prevPoint,
+ float timescale,
+ float steps)
{
PaintSurfaceData *sData = surface->data;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 235c834fde9..a43553ee89f 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -1094,11 +1094,11 @@ void BKE_effectors_apply(ListBase *effectors,
* Modifies the force on a particle according to its
* relation with the effector object
* Different kind of effectors include:
- * Forcefields: Gravity-like attractor
+ * Force-fields: Gravity-like attractor
* (force power is related to the inverse of distance to the power of a falloff value)
* Vortex fields: swirling effectors
* (particles rotate around Z-axis of the object. otherwise, same relation as)
- * (Forcefields, but this is not done through a force/acceleration)
+ * (Force-fields, but this is not done through a force/acceleration)
* Guide: particles on a path
* (particles are guided along a curve bezier or old nurbs)
* (is independent of other effectors)
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index bc14f525c2c..746aff1697c 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1277,7 +1277,7 @@ short test_time_fcurve(FCurve *fcu)
* than the horizontal distance between (v1-v4).
* This is to prevent curve loops.
*/
-void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2])
+void correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 1f748487841..52a3521189b 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -137,9 +137,9 @@ bool BKE_fluid_reallocate_fluid(FluidDomainSettings *fds, int res[3], int free_o
void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *fds,
int o_res[3],
int n_res[3],
- int o_min[3],
- int n_min[3],
- int o_max[3],
+ const int o_min[3],
+ const int n_min[3],
+ const int o_max[3],
int o_shift[3],
int n_shift[3])
{
@@ -491,6 +491,17 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *fds,
fds->cell_size[2] /= (float)fds->base_res[2];
}
+static void update_final_gravity(FluidDomainSettings *fds, Scene *scene)
+{
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(fds->gravity_final, scene->physics_settings.gravity);
+ }
+ else {
+ copy_v3_v3(fds->gravity_final, fds->gravity);
+ }
+ mul_v3_fl(fds->gravity_final, fds->effector_weights->global_gravity);
+}
+
static bool BKE_fluid_modifier_init(
FluidModifierData *fmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
{
@@ -502,10 +513,7 @@ static bool BKE_fluid_modifier_init(
/* Set domain dimensions from mesh. */
manta_set_domain_from_mesh(fds, ob, me, true);
/* Set domain gravity, use global gravity if enabled. */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(fds->gravity, scene->physics_settings.gravity);
- }
- mul_v3_fl(fds->gravity, fds->effector_weights->global_gravity);
+ update_final_gravity(fds, scene);
/* Reset domain values. */
zero_v3_int(fds->shift);
zero_v3(fds->shift_f);
@@ -559,7 +567,7 @@ static bool BKE_fluid_modifier_init(
// forward declaration
static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *view_layer);
static float calc_voxel_transp(
- float *result, float *input, int res[3], int *pixel, float *t_ray, float correct);
+ float *result, const float *input, int res[3], int *pixel, float *t_ray, float correct);
static void update_distances(int index,
float *fesh_distances,
BVHTreeFromMesh *tree_data,
@@ -594,8 +602,8 @@ static int get_light(ViewLayer *view_layer, float *light)
static void clamp_bounds_in_domain(FluidDomainSettings *fds,
int min[3],
int max[3],
- float *min_vel,
- float *max_vel,
+ const float *min_vel,
+ const float *max_vel,
int margin,
float dt)
{
@@ -1830,7 +1838,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
float *velocity_map,
int index,
const int base_res[3],
- float flow_center[3],
+ const float flow_center[3],
BVHTreeFromMesh *tree_data,
const float ray_start[3],
const float *vert_vel,
@@ -3328,17 +3336,13 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obj
mverts->co[1] = manta_liquid_get_vertex_y_at(fds->fluid, i);
mverts->co[2] = manta_liquid_get_vertex_z_at(fds->fluid, i);
- /* If reading raw data directly from manta, normalize now (e.g. during replay mode).
- * If reading data from files from disk, omit this normalization. */
- if (!manta_liquid_mesh_from_file(fds->fluid)) {
- // normalize to unit cube around 0
- mverts->co[0] -= ((float)fds->res[0] * fds->mesh_scale) * 0.5f;
- mverts->co[1] -= ((float)fds->res[1] * fds->mesh_scale) * 0.5f;
- mverts->co[2] -= ((float)fds->res[2] * fds->mesh_scale) * 0.5f;
- mverts->co[0] *= fds->dx / fds->mesh_scale;
- mverts->co[1] *= fds->dx / fds->mesh_scale;
- mverts->co[2] *= fds->dx / fds->mesh_scale;
- }
+ /* Adjust coordinates from Mantaflow to match viewport scaling. */
+ float tmp[3] = {(float)fds->res[0], (float)fds->res[1], (float)fds->res[2]};
+ /* Scale to unit cube around 0. */
+ mul_v3_fl(tmp, fds->mesh_scale * 0.5f);
+ sub_v3_v3(mverts->co, tmp);
+ /* Apply scaling of domain object. */
+ mul_v3_fl(mverts->co, fds->dx / fds->mesh_scale);
mul_v3_v3(mverts->co, co_scale);
add_v3_v3(mverts->co, co_offset);
@@ -3808,10 +3812,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
fds->time_per_frame = 0;
/* Ensure that gravity is copied over every frame (could be keyframed). */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(fds->gravity, scene->physics_settings.gravity);
- mul_v3_fl(fds->gravity, fds->effector_weights->global_gravity);
- }
+ update_final_gravity(fds, scene);
int next_frame = scene_framenr + 1;
int prev_frame = scene_framenr - 1;
@@ -4118,43 +4119,47 @@ static void BKE_fluid_modifier_process(
struct Mesh *BKE_fluid_modifier_do(
FluidModifierData *fmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
- /* Lock so preview render does not read smoke data while it gets modified. */
- if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
- BLI_rw_mutex_lock(fmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- }
-
- BKE_fluid_modifier_process(fmd, depsgraph, scene, ob, me);
-
- if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
- BLI_rw_mutex_unlock(fmd->domain->fluid_mutex);
- }
-
/* Optimization: Do not update viewport during bakes (except in replay mode)
* Reason: UI is locked and updated liquid / smoke geometry is not visible anyways. */
bool needs_viewport_update = false;
- if (fmd->domain) {
- FluidDomainSettings *fds = fmd->domain;
- /* Always update viewport in cache replay mode. */
- if (fds->cache_type == FLUID_DOMAIN_CACHE_REPLAY ||
- fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- needs_viewport_update = true;
+ /* Optimization: Only process modifier if object is not being altered. */
+ if (!G.moving) {
+ /* Lock so preview render does not read smoke data while it gets modified. */
+ if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
+ BLI_rw_mutex_lock(fmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
}
- /* In other cache modes, only update the viewport when no bake is going on. */
- else {
- bool with_mesh;
- with_mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
- bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
- baking_data = fds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
- baking_noise = fds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
- baking_mesh = fds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
- baking_particles = fds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
- baking_guide = fds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
-
- if (with_mesh && !baking_data && !baking_noise && !baking_mesh && !baking_particles &&
- !baking_guide) {
+
+ BKE_fluid_modifier_process(fmd, depsgraph, scene, ob, me);
+
+ if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
+ BLI_rw_mutex_unlock(fmd->domain->fluid_mutex);
+ }
+
+ if (fmd->domain) {
+ FluidDomainSettings *fds = fmd->domain;
+
+ /* Always update viewport in cache replay mode. */
+ if (fds->cache_type == FLUID_DOMAIN_CACHE_REPLAY ||
+ fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
needs_viewport_update = true;
}
+ /* In other cache modes, only update the viewport when no bake is going on. */
+ else {
+ bool with_mesh;
+ with_mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
+ bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
+ baking_data = fds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
+ baking_noise = fds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
+ baking_mesh = fds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
+ baking_particles = fds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
+ baking_guide = fds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
+
+ if (with_mesh && !baking_data && !baking_noise && !baking_mesh && !baking_particles &&
+ !baking_guide) {
+ needs_viewport_update = true;
+ }
+ }
}
}
@@ -4196,7 +4201,7 @@ struct Mesh *BKE_fluid_modifier_do(
}
static float calc_voxel_transp(
- float *result, float *input, int res[3], int *pixel, float *t_ray, float correct)
+ float *result, const float *input, int res[3], int *pixel, float *t_ray, float correct)
{
const size_t index = manta_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 6a9511d8275..eeb55c44d6e 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -681,10 +681,10 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d
}
/**
- * Make a copy of a given gpencil stroke.
- * \param gps_src: Source grease pencil strokeyes
- * \param dup_points: Duplicate points data
- * \return Pointer to new stroke
+ * Make a copy of a given grease-pencil stroke.
+ * \param gps_src: Source grease pencil strokes.
+ * \param dup_points: Duplicate points data.
+ * \return Pointer to new stroke.
*/
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, const bool dup_points)
{
@@ -1512,12 +1512,12 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi
}
/**
- * Creates a new gpencil material and assigns it to object.
+ * Creates a new grease-pencil material and assigns it to object.
* \param bmain: Main pointer
* \param ob: Grease pencil object
* \param name: Material name
* \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
- * \return Materil pointer
+ * \return Material pointer.
*/
Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
{
@@ -1555,7 +1555,7 @@ Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
* Returns the material index for a brush with respect to its pinned state.
* \param ob: Grease pencil object
* \param brush: Brush
- * \return Materil index
+ * \return Material index.
*/
int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
{
@@ -1571,8 +1571,7 @@ int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
* Guaranteed to return a material assigned to object. Returns never NULL.
* \param bmain: Main pointer
* \param ob: Grease pencil object
- * \param ts: Toolsettings
- * \return Material pointer
+ * \return Material pointer.
*/
Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main *bmain,
Object *ob,
@@ -1590,7 +1589,7 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main
/**
* Guaranteed to return a material assigned to object. Returns never NULL.
* \param bmain: Main pointer
- * \param ob: Grease pencil obejct
+ * \param ob: Grease pencil object.
* \param brush: Brush
* \return Material pointer
*/
@@ -1783,7 +1782,8 @@ float BKE_gpencil_multiframe_falloff_calc(
value = BKE_curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
}
else {
- value = 1.0f;
+ /* Center of the curve. */
+ value = BKE_curvemapping_evaluateF(cur_falloff, 0, 0.5f);
}
return value;
@@ -2330,8 +2330,8 @@ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
/**
* Update original pointers in evaluated frame.
- * \param gpf_orig: Original greas epencil frame
- * \param gpf_eval: Evaluated grease pencil frame
+ * \param gpf_orig: Original grease-pencil frame.
+ * \param gpf_eval: Evaluated grease pencil frame.
*/
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval)
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index 49940c2d466..b92f86d7aea 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -989,7 +989,7 @@ bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influe
* \param points: Array of grease pencil points (3D)
* \param totpoints: Total of points
* \param points2d: Result array of 2D points
- * \param r_direction: Return Concave (-1), Convex (1), or Autodetect (0)
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
*/
void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
int totpoints,
@@ -1043,7 +1043,7 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
points2d[i][1] = dot_v3v3(loc, locy);
}
- /* Concave (-1), Convex (1), or Autodetect (0)? */
+ /* Concave (-1), Convex (1), or Auto-detect (0)? */
*r_direction = (int)locy[2];
}
@@ -1056,7 +1056,7 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
* \param totpoints: Total points
* \param points2d: Result array of 2D points
* \param scale: Scale factor
- * \param r_direction: Return Concave (-1), Convex (1), or Autodetect (0)
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
*/
void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
int ref_totpoints,
@@ -1138,7 +1138,7 @@ void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
points2d[i][1] = dot_v3v3(loc, locy);
}
- /* Concave (-1), Convex (1), or Autodetect (0)? */
+ /* Concave (-1), Convex (1), or Auto-detect (0)? */
*r_direction = (int)locy[2];
}
@@ -1146,7 +1146,7 @@ void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
bGPDstroke *gps,
const float minv[2],
- float maxv[2],
+ const float maxv[2],
float (*r_uv)[2])
{
const float s = sin(gps->uv_rotation);
@@ -1289,9 +1289,9 @@ void BKE_gpencil_stroke_geometry_update(bGPDstroke *gps)
/**
* Calculate grease pencil stroke length.
- * @param gps Grease pencil stroke
- * @param use_3d Set to true to use 3D points
- * @return Length of the stroke
+ * \param gps: Grease pencil stroke
+ * \param use_3d: Set to true to use 3D points
+ * \return Length of the stroke
*/
float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
{
@@ -2395,8 +2395,8 @@ void BKE_gpencil_convert_mesh(Main *bmain,
/**
* Apply grease pencil Transforms.
- * @param gpd Grease pencil data-block
- * @param mat Transformation matrix
+ * \param gpd: Grease pencil data-block
+ * \param mat: Transformation matrix
*/
void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 24cfc65a8fe..e92bf5a4502 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -197,7 +197,7 @@ static int gpencil_time_modifier(
/**
* Set current grease pencil active frame.
* \param depsgraph: Current depsgraph
- * \param gpd: Grease pencil data-block
+ * \param gpd: Grease pencil data-block.
*/
void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
{
@@ -223,8 +223,7 @@ void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
}
/**
- * Init grease pencil modifier.
- * \param void
+ * Initialize grease pencil modifier.
*/
void BKE_gpencil_modifier_init(void)
{
@@ -460,7 +459,6 @@ GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifi
* Set grease pencil modifier error.
* \param md: Modifier data
* \param _format: Format
- * \param
*/
void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format, ...)
{
@@ -560,8 +558,8 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
return remap_cfra;
}
-/** Get the current frame retimed with time modifiers.
- * \param depsgraph: Current depsgraph
+/** Get the current frame re-timed with time modifiers.
+ * \param depsgraph: Current depsgraph.
* \param scene: Current scene
* \param ob: Grease pencil object
* \param gpl: Grease pencil layer
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index 2684e964eb1..1166ad9ad2f 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -36,8 +36,11 @@
#include "BLT_translation.h"
#include "DNA_ID.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_idtype.h"
@@ -470,3 +473,33 @@ short BKE_idtype_idcode_iter_step(int *index)
{
return (*index < ARRAY_SIZE(id_types)) ? BKE_idtype_idcode_from_index((*index)++) : 0;
}
+
+/** Wrapper around IDTypeInfo foreach_cache that also handles embedded IDs. */
+void BKE_idtype_id_foreach_cache(struct ID *id,
+ IDTypeForeachCacheFunctionCallback function_callback,
+ void *user_data)
+{
+ const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
+ if (type_info->foreach_cache != NULL) {
+ type_info->foreach_cache(id, function_callback, user_data);
+ }
+
+ /* Handle 'private IDs'. */
+ bNodeTree *nodetree = ntreeFromID(id);
+ if (nodetree != NULL) {
+ type_info = BKE_idtype_get_info_from_id(&nodetree->id);
+ if (type_info->foreach_cache != NULL) {
+ type_info->foreach_cache(&nodetree->id, function_callback, user_data);
+ }
+ }
+
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ if (scene->master_collection != NULL) {
+ type_info = BKE_idtype_get_info_from_id(&scene->master_collection->id);
+ if (type_info->foreach_cache != NULL) {
+ type_info->foreach_cache(&scene->master_collection->id, function_callback, user_data);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 41ef5dc00ef..647349108e1 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -195,24 +195,24 @@ static void image_foreach_cache(ID *id,
.offset_in_ID = offsetof(Image, cache),
.cache_v = image->cache,
};
- function_callback(id, &key, (void **)&image->cache, user_data);
+ function_callback(id, &key, (void **)&image->cache, 0, user_data);
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
key.offset_in_ID = offsetof(Image, gputexture[a][eye]);
key.cache_v = image->gputexture[a][eye];
- function_callback(id, &key, (void **)&image->gputexture[a][eye], user_data);
+ function_callback(id, &key, (void **)&image->gputexture[a][eye], 0, user_data);
}
}
key.offset_in_ID = offsetof(Image, rr);
key.cache_v = image->rr;
- function_callback(id, &key, (void **)&image->rr, user_data);
+ function_callback(id, &key, (void **)&image->rr, 0, user_data);
LISTBASE_FOREACH (RenderSlot *, slot, &image->renderslots) {
key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(slot->name);
key.cache_v = slot->render;
- function_callback(id, &key, (void **)&slot->render, user_data);
+ function_callback(id, &key, (void **)&slot->render, 0, user_data);
}
}
@@ -4363,7 +4363,7 @@ static ImBuf *load_image_single(Image *ima,
/* make packed file for autopack */
if ((has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) {
- ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Pack-file");
BLI_addtail(&ima->packedfiles, imapf);
STRNCPY(imapf->filepath, filepath);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index af8ab22e14b..46a41df0391 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -529,7 +529,13 @@ static int setkeys(float fac, ListBase *lb, KeyBlock *k[], float t[4], int cycl)
return 0;
}
-static void flerp(int tot, float *in, float *f0, float *f1, float *f2, float *f3, float *t)
+static void flerp(int tot,
+ float *in,
+ const float *f0,
+ const float *f1,
+ const float *f2,
+ const float *f3,
+ const float *t)
{
int a;
@@ -538,7 +544,7 @@ static void flerp(int tot, float *in, float *f0, float *f1, float *f2, float *f3
}
}
-static void rel_flerp(int tot, float *in, float *ref, float *out, float fac)
+static void rel_flerp(int tot, float *in, const float *ref, const float *out, float fac)
{
int a;
diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c
index 2b3349d4d9a..674ee9ed2c5 100644
--- a/source/blender/blenkernel/intern/lattice_deform.c
+++ b/source/blender/blenkernel/intern/lattice_deform.c
@@ -418,8 +418,8 @@ static void lattice_deform_coords_impl(const Object *ob_lattice,
void BKE_lattice_deform_coords(const Object *ob_lattice,
const Object *ob_target,
float (*vert_coords)[3],
- int vert_coords_len,
- short flag,
+ const int vert_coords_len,
+ const short flag,
const char *defgrp_name,
float fac)
{
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 7c09ae51344..eb440de1a6f 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -611,41 +611,39 @@ bool BKE_id_copy(Main *bmain, const ID *id, ID **newid)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
-ID *BKE_id_copy_for_duplicate(Main *bmain,
- ID *id,
- const bool is_owner_id_liboverride,
- const eDupli_ID_Flags duplicate_flags)
+ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
{
if (id == NULL) {
- return NULL;
+ return id;
}
if (id->newid == NULL) {
- if (!is_owner_id_liboverride || !ID_IS_LINKED(id)) {
- ID *id_new;
- BKE_id_copy(bmain, id, &id_new);
- /* Copying add one user by default, need to get rid of that one. */
- id_us_min(id_new);
- ID_NEW_SET(id, id_new);
-
- /* Shape keys are always copied with their owner ID, by default. */
- ID *key_new = (ID *)BKE_key_from_id(id_new);
- ID *key = (ID *)BKE_key_from_id(id);
- if (key != NULL) {
- ID_NEW_SET(key, key_new);
- }
+ const bool do_linked_id = (duplicate_flags & USER_DUP_LINKED_ID) != 0;
+ if (!(do_linked_id || !ID_IS_LINKED(id))) {
+ return id;
+ }
- /* Note: embedded data (root nodetrees and master collections) should never be referenced by
- * anything else, so we do not need to set their newid pointer and flag. */
+ ID *id_new;
+ BKE_id_copy(bmain, id, &id_new);
+ /* Copying add one user by default, need to get rid of that one. */
+ id_us_min(id_new);
+ ID_NEW_SET(id, id_new);
- if (duplicate_flags & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, id_new, true);
- if (key_new != NULL) {
- BKE_animdata_copy_id_action(bmain, key_new, true);
- }
- /* Note that actions of embedded data (root nodetrees and master collections) are handled
- * by `BKE_animdata_copy_id_action` as well. */
- }
+ /* Shape keys are always copied with their owner ID, by default. */
+ ID *key_new = (ID *)BKE_key_from_id(id_new);
+ ID *key = (ID *)BKE_key_from_id(id);
+ if (key != NULL) {
+ ID_NEW_SET(key, key_new);
+ }
+
+ /* Note: embedded data (root nodetrees and master collections) should never be referenced by
+ * anything else, so we do not need to set their newid pointer and flag. */
+
+ BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags);
+ if (key_new != NULL) {
+ BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags);
}
+ /* Note that actions of embedded data (root nodetrees and master collections) are handled
+ * by `BKE_animdata_duplicate_id_action` as well. */
}
return id->newid;
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 457d096f983..58856729f24 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -38,6 +38,7 @@
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
+#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
@@ -66,20 +67,6 @@ static void lib_override_library_property_clear(IDOverrideLibraryProperty *op);
static void lib_override_library_property_operation_clear(
IDOverrideLibraryPropertyOperation *opop);
-/* Temp, for until library override is ready and tested enough to go 'public',
- * we hide it by default in UI and such. */
-static bool _lib_override_library_enabled = true;
-
-void BKE_lib_override_library_enable(const bool do_enable)
-{
- _lib_override_library_enabled = do_enable;
-}
-
-bool BKE_lib_override_library_is_enabled()
-{
- return _lib_override_library_enabled;
-}
-
/** Initialize empty overriding of \a reference_id by \a local_id. */
IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
{
@@ -368,6 +355,56 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
return success;
}
+static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id)
+{
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+
+ /* This way we won't process again that ID should we encounter it again through another
+ * relationship hierarchy.
+ * Note that this does not free any memory from relations, so we can still use the entries.
+ */
+ BKE_main_relations_ID_remove(bmain, id);
+
+ for (; entry != NULL; entry = entry->next) {
+ /* We only consider IDs from the same library. */
+ if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
+ if (lib_override_hierarchy_recursive_tag(bmain, *entry->id_pointer)) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
+
+ return (id->tag & LIB_TAG_DOIT) != 0;
+}
+
+/**
+ * Tag all IDs in given \a bmain that use (depends on) given \a id_root ID.
+ *
+ * This will include all local IDs, and all IDs from the same library as the \a id_root.
+ *
+ * \param id_root The root of the hierarchy of dependencies to be tagged.
+ * \param do_create_main_relashionships Whether main relations needs to be created or already exist
+ * (in any case, they will be freed by this function).
+ */
+void BKE_lib_override_library_dependencies_tag(struct Main *bmain,
+ struct ID *id_root,
+ const uint tag,
+ const bool do_create_main_relashionships)
+{
+ id_root->tag |= tag;
+
+ if (do_create_main_relashionships) {
+ BKE_main_relations_create(bmain, 0);
+ }
+
+ /* Then we tag all intermediary data-blocks in-between two overridden ones (e.g. if a shapekey
+ * has a driver using an armature object's bone, we need to override the shapekey/obdata, the
+ * objects using them, etc.) */
+ lib_override_hierarchy_recursive_tag(bmain, id_root);
+
+ BKE_main_relations_free(bmain);
+}
+
/* We only build override GHash on request. */
BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_mapping_ensure(
IDOverrideLibrary *override)
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 49c909850de..7e859799a4e 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -624,7 +624,7 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float
co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u);
}
-BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2])
+BLI_INLINE void orthogonal_direction_get(const float vec[2], float result[2])
{
result[0] = -vec[1];
result[1] = vec[0];
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 412ccd3ab39..7f98266becc 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1256,7 +1256,7 @@ static float maskrasterize_layer_z_depth_quad(
return w[2] + w[3]; /* we can make this assumption for small speedup */
}
-static float maskrasterize_layer_isect(unsigned int *face,
+static float maskrasterize_layer_isect(const unsigned int *face,
float (*cos)[3],
const float dist_orig,
const float xy[2])
@@ -1489,6 +1489,8 @@ static void maskrasterize_buffer_cb(void *__restrict userdata,
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
const unsigned int width,
const unsigned int height,
+ /* Cannot be const, because it is assigned to non-const variable.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
float *buffer)
{
const float x_inv = 1.0f / (float)width;
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index b298a6a2787..49957b584ad 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2888,7 +2888,7 @@ void BKE_mesh_loops_to_mface_corners(
void BKE_mesh_loops_to_tessdata(CustomData *fdata,
CustomData *ldata,
MFace *mface,
- int *polyindices,
+ const int *polyindices,
unsigned int (*loopindices)[4],
const int num_faces)
{
@@ -2981,7 +2981,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata,
void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata,
CustomData *ldata,
MFace *mface,
- int *polyindices,
+ const int *polyindices,
unsigned int (*loopindices)[4],
const int num_faces,
const char *layer_name)
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 4ed9b31dbb5..686f58a0ceb 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -953,7 +953,7 @@ void BKE_mesh_loop_islands_free(MeshIslandStore *island_store)
void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
const int item_num,
- int *items_indices,
+ const int *items_indices,
const int num_island_items,
int *island_item_indices,
const int num_innercut_items,
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 404d6a581ae..a4991675d2d 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -1071,7 +1071,7 @@ static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands,
BLI_bitmap *done_edges,
MeshElemMap *edge_to_poly_map,
const bool is_edge_innercut,
- int *poly_island_index_map,
+ const int *poly_island_index_map,
float (*poly_centers)[3],
unsigned char *poly_status)
{
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index d36f5ed0329..4a65c6ff5e7 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -139,11 +139,11 @@ static void movie_clip_foreach_cache(ID *id,
.offset_in_ID = offsetof(MovieClip, cache),
.cache_v = movie_clip->cache,
};
- function_callback(id, &key, (void **)&movie_clip->cache, user_data);
+ function_callback(id, &key, (void **)&movie_clip->cache, 0, user_data);
key.offset_in_ID = offsetof(MovieClip, tracking.camera.intrinsics);
key.cache_v = movie_clip->tracking.camera.intrinsics;
- function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, user_data);
+ function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, 0, user_data);
}
IDTypeInfo IDType_ID_MC = {
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 7e78be6d66e..71d49dd1c19 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -175,7 +175,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
return subd;
}
-static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden,
+static BLI_bitmap *multires_mdisps_downsample_hidden(const BLI_bitmap *old_hidden,
int old_level,
int new_level)
{
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 3564ae80d24..e12e692ea23 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -271,7 +271,7 @@ static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_sm
for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
surface_grid[grid_index].points = MEM_calloc_arrayN(
- sizeof(SurfacePoint), grid_area, "delta grid dispalcement");
+ sizeof(SurfacePoint), grid_area, "delta grid displacement");
}
reshape_smooth_context->base_surface_grids = surface_grid;
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
index 6bd7b6b6a98..fa1a53f946e 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.c
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -80,7 +80,7 @@
/**
* Used to check if a vertex is in a disconnected element ID.
*/
-static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem)
+static bool is_vertex_in_id(BMVert *v, const int *elem_id, int elem)
{
const int v_index = BM_elem_index_get(v);
return elem_id[v_index] == elem;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index b73f957535c..52f0d259058 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -315,6 +315,33 @@ static void node_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
+static void node_foreach_cache(ID *id,
+ IDTypeForeachCacheFunctionCallback function_callback,
+ void *user_data)
+{
+ bNodeTree *nodetree = (bNodeTree *)id;
+ IDCacheKey key = {
+ .id_session_uuid = id->session_uuid,
+ .offset_in_ID = offsetof(bNodeTree, previews),
+ .cache_v = nodetree->previews,
+ };
+
+ /* TODO, see also `direct_link_nodetree()` in readfile.c. */
+#if 0
+ function_callback(id, &key, (void **)&nodetree->previews, 0, user_data);
+#endif
+
+ if (nodetree->type == NTREE_COMPOSIT) {
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_MOVIEDISTORTION) {
+ key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(node->name);
+ key.cache_v = node->storage;
+ function_callback(id, &key, (void **)&node->storage, 0, user_data);
+ }
+ }
+ }
+}
+
IDTypeInfo IDType_ID_NT = {
.id_code = ID_NT,
.id_filter = FILTER_ID_NT,
@@ -330,6 +357,7 @@ IDTypeInfo IDType_ID_NT = {
.free_data = ntree_free_data,
.make_local = NULL,
.foreach_id = node_foreach_id,
+ .foreach_cache = node_foreach_cache,
};
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
diff --git a/source/blender/blenkernel/intern/node_tree_multi_function.cc b/source/blender/blenkernel/intern/node_tree_multi_function.cc
new file mode 100644
index 00000000000..4e505db9b9d
--- /dev/null
+++ b/source/blender/blenkernel/intern/node_tree_multi_function.cc
@@ -0,0 +1,306 @@
+/*
+ * 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_node_tree_multi_function.hh"
+
+#include "BLI_float3.hh"
+
+namespace blender {
+namespace bke {
+
+/* Maybe this should be moved to BKE_node.h. */
+static std::optional<fn::MFDataType> try_get_multi_function_data_type_of_socket(
+ const bNodeSocket *bsocket)
+{
+ if (bsocket->typeinfo->get_mf_data_type == nullptr) {
+ return {};
+ }
+ return bsocket->typeinfo->get_mf_data_type();
+}
+
+static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &dnode)
+{
+ constexpr uint stack_capacity = 10;
+
+ Vector<fn::MFDataType, stack_capacity> input_types;
+ Vector<StringRef, stack_capacity> input_names;
+ Vector<const DInputSocket *, stack_capacity> input_dsockets;
+
+ for (const DInputSocket *dsocket : dnode.inputs()) {
+ if (dsocket->is_available()) {
+ std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
+ dsocket->bsocket());
+ if (data_type.has_value()) {
+ input_types.append(*data_type);
+ input_names.append(dsocket->name());
+ input_dsockets.append(dsocket);
+ }
+ }
+ }
+
+ Vector<fn::MFDataType, stack_capacity> output_types;
+ Vector<StringRef, stack_capacity> output_names;
+ Vector<const DOutputSocket *, stack_capacity> output_dsockets;
+
+ for (const DOutputSocket *dsocket : dnode.outputs()) {
+ if (dsocket->is_available()) {
+ std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
+ dsocket->bsocket());
+ if (data_type.has_value()) {
+ output_types.append(*data_type);
+ output_names.append(dsocket->name());
+ output_dsockets.append(dsocket);
+ }
+ }
+ }
+
+ fn::MFDummyNode &dummy_node = common.network.add_dummy(
+ dnode.name(), input_types, output_types, input_names, output_names);
+
+ common.network_map.add(input_dsockets, dummy_node.inputs());
+ common.network_map.add(output_dsockets, dummy_node.outputs());
+}
+
+static bool has_data_sockets(const DNode &dnode)
+{
+ for (const DInputSocket *socket : dnode.inputs()) {
+ if (is_multi_function_data_socket(socket->bsocket())) {
+ return true;
+ }
+ }
+ for (const DOutputSocket *socket : dnode.outputs()) {
+ if (is_multi_function_data_socket(socket->bsocket())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Expands all function nodes in the multi-function network. Nodes that don't have an expand
+ * function, but do have data sockets, will get corresponding dummy nodes.
+ */
+static void insert_nodes(CommonMFNetworkBuilderData &common)
+{
+ for (const DNode *dnode : common.tree.nodes()) {
+ const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo;
+ if (node_type->expand_in_mf_network != nullptr) {
+ NodeMFNetworkBuilder builder{common, *dnode};
+ node_type->expand_in_mf_network(builder);
+ }
+ else if (has_data_sockets(*dnode)) {
+ insert_dummy_node(common, *dnode);
+ }
+ }
+}
+
+static void insert_group_inputs(CommonMFNetworkBuilderData &common)
+{
+ for (const DGroupInput *group_input : common.tree.group_inputs()) {
+ bNodeSocket *bsocket = group_input->bsocket();
+ if (is_multi_function_data_socket(bsocket)) {
+ bNodeSocketType *socktype = bsocket->typeinfo;
+ BLI_assert(socktype->expand_in_mf_network != nullptr);
+
+ SocketMFNetworkBuilder builder{common, *group_input};
+ socktype->expand_in_mf_network(builder);
+
+ fn::MFOutputSocket *from_socket = builder.built_socket();
+ BLI_assert(from_socket != nullptr);
+ common.network_map.add(*group_input, *from_socket);
+ }
+ }
+}
+
+static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
+ const DInputSocket &to_dsocket)
+{
+ Span<const DOutputSocket *> from_dsockets = to_dsocket.linked_sockets();
+ Span<const DGroupInput *> from_group_inputs = to_dsocket.linked_group_inputs();
+ uint total_linked_amount = from_dsockets.size() + from_group_inputs.size();
+ BLI_assert(total_linked_amount <= 1);
+
+ if (total_linked_amount == 0) {
+ return nullptr;
+ }
+
+ if (from_dsockets.size() == 1) {
+ if (is_multi_function_data_socket(from_dsockets[0]->bsocket())) {
+ return &common.network_map.lookup(*from_dsockets[0]);
+ }
+ else {
+ return nullptr;
+ }
+ }
+ else {
+ if (is_multi_function_data_socket(from_group_inputs[0]->bsocket())) {
+ return &common.network_map.lookup(*from_group_inputs[0]);
+ }
+ else {
+ return nullptr;
+ }
+ }
+}
+
+static const fn::MultiFunction *try_get_conversion_function(fn::MFDataType from, fn::MFDataType to)
+{
+ if (from == fn::MFDataType::ForSingle<float>()) {
+ if (to == fn::MFDataType::ForSingle<int32_t>()) {
+ static fn::CustomMF_Convert<float, int32_t> function;
+ return &function;
+ }
+ if (to == fn::MFDataType::ForSingle<float3>()) {
+ static fn::CustomMF_Convert<float, float3> function;
+ return &function;
+ }
+ }
+ if (from == fn::MFDataType::ForSingle<float3>()) {
+ if (to == fn::MFDataType::ForSingle<float>()) {
+ static fn::CustomMF_SI_SO<float3, float> function{"Vector Length",
+ [](float3 a) { return a.length(); }};
+ return &function;
+ }
+ }
+ if (from == fn::MFDataType::ForSingle<int32_t>()) {
+ if (to == fn::MFDataType::ForSingle<float>()) {
+ static fn::CustomMF_Convert<int32_t, float> function;
+ return &function;
+ }
+ if (to == fn::MFDataType::ForSingle<float3>()) {
+ static fn::CustomMF_SI_SO<int32_t, float3> function{
+ "int32 to float3", [](int32_t a) { return float3((float)a); }};
+ return &function;
+ }
+ }
+
+ return nullptr;
+}
+
+static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common,
+ fn::MFDataType type)
+{
+ const fn::MultiFunction *default_fn;
+ if (type.is_single()) {
+ default_fn = &common.resources.construct<fn::CustomMF_GenericConstant>(
+ AT, type.single_type(), type.single_type().default_value());
+ }
+ else {
+ default_fn = &common.resources.construct<fn::CustomMF_GenericConstantArray>(
+ AT, fn::GSpan(type.vector_base_type()));
+ }
+
+ fn::MFNode &node = common.network.add_function(*default_fn);
+ return node.output(0);
+}
+
+static void insert_links(CommonMFNetworkBuilderData &common)
+{
+ for (const DInputSocket *to_dsocket : common.tree.input_sockets()) {
+ if (!to_dsocket->is_available()) {
+ continue;
+ }
+ if (!to_dsocket->is_linked()) {
+ continue;
+ }
+ if (!is_multi_function_data_socket(to_dsocket->bsocket())) {
+ continue;
+ }
+
+ Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket);
+ BLI_assert(to_sockets.size() >= 1);
+ fn::MFDataType to_type = to_sockets[0]->data_type();
+
+ fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
+ if (from_socket == nullptr) {
+ from_socket = &insert_default_value_for_type(common, to_type);
+ }
+
+ fn::MFDataType from_type = from_socket->data_type();
+
+ if (from_type != to_type) {
+ const fn::MultiFunction *conversion_fn = try_get_conversion_function(from_type, to_type);
+ if (conversion_fn != nullptr) {
+ fn::MFNode &node = common.network.add_function(*conversion_fn);
+ common.network.add_link(*from_socket, node.input(0));
+ from_socket = &node.output(0);
+ }
+ else {
+ from_socket = &insert_default_value_for_type(common, to_type);
+ }
+ }
+
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*from_socket, *to_socket);
+ }
+ }
+}
+
+static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket)
+{
+ bNodeSocket *bsocket = dsocket.bsocket();
+ bNodeSocketType *socktype = bsocket->typeinfo;
+ BLI_assert(socktype->expand_in_mf_network != nullptr);
+
+ SocketMFNetworkBuilder builder{common, dsocket};
+ socktype->expand_in_mf_network(builder);
+
+ fn::MFOutputSocket *from_socket = builder.built_socket();
+ BLI_assert(from_socket != nullptr);
+
+ for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) {
+ common.network.add_link(*from_socket, *to_socket);
+ }
+}
+
+static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
+{
+ Vector<const DInputSocket *> unlinked_data_inputs;
+ for (const DInputSocket *dsocket : common.tree.input_sockets()) {
+ if (dsocket->is_available()) {
+ if (is_multi_function_data_socket(dsocket->bsocket())) {
+ if (!dsocket->is_linked()) {
+ insert_unlinked_input(common, *dsocket);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Expands all function nodes contained in the given node tree within the given multi-function
+ * network.
+ *
+ * Returns a mapping between the original node tree and the generated nodes/sockets for further
+ * processing.
+ */
+MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
+ const DerivedNodeTree &tree,
+ ResourceCollector &resources)
+{
+ MFNetworkTreeMap network_map{tree, network};
+
+ CommonMFNetworkBuilderData common{resources, network, network_map, tree};
+
+ insert_nodes(common);
+ insert_group_inputs(common);
+ insert_links(common);
+ insert_unlinked_inputs(common);
+
+ return network_map;
+}
+
+} // namespace bke
+} // namespace blender
diff --git a/source/blender/blenkernel/intern/node_tree_ref.cc b/source/blender/blenkernel/intern/node_tree_ref.cc
index 54ea2d338db..5c998a06cb5 100644
--- a/source/blender/blenkernel/intern/node_tree_ref.cc
+++ b/source/blender/blenkernel/intern/node_tree_ref.cc
@@ -52,8 +52,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
RNA_pointer_create(&btree->id, &RNA_NodeSocket, bsocket, &socket.rna_);
}
- input_sockets_.extend(node.inputs_);
- output_sockets_.extend(node.outputs_);
+ input_sockets_.extend(node.inputs_.as_span());
+ output_sockets_.extend(node.outputs_.as_span());
node_mapping.add_new(bnode, &node);
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 6331f87f09f..d48ea33cc65 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1760,7 +1760,7 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
*/
Object *BKE_object_duplicate(Main *bmain,
Object *ob,
- const eDupli_ID_Flags dupflag,
+ eDupli_ID_Flags dupflag,
const eLibIDDuplicateFlags duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
@@ -1768,10 +1768,14 @@ Object *BKE_object_duplicate(Main *bmain,
if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
+ /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
+ * all expected linked data. */
+ if (ID_IS_LINKED(ob)) {
+ dupflag |= USER_DUP_LINKED_ID;
+ }
}
Material ***matarar;
- const bool is_object_liboverride = ID_IS_OVERRIDE_LIBRARY(ob);
Object *obn;
BKE_id_copy(bmain, &ob->id, (ID **)&obn);
@@ -1785,112 +1789,109 @@ Object *BKE_object_duplicate(Main *bmain,
return obn;
}
- /* duplicates using userflags */
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &obn->id, true);
- }
+ BKE_animdata_duplicate_id_action(bmain, &obn->id, dupflag);
if (dupflag & USER_DUP_MAT) {
for (int i = 0; i < obn->totcol; i++) {
- BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], is_object_liboverride, dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], dupflag);
}
}
if (dupflag & USER_DUP_PSYS) {
ParticleSystem *psys;
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
- BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, is_object_liboverride, dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, dupflag);
}
}
- ID *id = obn->data;
+ ID *id_old = obn->data;
ID *id_new = NULL;
- const bool need_to_duplicate_obdata = (id != NULL) && (id->newid == NULL);
+ const bool need_to_duplicate_obdata = (id_old != NULL) && (id_old->newid == NULL);
switch (obn->type) {
case OB_MESH:
if (dupflag & USER_DUP_MESH) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_CURVE:
if (dupflag & USER_DUP_CURVE) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_SURF:
if (dupflag & USER_DUP_SURF) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_FONT:
if (dupflag & USER_DUP_FONT) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_MBALL:
if (dupflag & USER_DUP_MBALL) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_LAMP:
if (dupflag & USER_DUP_LAMP) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_ARMATURE:
if (dupflag & USER_DUP_ARM) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_LATTICE:
if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_CAMERA:
if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_LIGHTPROBE:
if (dupflag & USER_DUP_LIGHTPROBE) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_SPEAKER:
if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_GPENCIL:
if (dupflag & USER_DUP_GPENCIL) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_HAIR:
if (dupflag & USER_DUP_HAIR) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_POINTCLOUD:
if (dupflag & USER_DUP_POINTCLOUD) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
case OB_VOLUME:
if (dupflag & USER_DUP_VOLUME) {
- id_new = BKE_id_copy_for_duplicate(bmain, id, is_object_liboverride, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
}
break;
}
/* If obdata has been copied, we may also have to duplicate the materials assigned to it. */
- if (need_to_duplicate_obdata && id_new != NULL) {
+ if (need_to_duplicate_obdata && !ELEM(id_new, NULL, id_old)) {
if (dupflag & USER_DUP_MAT) {
matarar = BKE_object_material_array_p(obn);
if (matarar) {
for (int i = 0; i < obn->totcol; i++) {
- BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], is_object_liboverride, dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], dupflag);
}
}
}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 6ca1442497a..51ec89cf77d 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -68,7 +68,7 @@ static Lattice *object_defgroup_lattice_get(ID *id)
*
* \param map: an array mapping old indices to new indices.
*/
-void BKE_object_defgroup_remap_update_users(Object *ob, int *map)
+void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
{
ModifierData *md;
ParticleSystem *psys;
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 4c6354f12a1..f498e147110 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -186,7 +186,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, float mat[4]
dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
if (dob->persistent_id[0] != INT_MAX) {
- for (i = 0; i < MAX_DUPLI_RECUR * 2; i++) {
+ for (i = 0; i < MAX_DUPLI_RECUR; i++) {
dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
}
}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 609c5c1e580..f94ef946851 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -147,19 +147,19 @@ static void init_complex(fftw_complex cmpl, float real, float image)
cmpl[1] = image;
}
-static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2)
+static void add_comlex_c(fftw_complex res, const fftw_complex cmpl1, const fftw_complex cmpl2)
{
res[0] = cmpl1[0] + cmpl2[0];
res[1] = cmpl1[1] + cmpl2[1];
}
-static void mul_complex_f(fftw_complex res, fftw_complex cmpl, float f)
+static void mul_complex_f(fftw_complex res, const fftw_complex cmpl, float f)
{
res[0] = cmpl[0] * (double)f;
res[1] = cmpl[1] * (double)f;
}
-static void mul_complex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2)
+static void mul_complex_c(fftw_complex res, const fftw_complex cmpl1, const fftw_complex cmpl2)
{
fftwf_complex temp;
temp[0] = cmpl1[0] * cmpl2[0] - cmpl1[1] * cmpl2[1];
@@ -178,7 +178,7 @@ static float image_c(fftw_complex cmpl)
return cmpl[1];
}
-static void conj_complex(fftw_complex res, fftw_complex cmpl1)
+static void conj_complex(fftw_complex res, const fftw_complex cmpl1)
{
res[0] = cmpl1[0];
res[1] = -cmpl1[1];
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index b3ab856468c..dca2022382a 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1514,7 +1514,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* Add a color layer if a color tool is used. */
Mesh *orig_me = BKE_object_get_original_mesh(ob);
- if (need_colors) {
+ if (need_colors && U.experimental.use_sculpt_vertex_colors) {
if (!CustomData_has_layer(&orig_me->vdata, CD_PROP_COLOR)) {
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
BKE_mesh_update_customdata_pointers(orig_me, true);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 942f3e0ca2b..a003daf1042 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -283,8 +283,8 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
}
return tot;
}
-/* we allocate path cache memory in chunks instead of a big contiguous
- * chunk, windows' memory allocater fails to find big blocks of memory often */
+/* We allocate path cache memory in chunks instead of a big contiguous
+ * chunk, windows' memory allocator fails to find big blocks of memory often. */
#define PATH_CACHE_BUF_SIZE 1024
@@ -1297,7 +1297,7 @@ static void do_particle_interpolation(ParticleSystem *psys,
dfra = keys[2].time - keys[1].time;
keytime = (real_t - keys[1].time) / dfra;
- /* convert velocity to timestep size */
+ /* Convert velocity to time-step size. */
if (pind->keyed || pind->cache || point_vel) {
invdt = dfra * 0.04f * (psys ? psys->part->timetweak : 1.f);
mul_v3_fl(keys[1].vel, invdt);
@@ -1305,8 +1305,8 @@ static void do_particle_interpolation(ParticleSystem *psys,
interp_qt_qtqt(result->rot, keys[1].rot, keys[2].rot, keytime);
}
- /* Now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between
- * [0, 1]->[k2, k3] (k1 & k4 used for cardinal & bspline interpolation). */
+ /* Now we should have in chronological order k1<=k2<=t<=k3<=k4 with key-time between
+ * [0, 1]->[k2, k3] (k1 & k4 used for cardinal & b-spline interpolation). */
psys_interpolate_particle((pind->keyed || pind->cache || point_vel) ?
-1 /* signal for cubic interpolation */
:
@@ -3611,7 +3611,8 @@ void psys_mat_hair_to_global(
/************************************************/
/* ParticleSettings handling */
/************************************************/
-ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob, const char *name)
+static ModifierData *object_add_or_copy_particle_system(
+ Main *bmain, Scene *scene, Object *ob, const char *name, const ParticleSystem *psys_orig)
{
ParticleSystem *psys;
ModifierData *md;
@@ -3622,7 +3623,7 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
}
if (name == NULL) {
- name = DATA_("ParticleSettings");
+ name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSettings");
}
psys = ob->particlesystem.first;
@@ -3635,8 +3636,13 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
BLI_addtail(&ob->particlesystem, psys);
psys_unique_name(ob, psys, name);
- psys->part = BKE_particlesettings_add(bmain, psys->name);
-
+ if (psys_orig != NULL) {
+ psys->part = psys_orig->part;
+ id_us_plus(&psys->part->id);
+ }
+ else {
+ psys->part = BKE_particlesettings_add(bmain, psys->name);
+ }
md = BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(md->name, psys->name, sizeof(md->name));
BKE_modifier_unique_name(&ob->modifiers, md);
@@ -3656,6 +3662,20 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
return md;
}
+
+ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob, const char *name)
+{
+ return object_add_or_copy_particle_system(bmain, scene, ob, name, NULL);
+}
+
+ModifierData *object_copy_particle_system(Main *bmain,
+ Scene *scene,
+ Object *ob,
+ const ParticleSystem *psys_orig)
+{
+ return object_add_or_copy_particle_system(bmain, scene, ob, NULL, psys_orig);
+}
+
void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob)
{
ParticleSystem *psys = psys_get_current(ob);
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 7b9b2484dbe..e0dccd4d14a 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -433,7 +433,7 @@ static void psys_uv_to_w(float u, float v, int quad, float *w)
}
/* Find the index in "sum" array before "value" is crossed. */
-static int distribute_binary_search(float *sum, int n, float value)
+static int distribute_binary_search(const float *sum, int n, float value)
{
int mid, low = 0, high = n - 1;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 4dc4aea04a7..bf9aea81181 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -1939,7 +1939,7 @@ static void sphclassical_density_accum_cb(void *userdata,
return;
}
- /* Smoothing factor. Utilise the Wendland kernel. gnuplot:
+ /* Smoothing factor. Utilize the Wendland kernel. gnuplot:
* q1(x) = (2.0 - x)**4 * ( 1.0 + 2.0 * x)
* plot [0:2] q1(x) */
q = qfac / pow3f(pfr->h) * pow4f(2.0f - rij_h) * (1.0f + 2.0f * rij_h);
@@ -2054,7 +2054,7 @@ static void sphclassical_force_cb(void *sphdata_v,
npressure = stiffness * (pow7f(npa->sphdensity / rest_density) - 1.0f);
- /* First derivative of smoothing factor. Utilise the Wendland kernel.
+ /* First derivative of smoothing factor. Utilize the Wendland kernel.
* gnuplot:
* q2(x) = 2.0 * (2.0 - x)**4 - 4.0 * (2.0 - x)**3 * (1.0 + 2.0 * x)
* plot [0:2] q2(x)
@@ -2947,7 +2947,7 @@ static int collision_response(ParticleSimulationData *sim,
/* get exact velocity right before collision */
madd_v3_v3v3fl(v0, col->ve1, col->acc, dt1);
- /* Convert collider velocity from 1/framestep to 1/s TODO:
+ /* Convert collider velocity from `1/frame_step` to `1/s` TODO:
* here we assume 1 frame step for collision modifier. */
mul_v3_fl(pce->vel, col->inv_timestep);
@@ -4966,6 +4966,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
psys_orig->flag = (psys->flag & ~PSYS_SHARED_CACHES);
psys_orig->cfra = psys->cfra;
psys_orig->recalc = psys->recalc;
+ psys_orig->part->totpart = part->totpart;
}
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 8d7dabf9859..67988427bd2 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -358,7 +358,7 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int
/* Returns the number of visible quads in the nodes' grids. */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
- int *grid_indices,
+ const int *grid_indices,
int totgrid,
int gridsize)
{
@@ -1542,7 +1542,7 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
PBVHUpdateData *data = userdata;
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
- if (node->flag & PBVH_UpdateMask) {
+ if (node->flag & PBVH_UpdateVisibility) {
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES:
pbvh_faces_node_visibility_update(pbvh, node);
@@ -1554,7 +1554,7 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
pbvh_bmesh_node_visibility_update(node);
break;
}
- node->flag &= ~PBVH_UpdateMask;
+ node->flag &= ~PBVH_UpdateVisibility;
}
}
@@ -1772,6 +1772,11 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
}
}
+bool BKE_pbvh_node_fully_hidden_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyHidden);
+}
+
void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked)
{
BLI_assert(node->flag & PBVH_Leaf);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 61308810191..9a9d8dc215b 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -206,7 +206,7 @@ static int ptcache_softbody_write(int index, void *soft_v, void **data, int UNUS
return 1;
}
static void ptcache_softbody_read(
- int index, void *soft_v, void **data, float UNUSED(cfra), float *old_data)
+ int index, void *soft_v, void **data, float UNUSED(cfra), const float *old_data)
{
SoftBody *soft = soft_v;
BodyPoint *bp = soft->bpoint + index;
@@ -220,8 +220,13 @@ static void ptcache_softbody_read(
PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, bp->vec);
}
}
-static void ptcache_softbody_interpolate(
- int index, void *soft_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_softbody_interpolate(int index,
+ void *soft_v,
+ void **data,
+ float cfra,
+ float cfra1,
+ float cfra2,
+ const float *old_data)
{
SoftBody *soft = soft_v;
BodyPoint *bp = soft->bpoint + index;
@@ -316,7 +321,7 @@ static int ptcache_particle_write(int index, void *psys_v, void **data, int cfra
return 1 + (pa->state.time >= pa->time && pa->prev_state.time <= pa->time);
}
static void ptcache_particle_read(
- int index, void *psys_v, void **data, float cfra, float *old_data)
+ int index, void *psys_v, void **data, float cfra, const float *old_data)
{
ParticleSystem *psys = psys_v;
ParticleData *pa;
@@ -383,8 +388,13 @@ static void ptcache_particle_read(
unit_qt(pa->state.rot);
}
}
-static void ptcache_particle_interpolate(
- int index, void *psys_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_particle_interpolate(int index,
+ void *psys_v,
+ void **data,
+ float cfra,
+ float cfra1,
+ float cfra2,
+ const float *old_data)
{
ParticleSystem *psys = psys_v;
ParticleData *pa;
@@ -528,7 +538,7 @@ static int ptcache_cloth_write(int index, void *cloth_v, void **data, int UNUSED
return 1;
}
static void ptcache_cloth_read(
- int index, void *cloth_v, void **data, float UNUSED(cfra), float *old_data)
+ int index, void *cloth_v, void **data, float UNUSED(cfra), const float *old_data)
{
ClothModifierData *clmd = cloth_v;
Cloth *cloth = clmd->clothObject;
@@ -545,8 +555,13 @@ static void ptcache_cloth_read(
PTCACHE_DATA_TO(data, BPHYS_DATA_XCONST, 0, vert->xconst);
}
}
-static void ptcache_cloth_interpolate(
- int index, void *cloth_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_cloth_interpolate(int index,
+ void *cloth_v,
+ void **data,
+ float cfra,
+ float cfra1,
+ float cfra2,
+ const float *old_data)
{
ClothModifierData *clmd = cloth_v;
Cloth *cloth = clmd->clothObject;
@@ -1509,7 +1524,7 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSE
return 1;
}
static void ptcache_rigidbody_read(
- int index, void *rb_v, void **data, float UNUSED(cfra), float *old_data)
+ int index, void *rb_v, void **data, float UNUSED(cfra), const float *old_data)
{
RigidBodyWorld *rbw = rb_v;
Object *ob = NULL;
@@ -1534,8 +1549,13 @@ static void ptcache_rigidbody_read(
}
}
}
-static void ptcache_rigidbody_interpolate(
- int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_rigidbody_interpolate(int index,
+ void *rb_v,
+ void **data,
+ float cfra,
+ float cfra1,
+ float cfra2,
+ const float *old_data)
{
RigidBodyWorld *rbw = rb_v;
Object *ob = NULL;
@@ -1887,7 +1907,7 @@ static int ptcache_sim_particle_write(int index, void *state_v, void **data, int
return 1;
}
static void ptcache_sim_particle_read(
- int index, void *state_v, void **data, float UNUSED(cfra), float *UNUSED(old_data))
+ int index, void *state_v, void **data, float UNUSED(cfra), const float *UNUSED(old_data))
{
ParticleSimulationState *state = (ParticleSimulationState *)state_v;
@@ -1898,19 +1918,13 @@ static void ptcache_sim_particle_read(
PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, positions + (index * 3));
}
-void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, ParticleSimulationState *state)
+void BKE_ptcache_id_from_sim_particles(PTCacheID *pid,
+ ParticleSimulationState *state_orig,
+ ParticleSimulationState *state_cow)
{
memset(pid, 0, sizeof(PTCacheID));
- ParticleSimulationState *state_orig;
- if (state->head.orig_state != NULL) {
- state_orig = (ParticleSimulationState *)state->head.orig_state;
- }
- else {
- state_orig = state;
- }
-
- pid->calldata = state;
+ pid->calldata = state_cow;
pid->type = PTCACHE_TYPE_SIM_PARTICLES;
pid->cache = state_orig->point_cache;
pid->cache_ptr = &state_orig->point_cache;
@@ -2050,11 +2064,7 @@ static bool foreach_object_modifier_ptcache(Object *object,
LISTBASE_FOREACH (SimulationState *, state, &smd->simulation->states) {
switch ((eSimulationStateType)state->type) {
case SIM_STATE_TYPE_PARTICLES: {
- ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
- BKE_ptcache_id_from_sim_particles(&pid, particle_state);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
+ /* TODO(jacques) */
break;
}
}
@@ -2289,7 +2299,9 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
return len; /* make sure the above string is always 16 chars */
}
-/* youll need to close yourself after! */
+/**
+ * Caller must close after!
+ */
static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
{
PTCacheFile *pf;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 7f3d6eb0372..5ae2f4b9005 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -581,7 +581,11 @@ static void scene_foreach_cache(ID *id,
.cache_v = scene->eevee.light_cache_data,
};
- function_callback(id, &key, (void **)&scene->eevee.light_cache_data, user_data);
+ function_callback(id,
+ &key,
+ (void **)&scene->eevee.light_cache_data,
+ IDTYPE_CACHE_CB_FLAGS_PERSISTENT,
+ user_data);
}
IDTypeInfo IDType_ID_SCE = {
@@ -766,7 +770,6 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src)
Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
{
- const bool is_scene_liboverride = ID_IS_OVERRIDE_LIBRARY(sce);
Scene *sce_copy;
/* TODO this should/could most likely be replaced by call to more generic code at some point...
@@ -837,15 +840,13 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
return sce_copy;
}
else {
- const eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT;
+ eDupli_ID_Flags duplicate_flags = U.dupflag | USER_DUP_OBJECT;
BKE_id_copy(bmain, (ID *)sce, (ID **)&sce_copy);
id_us_min(&sce_copy->id);
id_us_ensure_real(&sce_copy->id);
- if (duplicate_flags & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &sce_copy->id, true);
- }
+ BKE_animdata_duplicate_id_action(bmain, &sce_copy->id, duplicate_flags);
/* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks. */
@@ -856,22 +857,26 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
if (!is_subprocess) {
BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
BKE_main_id_clear_newpoins(bmain);
+ /* In case root duplicated ID is linked, assume we want to get a local copy of it and
+ * duplicate all expected linked data. */
+ if (ID_IS_LINKED(sce)) {
+ duplicate_flags |= USER_DUP_LINKED_ID;
+ }
}
/* Copy Freestyle LineStyle datablocks. */
LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
LISTBASE_FOREACH (
FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
- BKE_id_copy_for_duplicate(
- bmain, &lineset->linestyle->id, is_scene_liboverride, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)lineset->linestyle, duplicate_flags);
}
}
/* Full copy of world (included animations) */
- BKE_id_copy_for_duplicate(bmain, &sce->world->id, is_scene_liboverride, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)sce->world, duplicate_flags);
/* Full copy of GreasePencil. */
- BKE_id_copy_for_duplicate(bmain, &sce->gpd->id, is_scene_liboverride, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)sce->gpd, duplicate_flags);
/* Deep-duplicate collections and objects (using preferences' settings for which sub-data to
* duplicate along the object itself). */
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index de233a8d473..4a2ad88bb28 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -2668,7 +2668,7 @@ static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int heig
}
static void RVIsolateHighlights_float(
- float *in, float *out, int width, int height, float threshold, float boost, float clamp)
+ const float *in, float *out, int width, int height, float threshold, float boost, float clamp)
{
int x, y, index;
float intensity;
@@ -3423,7 +3423,7 @@ static void do_gaussian_blur_effect_byte_x(Sequence *seq,
int y,
int frame_width,
int UNUSED(frame_height),
- unsigned char *rect,
+ const unsigned char *rect,
unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
@@ -3473,7 +3473,7 @@ static void do_gaussian_blur_effect_byte_y(Sequence *seq,
int y,
int UNUSED(frame_width),
int frame_height,
- unsigned char *rect,
+ const unsigned char *rect,
unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 604cbf476a8..a630170d6d5 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -57,7 +57,7 @@ typedef void (*modifier_apply_threaded_cb)(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v);
typedef struct ModifierInitData {
@@ -223,7 +223,7 @@ static void whiteBalance_apply_threaded(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v)
{
int x, y;
@@ -331,7 +331,7 @@ static void curves_apply_threaded(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v)
{
CurveMapping *curve_mapping = (CurveMapping *)data_v;
@@ -461,7 +461,7 @@ static void hue_correct_apply_threaded(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v)
{
CurveMapping *curve_mapping = (CurveMapping *)data_v;
@@ -556,7 +556,7 @@ static void brightcontrast_apply_threaded(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v)
{
BrightContrastThreadData *data = (BrightContrastThreadData *)data_v;
@@ -658,7 +658,7 @@ static void maskmodifier_apply_threaded(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *UNUSED(data_v))
{
int x, y;
@@ -755,7 +755,7 @@ static void tonemapmodifier_apply_threaded_simple(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v)
{
AvgLogLum *avg = (AvgLogLum *)data_v;
@@ -814,7 +814,7 @@ static void tonemapmodifier_apply_threaded_photoreceptor(int width,
unsigned char *rect,
float *rect_float,
unsigned char *mask_rect,
- float *mask_rect_float,
+ const float *mask_rect_float,
void *data_v)
{
AvgLogLum *avg = (AvgLogLum *)data_v;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 297d60e5976..7339c887151 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -114,8 +114,7 @@ static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
float cfra,
clock_t begin,
bool use_preprocess,
- const bool is_proxy_image,
- const bool is_preprocessed);
+ const bool is_proxy_image);
static ImBuf *seq_render_strip(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -1091,6 +1090,64 @@ void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, cons
BKE_sequence_calc(scene, seq);
}
+void BKE_sequence_movie_reload_if_needed(struct Main *bmain,
+ struct Scene *scene,
+ struct Sequence *seq,
+ bool *r_was_reloaded,
+ bool *r_can_produce_frames)
+{
+ BLI_assert(seq->type == SEQ_TYPE_MOVIE ||
+ !"This function is only implemented for movie strips.");
+
+ bool must_reload = false;
+
+ /* The Sequence struct allows for multiple anim structs to be associated with one strip. This
+ * function will return true only if there is at least one 'anim' AND all anims can produce
+ * frames. */
+
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ /* No anim present, so reloading is always necessary. */
+ must_reload = true;
+ }
+ else {
+ LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
+ if (!IMB_anim_can_produce_frames(sanim->anim)) {
+ /* Anim cannot produce frames, try reloading. */
+ must_reload = true;
+ break;
+ }
+ };
+ }
+
+ if (!must_reload) {
+ /* There are one or more anims, and all can produce frames. */
+ *r_was_reloaded = false;
+ *r_can_produce_frames = true;
+ return;
+ }
+
+ BKE_sequence_reload_new_file(bmain, scene, seq, true);
+ *r_was_reloaded = true;
+
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ /* No anims present after reloading => no frames can be produced. */
+ *r_can_produce_frames = false;
+ return;
+ }
+
+ /* Check if there are still anims that cannot produce frames. */
+ LISTBASE_FOREACH (StripAnim *, sanim, &seq->anims) {
+ if (!IMB_anim_can_produce_frames(sanim->anim)) {
+ /* There still is an anim that cannot produce frames. */
+ *r_can_produce_frames = false;
+ return;
+ }
+ };
+
+ /* There are one or more anims, and all can produce frames. */
+ *r_can_produce_frames = true;
+}
+
void BKE_sequencer_sort(Scene *scene)
{
/* all strips together per kind, and in order of y location ("machine") */
@@ -1332,30 +1389,6 @@ ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset)
/*********************** DO THE SEQUENCE *************************/
-static void make_black_ibuf(ImBuf *ibuf)
-{
- unsigned int *rect;
- float *rect_float;
- int tot;
-
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- return;
- }
-
- tot = ibuf->x * ibuf->y;
-
- rect = ibuf->rect;
- rect_float = ibuf->rect_float;
-
- if (rect) {
- memset(rect, 0, tot * sizeof(char) * 4);
- }
-
- if (rect_float) {
- memset(rect_float, 0, tot * sizeof(float) * 4);
- }
-}
-
static void multibuf(ImBuf *ibuf, const float fmul)
{
char *rt;
@@ -2415,7 +2448,7 @@ static void color_balance_byte_float(StripColorBalance *cb_,
static void color_balance_float_float(StripColorBalance *cb_,
float *rect_float,
- float *mask_rect_float,
+ const float *mask_rect_float,
int width,
int height,
float mul)
@@ -2657,8 +2690,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
Sequence *seq,
float cfra,
ImBuf *ibuf,
- const bool is_proxy_image,
- const bool is_preprocessed)
+ const bool is_proxy_image)
{
Scene *scene = context->scene;
float mul;
@@ -2672,15 +2704,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
if (seq->flag & (SEQ_USE_CROP | SEQ_USE_TRANSFORM)) {
StripCrop c = {0};
StripTransform t = {0};
- int sx, sy, dx, dy;
-
- if (is_proxy_image) {
- double f = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
-
- if (f != 1.0) {
- IMB_scalefastImBuf(ibuf, ibuf->x * f, ibuf->y * f);
- }
- }
if (seq->flag & SEQ_USE_CROP && seq->strip->crop) {
c = *seq->strip->crop;
@@ -2689,33 +2712,41 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
t = *seq->strip->transform;
}
- if (is_preprocessed) {
- double xscale = scene->r.xsch ? ((double)context->rectx / (double)scene->r.xsch) : 1.0;
- double yscale = scene->r.ysch ? ((double)context->recty / (double)scene->r.ysch) : 1.0;
- if (seq->flag & SEQ_USE_TRANSFORM) {
- t.xofs *= xscale;
- t.yofs *= yscale;
+ /* Calculate scale factor for current image if needed. */
+ double scale_factor, image_scale_factor = 1.0;
+ if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
+ scale_factor = image_scale_factor = (double)scene->r.size / 100;
+ }
+ else {
+ scale_factor = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
+ if (!is_proxy_image) {
+ image_scale_factor = scale_factor;
}
- if (seq->flag & SEQ_USE_CROP) {
- c.left *= xscale;
- c.right *= xscale;
- c.top *= yscale;
- c.bottom *= yscale;
+ }
+
+ if (image_scale_factor != 1.0) {
+ if (context->for_render) {
+ IMB_scaleImBuf(ibuf, ibuf->x * image_scale_factor, ibuf->y * image_scale_factor);
+ }
+ else {
+ IMB_scalefastImBuf(ibuf, ibuf->x * image_scale_factor, ibuf->y * image_scale_factor);
}
}
+ t.xofs *= scale_factor;
+ t.yofs *= scale_factor;
+ c.left *= scale_factor;
+ c.right *= scale_factor;
+ c.top *= scale_factor;
+ c.bottom *= scale_factor;
+
+ int sx, sy, dx, dy;
sx = ibuf->x - c.left - c.right;
sy = ibuf->y - c.top - c.bottom;
if (seq->flag & SEQ_USE_TRANSFORM) {
- if (is_preprocessed) {
- dx = context->rectx;
- dy = context->recty;
- }
- else {
- dx = scene->r.xsch;
- dy = scene->r.ysch;
- }
+ dx = context->rectx;
+ dy = context->recty;
}
else {
dx = sx;
@@ -2724,19 +2755,15 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
if (c.top + c.bottom >= ibuf->y || c.left + c.right >= ibuf->x || t.xofs >= dx ||
t.yofs >= dy) {
- make_black_ibuf(ibuf);
+ return NULL;
}
- else {
- ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
-
- IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
- sequencer_imbuf_assign_spaces(scene, i);
-
- IMB_metadata_copy(i, ibuf);
- IMB_freeImBuf(ibuf);
- ibuf = i;
- }
+ ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
+ IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
+ sequencer_imbuf_assign_spaces(scene, i);
+ IMB_metadata_copy(i, ibuf);
+ IMB_freeImBuf(ibuf);
+ ibuf = i;
}
if (seq->flag & SEQ_FLIPX) {
@@ -3097,7 +3124,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
if (view_id != context->view_id) {
ibufs_arr[view_id] = seq_render_preprocess_ibuf(
- &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false);
+ &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false);
}
}
@@ -3214,7 +3241,7 @@ static ImBuf *seq_render_movie_strip(
if (view_id != context->view_id) {
ibuf_arr[view_id] = seq_render_preprocess_ibuf(
- &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false, false);
+ &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false);
}
}
@@ -3804,8 +3831,7 @@ static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
float cfra,
clock_t begin,
bool use_preprocess,
- const bool is_proxy_image,
- const bool is_preprocessed)
+ const bool is_proxy_image)
{
if (context->is_proxy_render == false &&
(ibuf->x != context->rectx || ibuf->y != context->recty)) {
@@ -3814,11 +3840,17 @@ static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
if (use_preprocess) {
float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
+
+ /* TODO (Richard): It should be possible to store in cache if image is proxy,
+ * but it adds quite a bit of complexity. Since proxies are fast to read, I would
+ * rather simplify existing code a bit. */
+ if (!is_proxy_image) {
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
+ }
/* Reset timer so we can get partial render time. */
begin = seq_estimate_render_cost_begin();
- ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
+ ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image);
}
float cost = seq_estimate_render_cost_end(context->scene, begin);
@@ -3834,11 +3866,6 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
ImBuf *ibuf = NULL;
bool use_preprocess = false;
bool is_proxy_image = false;
- /* all effects are handled similarly with the exception of speed effect */
- int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT :
- seq->type;
- bool is_preprocessed = !ELEM(
- type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP);
clock_t begin = seq_estimate_render_cost_begin();
@@ -3855,7 +3882,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
if (ibuf) {
use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
ibuf = seq_render_preprocess_ibuf(
- context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image, is_preprocessed);
+ context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image);
}
if (ibuf == NULL) {
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index c4a35141b0d..e163bb8da8d 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -31,6 +31,7 @@
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -44,6 +45,7 @@
#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_multi_function.hh"
#include "BKE_pointcache.h"
#include "BKE_simulation.h"
@@ -51,9 +53,18 @@
#include "BLT_translation.h"
+#include "FN_attributes_ref.hh"
+#include "FN_cpp_types.hh"
+#include "FN_multi_function_network_evaluation.hh"
+#include "FN_multi_function_network_optimization.hh"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+extern "C" {
+void WM_clipboard_text_set(const char *buf, bool selection);
+}
+
static void simulation_init_data(ID *id)
{
Simulation *simulation = (Simulation *)id;
@@ -63,14 +74,6 @@ static void simulation_init_data(ID *id)
bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
simulation->nodetree = ntree;
-
- /* Add a default particle simulation state for now. */
- ParticleSimulationState *state = (ParticleSimulationState *)MEM_callocN(
- sizeof(ParticleSimulationState), __func__);
- CustomData_reset(&state->attributes);
-
- state->point_cache = BKE_ptcache_add(&state->ptcaches);
- BLI_addtail(&simulation->states, state);
}
static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
@@ -89,19 +92,19 @@ static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
}
BLI_listbase_clear(&simulation_dst->states);
+}
- LISTBASE_FOREACH (const SimulationState *, state_src, &simulation_src->states) {
- switch ((eSimulationStateType)state_src->type) {
- case SIM_STATE_TYPE_PARTICLES: {
- ParticleSimulationState *particle_state_dst = (ParticleSimulationState *)MEM_callocN(
- sizeof(ParticleSimulationState), __func__);
- CustomData_reset(&particle_state_dst->attributes);
+static void free_simulation_state_head(SimulationState *state)
+{
+ MEM_freeN(state->name);
+}
- BLI_addtail(&simulation_dst->states, particle_state_dst);
- break;
- }
- }
- }
+static void free_particle_simulation_state(ParticleSimulationState *state)
+{
+ free_simulation_state_head(&state->head);
+ CustomData_free(&state->attributes, state->tot_particles);
+ BKE_ptcache_free_list(&state->ptcaches);
+ MEM_freeN(state);
}
static void simulation_free_data(ID *id)
@@ -119,13 +122,10 @@ static void simulation_free_data(ID *id)
LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) {
switch ((eSimulationStateType)state->type) {
case SIM_STATE_TYPE_PARTICLES: {
- ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
- CustomData_free(&particle_state->attributes, particle_state->tot_particles);
- BKE_ptcache_free_list(&particle_state->ptcaches);
+ free_particle_simulation_state((ParticleSimulationState *)state);
break;
}
}
- MEM_freeN(state);
}
}
@@ -166,59 +166,556 @@ void *BKE_simulation_add(Main *bmain, const char *name)
namespace blender::bke {
-static MutableSpan<float3> get_particle_positions(ParticleSimulationState *state)
-{
- return MutableSpan<float3>(
- (float3 *)CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position"),
- state->tot_particles);
-}
-
static void ensure_attributes_exist(ParticleSimulationState *state)
{
if (CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position") == nullptr) {
CustomData_add_layer_named(
&state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Position");
}
+ if (CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Velocity") == nullptr) {
+ CustomData_add_layer_named(
+ &state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Velocity");
+ }
+ if (CustomData_get_layer_named(&state->attributes, CD_PROP_INT32, "ID") == nullptr) {
+ CustomData_add_layer_named(
+ &state->attributes, CD_PROP_INT32, CD_CALLOC, nullptr, state->tot_particles, "ID");
+ }
}
-static void copy_particle_state_to_cow(ParticleSimulationState *state_orig,
- ParticleSimulationState *state_cow)
+static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow)
{
- ensure_attributes_exist(state_cow);
- CustomData_free(&state_cow->attributes, state_cow->tot_particles);
- CustomData_copy(&state_orig->attributes,
- &state_cow->attributes,
- CD_MASK_ALL,
- CD_DUPLICATE,
- state_orig->tot_particles);
- state_cow->current_frame = state_orig->current_frame;
- state_cow->tot_particles = state_orig->tot_particles;
+ LISTBASE_FOREACH_MUTABLE (SimulationState *, state_cow, &simulation_cow->states) {
+ switch ((eSimulationStateType)state_cow->type) {
+ case SIM_STATE_TYPE_PARTICLES: {
+ BLI_remlink(&simulation_cow->states, state_cow);
+ free_particle_simulation_state((ParticleSimulationState *)state_cow);
+ break;
+ }
+ }
+ }
+ simulation_cow->current_frame = simulation_orig->current_frame;
+
+ LISTBASE_FOREACH (SimulationState *, state_orig, &simulation_orig->states) {
+ switch ((eSimulationStateType)state_orig->type) {
+ case SIM_STATE_TYPE_PARTICLES: {
+ ParticleSimulationState *particle_state_orig = (ParticleSimulationState *)state_orig;
+ ParticleSimulationState *particle_state_cow = (ParticleSimulationState *)MEM_callocN(
+ sizeof(*particle_state_cow), AT);
+ particle_state_cow->tot_particles = particle_state_orig->tot_particles;
+ particle_state_cow->head.name = BLI_strdup(state_orig->name);
+ CustomData_copy(&particle_state_orig->attributes,
+ &particle_state_cow->attributes,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ particle_state_orig->tot_particles);
+ BLI_addtail(&simulation_cow->states, particle_state_cow);
+ break;
+ }
+ }
+ }
}
-static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation)
+static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes(
+ fn::MFNetwork &network, MFNetworkTreeMap &network_map, const DerivedNodeTree &tree)
{
- int current_frame = scene->r.cfra;
+ Span<const DNode *> attribute_dnodes = tree.nodes_by_type("SimulationNodeParticleAttribute");
+ uint amount = attribute_dnodes.size();
+ if (amount == 0) {
+ return {};
+ }
- ParticleSimulationState *state_cow = (ParticleSimulationState *)simulation->states.first;
- ParticleSimulationState *state_orig = (ParticleSimulationState *)state_cow->head.orig_state;
+ Vector<fn::MFInputSocket *> name_sockets;
+ for (const DNode *dnode : attribute_dnodes) {
+ fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0));
+ name_sockets.append(&name_socket);
+ }
- if (current_frame == state_cow->current_frame) {
- return;
+ fn::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()};
+
+ fn::MFParamsBuilder params{network_fn, 1};
+
+ Array<std::string> attribute_names{amount, NoInitialization()};
+ for (uint i : IndexRange(amount)) {
+ params.add_uninitialized_single_output(
+ fn::GMutableSpan(fn::CPPType_string, attribute_names.data() + i, 1));
+ }
+
+ fn::MFContextBuilder context;
+ /* Todo: Check that the names don't depend on dummy nodes. */
+ network_fn.call({0}, params, context);
+
+ Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>>
+ attribute_nodes_by_name_and_type;
+ for (uint i : IndexRange(amount)) {
+ attribute_nodes_by_name_and_type
+ .lookup_or_add_default({attribute_names[i], name_sockets[i]->node().output(0).data_type()})
+ .append(&name_sockets[i]->node());
+ }
+
+ Map<const fn::MFOutputSocket *, std::string> attribute_inputs;
+ for (auto item : attribute_nodes_by_name_and_type.items()) {
+ StringRef attribute_name = item.key.first;
+ fn::MFDataType data_type = item.key.second;
+ Span<fn::MFNode *> nodes = item.value;
+
+ fn::MFOutputSocket &new_attribute_socket = network.add_input(
+ "Attribute '" + attribute_name + "'", data_type);
+ for (fn::MFNode *node : nodes) {
+ network.relink(node->output(0), new_attribute_socket);
+ }
+ network.remove(nodes);
+
+ attribute_inputs.add_new(&new_attribute_socket, attribute_name);
+ }
+
+ return attribute_inputs;
+}
+
+class CustomDataAttributesRef {
+ private:
+ Vector<void *> buffers_;
+ uint size_;
+ std::unique_ptr<fn::AttributesInfo> info_;
+
+ public:
+ CustomDataAttributesRef(CustomData &custom_data, uint size)
+ {
+ fn::AttributesInfoBuilder builder;
+ for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
+ buffers_.append(layer.data);
+ switch (layer.type) {
+ case CD_PROP_INT32: {
+ builder.add<int32_t>(layer.name, 0);
+ break;
+ }
+ case CD_LOCATION: {
+ builder.add<float3>(layer.name, {0, 0, 0});
+ break;
+ }
+ }
+ }
+ info_ = std::make_unique<fn::AttributesInfo>(builder);
+ size_ = size;
+ }
+
+ operator fn::MutableAttributesRef()
+ {
+ return fn::MutableAttributesRef(*info_, buffers_, size_);
+ }
+
+ operator fn::AttributesRef() const
+ {
+ return fn::AttributesRef(*info_, buffers_, size_);
+ }
+};
+
+static std::string dnode_to_path(const DNode &dnode)
+{
+ std::string path;
+ for (const DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
+ path = parent->node_ref().name() + "/" + path;
+ }
+ path = path + dnode.name();
+ return path;
+}
+
+static void remove_unused_states(Simulation *simulation, const VectorSet<std::string> &state_names)
+{
+ LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) {
+ if (!state_names.contains(state->name)) {
+ BLI_remlink(&simulation->states, state);
+ free_particle_simulation_state((ParticleSimulationState *)state);
+ }
+ }
+}
+
+static void reset_states(Simulation *simulation)
+{
+ LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
+ switch ((eSimulationStateType)state->type) {
+ case SIM_STATE_TYPE_PARTICLES: {
+ ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
+ CustomData_free(&particle_state->attributes, particle_state->tot_particles);
+ particle_state->tot_particles = 0;
+ break;
+ }
+ }
+ }
+}
+
+static SimulationState *try_find_state_by_name(Simulation *simulation, StringRef name)
+{
+ LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
+ if (state->name == name) {
+ return state;
+ }
+ }
+ return nullptr;
+}
+
+static void add_missing_particle_states(Simulation *simulation, Span<std::string> state_names)
+{
+ for (StringRefNull name : state_names) {
+ SimulationState *state = try_find_state_by_name(simulation, name);
+ if (state != nullptr) {
+ BLI_assert(state->type == SIM_STATE_TYPE_PARTICLES);
+ continue;
+ }
+
+ ParticleSimulationState *particle_state = (ParticleSimulationState *)MEM_callocN(
+ sizeof(*particle_state), AT);
+ particle_state->head.type = SIM_STATE_TYPE_PARTICLES;
+ particle_state->head.name = BLI_strdup(name.data());
+ CustomData_reset(&particle_state->attributes);
+ particle_state->point_cache = BKE_ptcache_add(&particle_state->ptcaches);
+ BLI_addtail(&simulation->states, particle_state);
+ }
+}
+
+static void reinitialize_empty_simulation_states(Simulation *simulation,
+ const DerivedNodeTree &tree)
+{
+ VectorSet<std::string> state_names;
+ for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) {
+ state_names.add(dnode_to_path(*dnode));
+ }
+
+ remove_unused_states(simulation, state_names);
+ reset_states(simulation);
+ add_missing_particle_states(simulation, state_names);
+}
+
+static void update_simulation_state_list(Simulation *simulation, const DerivedNodeTree &tree)
+{
+ VectorSet<std::string> state_names;
+ for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) {
+ state_names.add(dnode_to_path(*dnode));
+ }
+
+ remove_unused_states(simulation, state_names);
+ add_missing_particle_states(simulation, state_names);
+}
+
+class ParticleFunctionInput {
+ public:
+ virtual ~ParticleFunctionInput() = default;
+ virtual void add_input(fn::AttributesRef attributes,
+ fn::MFParamsBuilder &params,
+ ResourceCollector &resources) const = 0;
+};
+
+class ParticleFunction {
+ private:
+ const fn::MultiFunction *global_fn_;
+ const fn::MultiFunction *per_particle_fn_;
+ Array<const ParticleFunctionInput *> global_inputs_;
+ Array<const ParticleFunctionInput *> per_particle_inputs_;
+ Array<bool> output_is_global_;
+ Vector<uint> global_output_indices_;
+ Vector<uint> per_particle_output_indices_;
+ Vector<fn::MFDataType> output_types_;
+ Vector<StringRefNull> output_names_;
+
+ friend class ParticleFunctionEvaluator;
+
+ public:
+ ParticleFunction(const fn::MultiFunction *global_fn,
+ const fn::MultiFunction *per_particle_fn,
+ Span<const ParticleFunctionInput *> global_inputs,
+ Span<const ParticleFunctionInput *> per_particle_inputs,
+ Span<bool> output_is_global)
+ : global_fn_(global_fn),
+ per_particle_fn_(per_particle_fn),
+ global_inputs_(global_inputs),
+ per_particle_inputs_(per_particle_inputs),
+ output_is_global_(output_is_global)
+ {
+ for (uint i : output_is_global_.index_range()) {
+ if (output_is_global_[i]) {
+ uint param_index = global_inputs_.size() + global_output_indices_.size();
+ fn::MFParamType param_type = global_fn_->param_type(param_index);
+ BLI_assert(param_type.is_output());
+ output_types_.append(param_type.data_type());
+ output_names_.append(global_fn_->param_name(param_index));
+ global_output_indices_.append(i);
+ }
+ else {
+ uint param_index = per_particle_inputs_.size() + per_particle_output_indices_.size();
+ fn::MFParamType param_type = per_particle_fn_->param_type(param_index);
+ BLI_assert(param_type.is_output());
+ output_types_.append(param_type.data_type());
+ output_names_.append(per_particle_fn_->param_name(param_index));
+ per_particle_output_indices_.append(i);
+ }
+ }
+ }
+};
+
+class ParticleFunctionEvaluator {
+ private:
+ ResourceCollector resources_;
+ const ParticleFunction &particle_fn_;
+ IndexMask mask_;
+ fn::MFContextBuilder global_context_;
+ fn::MFContextBuilder per_particle_context_;
+ fn::AttributesRef particle_attributes_;
+ Vector<void *> outputs_;
+ bool is_computed_ = false;
+
+ public:
+ ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
+ IndexMask mask,
+ fn::AttributesRef particle_attributes)
+ : particle_fn_(particle_fn),
+ mask_(mask),
+ particle_attributes_(particle_attributes),
+ outputs_(particle_fn_.output_types_.size(), nullptr)
+ {
+ }
+
+ ~ParticleFunctionEvaluator()
+ {
+ for (uint output_index : outputs_.index_range()) {
+ void *buffer = outputs_[output_index];
+ fn::MFDataType data_type = particle_fn_.output_types_[output_index];
+ BLI_assert(data_type.is_single()); /* For now. */
+ const fn::CPPType &type = data_type.single_type();
+
+ if (particle_fn_.output_is_global_[output_index]) {
+ type.destruct(buffer);
+ }
+ else {
+ type.destruct_indices(outputs_[0], mask_);
+ }
+ }
+ }
+
+ void compute()
+ {
+ BLI_assert(!is_computed_);
+ this->compute_globals();
+ this->compute_per_particle();
+ is_computed_ = true;
+ }
+
+ template<typename T> fn::VSpan<T> get(uint output_index, StringRef expected_name) const
+ {
+ return this->get(output_index, expected_name).typed<T>();
+ }
+
+ fn::GVSpan get(uint output_index, StringRef expected_name) const
+ {
+#ifdef DEBUG
+ StringRef real_name = particle_fn_.output_names_[output_index];
+ BLI_assert(expected_name == real_name);
+ BLI_assert(is_computed_);
+#endif
+ UNUSED_VARS_NDEBUG(expected_name);
+ const void *buffer = outputs_[output_index];
+ const fn::CPPType &type = particle_fn_.output_types_[output_index].single_type();
+ if (particle_fn_.output_is_global_[output_index]) {
+ return fn::GVSpan::FromSingleWithMaxSize(type, buffer);
+ }
+ else {
+ return fn::GVSpan(fn::GSpan(type, buffer, mask_.min_array_size()));
+ }
+ }
+
+ private:
+ void compute_globals()
+ {
+ if (particle_fn_.global_fn_ == nullptr) {
+ return;
+ }
+
+ fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size());
+
+ /* Add input parameters. */
+ for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) {
+ input->add_input(particle_attributes_, params, resources_);
+ }
+
+ /* Add output parameters. */
+ for (uint output_index : particle_fn_.global_output_indices_) {
+ fn::MFDataType data_type = particle_fn_.output_types_[output_index];
+ BLI_assert(data_type.is_single()); /* For now. */
+
+ const fn::CPPType &type = data_type.single_type();
+ void *buffer = resources_.linear_allocator().allocate(type.size(), type.alignment());
+ params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, 1));
+ outputs_[output_index] = buffer;
+ }
+
+ particle_fn_.global_fn_->call({0}, params, global_context_);
+ }
+
+ void compute_per_particle()
+ {
+ if (particle_fn_.per_particle_fn_ == nullptr) {
+ return;
+ }
+
+ fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size());
+
+ /* Add input parameters. */
+ for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) {
+ input->add_input(particle_attributes_, params, resources_);
+ }
+
+ /* Add output parameters. */
+ for (uint output_index : particle_fn_.per_particle_output_indices_) {
+ fn::MFDataType data_type = particle_fn_.output_types_[output_index];
+ BLI_assert(data_type.is_single()); /* For now. */
+
+ const fn::CPPType &type = data_type.single_type();
+ void *buffer = resources_.linear_allocator().allocate(type.size() * mask_.min_array_size(),
+ type.alignment());
+ params.add_uninitialized_single_output(
+ fn::GMutableSpan(type, buffer, mask_.min_array_size()));
+ outputs_[output_index] = buffer;
+ }
+
+ particle_fn_.per_particle_fn_->call(mask_, params, global_context_);
+ }
+};
+
+class ParticleAttributeInput : public ParticleFunctionInput {
+ private:
+ std::string attribute_name_;
+ const fn::CPPType &attribute_type_;
+
+ public:
+ ParticleAttributeInput(std::string attribute_name, const fn::CPPType &attribute_type)
+ : attribute_name_(std::move(attribute_name)), attribute_type_(attribute_type)
+ {
+ }
+
+ void add_input(fn::AttributesRef attributes,
+ fn::MFParamsBuilder &params,
+ ResourceCollector &UNUSED(resources)) const override
+ {
+ std::optional<fn::GSpan> span = attributes.try_get(attribute_name_, attribute_type_);
+ if (span.has_value()) {
+ params.add_readonly_single_input(*span);
+ }
+ else {
+ params.add_readonly_single_input(fn::GVSpan::FromDefault(attribute_type_));
+ }
}
+};
+
+static const ParticleFunction *create_particle_function_for_inputs(
+ Span<const fn::MFInputSocket *> sockets_to_compute,
+ ResourceCollector &resources,
+ const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs)
+{
+ BLI_assert(sockets_to_compute.size() >= 1);
+ const fn::MFNetwork &network = sockets_to_compute[0]->node().network();
+
+ VectorSet<const fn::MFOutputSocket *> dummy_deps;
+ VectorSet<const fn::MFInputSocket *> unlinked_input_deps;
+ network.find_dependencies(sockets_to_compute, dummy_deps, unlinked_input_deps);
+ BLI_assert(unlinked_input_deps.size() == 0);
+
+ Vector<const ParticleFunctionInput *> per_particle_inputs;
+ for (const fn::MFOutputSocket *socket : dummy_deps) {
+ StringRef attribute_name = attribute_inputs.lookup(socket);
+ per_particle_inputs.append(&resources.construct<ParticleAttributeInput>(
+ AT, attribute_name, socket->data_type().single_type()));
+ }
+
+ const fn::MultiFunction &per_particle_fn = resources.construct<fn::MFNetworkEvaluator>(
+ AT, dummy_deps.as_span(), sockets_to_compute);
+
+ Array<bool> output_is_global(sockets_to_compute.size(), false);
+
+ const ParticleFunction &particle_fn = resources.construct<ParticleFunction>(
+ AT,
+ nullptr,
+ &per_particle_fn,
+ Span<const ParticleFunctionInput *>(),
+ per_particle_inputs.as_span(),
+ output_is_global.as_span());
+
+ return &particle_fn;
+}
+
+class ParticleForce {
+ public:
+ virtual ~ParticleForce() = default;
+ virtual void add_force(fn::AttributesRef attributes,
+ MutableSpan<float3> r_combined_force) const = 0;
+};
+
+class ParticleFunctionForce : public ParticleForce {
+ private:
+ const ParticleFunction &particle_fn_;
+
+ public:
+ ParticleFunctionForce(const ParticleFunction &particle_fn) : particle_fn_(particle_fn)
+ {
+ }
+
+ void add_force(fn::AttributesRef attributes, MutableSpan<float3> r_combined_force) const override
+ {
+ IndexMask mask = IndexRange(attributes.size());
+ ParticleFunctionEvaluator evaluator{particle_fn_, mask, attributes};
+ evaluator.compute();
+ fn::VSpan<float3> forces = evaluator.get<float3>(0, "Force");
+ for (uint i : mask) {
+ r_combined_force[i] += forces[i];
+ }
+ }
+};
+
+static Vector<const ParticleForce *> create_forces_for_particle_simulation(
+ const DNode &simulation_node,
+ MFNetworkTreeMap &network_map,
+ ResourceCollector &resources,
+ const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs)
+{
+ Vector<const ParticleForce *> forces;
+ for (const DOutputSocket *origin_socket : simulation_node.input(2, "Forces").linked_sockets()) {
+ const DNode &origin_node = origin_socket->node();
+ if (origin_node.idname() != "SimulationNodeForce") {
+ continue;
+ }
+
+ const fn::MFInputSocket &force_socket = network_map.lookup_dummy(
+ origin_node.input(0, "Force"));
+
+ const ParticleFunction *particle_fn = create_particle_function_for_inputs(
+ {&force_socket}, resources, attribute_inputs);
- /* Number of particles should be stored in the cache, but for now assume it is constant. */
- state_cow->tot_particles = state_orig->tot_particles;
- CustomData_realloc(&state_cow->attributes, state_orig->tot_particles);
- ensure_attributes_exist(state_cow);
+ if (particle_fn == nullptr) {
+ continue;
+ }
+
+ const ParticleForce &force = resources.construct<ParticleFunctionForce>(AT, *particle_fn);
+ forces.append(&force);
+ }
+ return forces;
+}
- PTCacheID pid_cow;
- BKE_ptcache_id_from_sim_particles(&pid_cow, state_cow);
- BKE_ptcache_id_time(&pid_cow, scene, current_frame, nullptr, nullptr, nullptr);
+static Map<std::string, Vector<const ParticleForce *>> collect_forces(
+ MFNetworkTreeMap &network_map,
+ ResourceCollector &resources,
+ const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs)
+{
+ Map<std::string, Vector<const ParticleForce *>> forces_by_simulation;
+ for (const DNode *dnode : network_map.tree().nodes_by_type("SimulationNodeParticleSimulation")) {
+ std::string name = dnode_to_path(*dnode);
+ Vector<const ParticleForce *> forces = create_forces_for_particle_simulation(
+ *dnode, network_map, resources, attribute_inputs);
+ forces_by_simulation.add_new(std::move(name), std::move(forces));
+ }
+ return forces_by_simulation;
+}
- /* If successfull, this will read the state directly into the cow state. */
- int cache_result = BKE_ptcache_read(&pid_cow, current_frame, true);
- if (cache_result == PTCACHE_READ_EXACT) {
- state_cow->current_frame = current_frame;
+static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation_cow)
+{
+ int current_frame = scene->r.cfra;
+ if (simulation_cow->current_frame == current_frame) {
return;
}
@@ -227,34 +724,82 @@ static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulatio
return;
}
- PTCacheID pid_orig;
- BKE_ptcache_id_from_sim_particles(&pid_orig, state_orig);
- BKE_ptcache_id_time(&pid_orig, scene, current_frame, nullptr, nullptr, nullptr);
+ Simulation *simulation_orig = (Simulation *)DEG_get_original_id(&simulation_cow->id);
+
+ NodeTreeRefMap tree_refs;
+ /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */
+ const DerivedNodeTree tree{simulation_orig->nodetree, tree_refs};
+ fn::MFNetwork network;
+ ResourceCollector resources;
+ MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources);
+ // WM_clipboard_text_set(tree.to_dot().c_str(), false);
+ Map<const fn::MFOutputSocket *, std::string> attribute_inputs = deduplicate_attribute_nodes(
+ network, network_map, tree);
+ fn::mf_network_optimization::constant_folding(network, resources);
+ fn::mf_network_optimization::common_subnetwork_elimination(network);
+ fn::mf_network_optimization::dead_node_removal(network);
+
+ Map<std::string, Vector<const ParticleForce *>> forces_by_simulation = collect_forces(
+ network_map, resources, attribute_inputs);
if (current_frame == 1) {
- state_orig->tot_particles = 100;
- state_orig->current_frame = 1;
- CustomData_realloc(&state_orig->attributes, state_orig->tot_particles);
- ensure_attributes_exist(state_orig);
-
- MutableSpan<float3> positions = get_particle_positions(state_orig);
- for (uint i : positions.index_range()) {
- positions[i] = {i / 10.0f, 0, 0};
+ reinitialize_empty_simulation_states(simulation_orig, tree);
+
+ RNG *rng = BLI_rng_new(0);
+
+ simulation_orig->current_frame = 1;
+ LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) {
+ state->tot_particles = 1000;
+ CustomData_realloc(&state->attributes, state->tot_particles);
+ ensure_attributes_exist(state);
+
+ CustomDataAttributesRef custom_data_attributes{state->attributes,
+ (uint)state->tot_particles};
+
+ fn::MutableAttributesRef attributes = custom_data_attributes;
+ MutableSpan<float3> positions = attributes.get<float3>("Position");
+ MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
+ MutableSpan<int32_t> ids = attributes.get<int32_t>("ID");
+
+ for (uint i : positions.index_range()) {
+ positions[i] = {i / 100.0f, 0, 0};
+ velocities[i] = {0, BLI_rng_get_float(rng), BLI_rng_get_float(rng) * 2 + 1};
+ ids[i] = i;
+ }
}
- BKE_ptcache_write(&pid_orig, current_frame);
- copy_particle_state_to_cow(state_orig, state_cow);
+ BLI_rng_free(rng);
+
+ copy_states_to_cow(simulation_orig, simulation_cow);
}
- else if (current_frame == state_orig->current_frame + 1) {
- state_orig->current_frame = current_frame;
- ensure_attributes_exist(state_orig);
- MutableSpan<float3> positions = get_particle_positions(state_orig);
- for (float3 &position : positions) {
- position.z += 0.1f;
+ else if (current_frame == simulation_orig->current_frame + 1) {
+ update_simulation_state_list(simulation_orig, tree);
+ float time_step = 1.0f / 24.0f;
+ simulation_orig->current_frame = current_frame;
+
+ LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) {
+ ensure_attributes_exist(state);
+
+ CustomDataAttributesRef custom_data_attributes{state->attributes,
+ (uint)state->tot_particles};
+
+ fn::MutableAttributesRef attributes = custom_data_attributes;
+ MutableSpan<float3> positions = attributes.get<float3>("Position");
+ MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
+
+ Array<float3> force_vectors{(uint)state->tot_particles, {0, 0, 0}};
+ Span<const ParticleForce *> forces = forces_by_simulation.lookup_as(state->head.name);
+ for (const ParticleForce *force : forces) {
+ force->add_force(attributes, force_vectors);
+ }
+
+ for (uint i : positions.index_range()) {
+ velocities[i] += force_vectors[i] * time_step;
+ positions[i] += velocities[i] * time_step;
+ }
}
- BKE_ptcache_write(&pid_orig, current_frame);
- copy_particle_state_to_cow(state_orig, state_cow);
+ copy_states_to_cow(simulation_orig, simulation_cow);
}
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 75da92a26b8..b7b325644ca 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -165,24 +165,28 @@ static void free_softbody_intern(SoftBody *sb);
/*physical unit of force is [kg * m / sec^2]*/
-static float sb_grav_force_scale(Object *UNUSED(ob))
-/* since unit of g is [m/sec^2] and F = mass * g we rescale unit mass of node to 1 gramm
- * put it to a function here, so we can add user options later without touching simulation code
+/**
+ * Since unit of g is [m/sec^2] and F = mass * g we re-scale unit mass of node to 1 gram
+ * put it to a function here, so we can add user options later without touching simulation code.
*/
+static float sb_grav_force_scale(Object *UNUSED(ob))
{
return (0.001f);
}
-static float sb_fric_force_scale(Object *UNUSED(ob))
-/* rescaling unit of drag [1 / sec] to somehow reasonable
- * put it to a function here, so we can add user options later without touching simulation code
+/**
+ * Re-scaling unit of drag [1 / sec] to somehow reasonable
+ * put it to a function here, so we can add user options later without touching simulation code.
*/
+static float sb_fric_force_scale(Object *UNUSED(ob))
{
return (0.01f);
}
+/**
+ * Defining the frames to *real* time relation.
+ */
static float sb_time_scale(Object *ob)
-/* defining the frames to *real* time relation */
{
SoftBody *sb = ob->soft; /* is supposed to be there */
if (sb) {
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 18fd8a10cc1..1fcfc9b060f 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -123,7 +123,7 @@ static void sound_foreach_cache(ID *id,
.cache_v = sound->waveform,
};
- function_callback(id, &key, &sound->waveform, user_data);
+ function_callback(id, &key, &sound->waveform, 0, user_data);
}
IDTypeInfo IDType_ID_SO = {
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index a1e218390c3..22649a2af07 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -1834,4 +1834,59 @@ const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG *subdiv_ccg)
return subdiv_ccg->cache_.start_face_grid_index;
}
+static void adjacet_vertices_index_from_adjacent_edge(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const MLoop *mloop,
+ const MPoly *mpoly,
+ int *r_v1,
+ int *r_v2)
+{
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ const int poly_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord->grid_index);
+ const MPoly *p = &mpoly[poly_index];
+ *r_v1 = mloop[coord->grid_index].v;
+ if (coord->x == grid_size_1) {
+ const MLoop *next = ME_POLY_LOOP_NEXT(mloop, p, coord->grid_index);
+ *r_v2 = next->v;
+ }
+ if (coord->y == grid_size_1) {
+ const MLoop *prev = ME_POLY_LOOP_PREV(mloop, p, coord->grid_index);
+ *r_v2 = prev->v;
+ }
+}
+
+SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const MLoop *mloop,
+ const MPoly *mpoly,
+ int *r_v1,
+ int *r_v2)
+{
+
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ if (is_corner_grid_coord(subdiv_ccg, coord)) {
+ if (coord->x == 0 && coord->y == 0) {
+ /* Grid corner in the center of a poly. */
+ return SUBDIV_CCG_ADJACENT_NONE;
+ }
+ if (coord->x == grid_size_1 && coord->y == grid_size_1) {
+ /* Grid corner adjacent to a coarse mesh vertex. */
+ *r_v1 = *r_v2 = mloop[coord->grid_index].v;
+ return SUBDIV_CCG_ADJACENT_VERTEX;
+ }
+ /* Grid corner adjacent to the middle of a coarse mesh edge. */
+ adjacet_vertices_index_from_adjacent_edge(subdiv_ccg, coord, mloop, mpoly, r_v1, r_v2);
+ return SUBDIV_CCG_ADJACENT_EDGE;
+ }
+
+ if (is_boundary_grid_coord(subdiv_ccg, coord)) {
+ if (!is_inner_edge_grid_coordinate(subdiv_ccg, coord)) {
+ /* Grid boundary adjacent to a coarse mesh edge. */
+ adjacet_vertices_index_from_adjacent_edge(subdiv_ccg, coord, mloop, mpoly, r_v1, r_v2);
+ return SUBDIV_CCG_ADJACENT_EDGE;
+ }
+ }
+ return SUBDIV_CCG_ADJACENT_NONE;
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index e155dedeef0..0809e8dda6d 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -507,9 +507,7 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
/* Might not be final place for this to be called - probably only want to call it from some
* undo handlers, not all of them? */
- if (BKE_lib_override_library_is_enabled()) {
- BKE_lib_override_library_main_operations_create(G_MAIN, false);
- }
+ BKE_lib_override_library_main_operations_create(G_MAIN, false);
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
while (ustack->steps.last != ustack->step_active) {
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 18859869b4e..48b920c8a05 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -494,7 +494,7 @@ static void volume_foreach_cache(ID *id,
/* cache_v */ volume->runtime.grids,
};
- function_callback(id, &key, (void **)&volume->runtime.grids, user_data);
+ function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
}
IDTypeInfo IDType_ID_VO = {
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index ee4e9702779..c411fc50f15 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -74,7 +74,7 @@ class Array {
Allocator allocator_;
/** A placeholder buffer that will remain uninitialized until it is used. */
- AlignedBuffer<sizeof(T) * InlineBufferCapacity, alignof(T)> inline_buffer_;
+ TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
public:
/**
@@ -82,23 +82,29 @@ class Array {
*/
Array()
{
- data_ = this->inline_buffer();
+ data_ = inline_buffer_;
size_ = 0;
}
/**
* Create a new array that contains copies of all values.
*/
- Array(Span<T> values)
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Array(Span<U> values, Allocator allocator = {}) : allocator_(allocator)
{
size_ = values.size();
data_ = this->get_buffer_for_size(values.size());
- uninitialized_copy_n(values.data(), size_, data_);
+ uninitialized_convert_n<U, T>(values.data(), size_, data_);
}
/**
* Create a new array that contains copies of all values.
*/
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Array(const std::initializer_list<U> &values) : Array(Span<U>(values))
+ {
+ }
+
Array(const std::initializer_list<T> &values) : Array(Span<T>(values))
{
}
@@ -147,12 +153,8 @@ class Array {
data_ = this->get_buffer_for_size(size);
}
- Array(const Array &other) : allocator_(other.allocator_)
+ Array(const Array &other) : Array(other.as_span(), other.allocator_)
{
- size_ = other.size();
-
- data_ = this->get_buffer_for_size(other.size());
- uninitialized_copy_n(other.data(), size_, data_);
}
Array(Array &&other) noexcept : allocator_(other.allocator_)
@@ -167,7 +169,7 @@ class Array {
uninitialized_relocate_n(other.data_, size_, data_);
}
- other.data_ = other.inline_buffer();
+ other.data_ = other.inline_buffer_;
other.size_ = 0;
}
@@ -223,6 +225,18 @@ class Array {
return MutableSpan<T>(data_, size_);
}
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator Span<U>() const
+ {
+ return Span<U>(data_, size_);
+ }
+
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator MutableSpan<U>()
+ {
+ return MutableSpan<U>(data_, size_);
+ }
+
Span<T> as_span() const
{
return *this;
@@ -335,18 +349,13 @@ class Array {
T *get_buffer_for_size(uint size)
{
if (size <= InlineBufferCapacity) {
- return this->inline_buffer();
+ return inline_buffer_;
}
else {
return this->allocate(size);
}
}
- T *inline_buffer() const
- {
- return (T *)inline_buffer_.ptr();
- }
-
T *allocate(uint size)
{
return (T *)allocator_.allocate(size * sizeof(T), alignof(T), AT);
@@ -354,7 +363,7 @@ class Array {
bool uses_inline_buffer() const
{
- return data_ == this->inline_buffer();
+ return data_ == inline_buffer_;
}
};
diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h
index 6dd1abacf78..4ebef814337 100644
--- a/source/blender/blenlib/BLI_blenlib.h
+++ b/source/blender/blenlib/BLI_blenlib.h
@@ -28,7 +28,7 @@
* a call to a BLI function that is not prototyped here, please add a
* prototype here. The library offers mathematical operations (mainly
* vector and matrix calculus), an abstraction layer for file i/o,
- * functions for calculating Perlin noise, scanfilling services for
+ * functions for calculating Perlin noise, scan-filling services for
* triangles, and a system for guarded memory
* allocation/deallocation. There is also a patch to make MS Windows
* behave more or less Posix-compliant.
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index 37f74edcf4c..265013c0013 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -51,6 +51,25 @@ struct Color4f {
stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
return stream;
}
+
+ friend bool operator==(const Color4f &a, const Color4f &b)
+ {
+ return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
+ }
+
+ friend bool operator!=(const Color4f &a, const Color4f &b)
+ {
+ return !(a == b);
+ }
+
+ uint32_t hash() const
+ {
+ uint32_t x1 = *(uint32_t *)&r;
+ uint32_t x2 = *(uint32_t *)&g;
+ uint32_t x3 = *(uint32_t *)&b;
+ uint32_t x4 = *(uint32_t *)&a;
+ return (x1 * 1283591) ^ (x2 * 850177) ^ (x3 * 735391) ^ (x4 * 442319);
+ }
};
struct Color4b {
@@ -89,6 +108,22 @@ struct Color4b {
stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
return stream;
}
+
+ friend bool operator==(const Color4b &a, const Color4b &b)
+ {
+ return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
+ }
+
+ friend bool operator!=(const Color4b &a, const Color4b &b)
+ {
+ return !(a == b);
+ }
+
+ uint32_t hash() const
+ {
+ return ((uint32_t)r * 1283591) ^ ((uint32_t)g * 850177) ^ ((uint32_t)b * 735391) ^
+ ((uint32_t)a * 442319);
+ }
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_disjoint_set.hh b/source/blender/blenlib/BLI_disjoint_set.hh
new file mode 100644
index 00000000000..3b8453669aa
--- /dev/null
+++ b/source/blender/blenlib/BLI_disjoint_set.hh
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_DISJOINT_SET_HH__
+#define __BLI_DISJOINT_SET_HH__
+
+/** \file
+ * \ingroup bli
+ *
+ * This implements the disjoint set data structure with path compression and union by rank.
+ */
+
+#include "BLI_array.hh"
+
+namespace blender {
+
+class DisjointSet {
+ private:
+ Array<uint> parents_;
+ Array<uint> ranks_;
+
+ public:
+ /**
+ * Create a new disjoint set with the given size. Initially, every element is in a separate set.
+ */
+ DisjointSet(uint size) : parents_(size), ranks_(size, 0)
+ {
+ for (uint i = 0; i < size; i++) {
+ parents_[i] = i;
+ }
+ }
+
+ /**
+ * Join the sets containing elements x and y. Nothing happens when they have been in the same set
+ * before.
+ */
+ void join(uint x, uint y)
+ {
+ uint root1 = this->find_root(x);
+ uint root2 = this->find_root(y);
+
+ /* x and y are in the same set already. */
+ if (root1 == root2) {
+ return;
+ }
+
+ /* Implement union by rank heuristic. */
+ if (ranks_[root1] < ranks_[root2]) {
+ std::swap(root1, root2);
+ }
+ parents_[root2] = root1;
+
+ if (ranks_[root1] == ranks_[root2]) {
+ ranks_[root1]++;
+ }
+ }
+
+ /**
+ * Return true when x and y are in the same set.
+ */
+ bool in_same_set(uint x, uint y)
+ {
+ uint root1 = this->find_root(x);
+ uint root2 = this->find_root(y);
+ return root1 == root2;
+ }
+
+ /**
+ * Find the element that represents the set containing x currently.
+ */
+ uint find_root(uint x)
+ {
+ /* Find root by following parents. */
+ uint root = x;
+ while (parents_[root] != root) {
+ root = parents_[root];
+ }
+
+ /* Compress path. */
+ while (parents_[x] != root) {
+ uint parent = parents_[x];
+ parents_[x] = root;
+ x = parent;
+ }
+
+ return root;
+ }
+};
+
+} // namespace blender
+
+#endif /* __BLI_DISJOINT_SET_HH__ */
diff --git a/source/blender/blenlib/BLI_dot_export.hh b/source/blender/blenlib/BLI_dot_export.hh
index 450cb2ef58c..a7c5f1436d1 100644
--- a/source/blender/blenlib/BLI_dot_export.hh
+++ b/source/blender/blenlib/BLI_dot_export.hh
@@ -269,6 +269,11 @@ class NodeWithSocketsRef {
Span<std::string> input_names,
Span<std::string> output_names);
+ Node &node()
+ {
+ return *node_;
+ }
+
NodePort input(uint index) const
{
std::string port = "\"in" + std::to_string(index) + "\"";
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
index 94da5d18ad2..5fe9d1b8ca9 100644
--- a/source/blender/blenlib/BLI_float2.hh
+++ b/source/blender/blenlib/BLI_float2.hh
@@ -48,6 +48,34 @@ struct float2 {
return &x;
}
+ float2 &operator+=(const float2 &other)
+ {
+ x += other.x;
+ y += other.y;
+ return *this;
+ }
+
+ float2 &operator-=(const float2 &other)
+ {
+ x -= other.x;
+ y -= other.y;
+ return *this;
+ }
+
+ float2 &operator*=(float factor)
+ {
+ x *= factor;
+ y *= factor;
+ return *this;
+ }
+
+ float2 &operator/=(float divisor)
+ {
+ x /= divisor;
+ y /= divisor;
+ return *this;
+ }
+
friend float2 operator+(const float2 &a, const float2 &b)
{
return {a.x + b.x, a.y + b.y};
@@ -79,6 +107,16 @@ struct float2 {
stream << "(" << v.x << ", " << v.y << ")";
return stream;
}
+
+ friend bool operator==(const float2 &a, const float2 &b)
+ {
+ return a.x == b.x && a.y == b.y;
+ }
+
+ friend bool operator!=(const float2 &a, const float2 &b)
+ {
+ return !(a == b);
+ }
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
index 0edee600ef6..a36cedad41d 100644
--- a/source/blender/blenlib/BLI_float3.hh
+++ b/source/blender/blenlib/BLI_float3.hh
@@ -128,6 +128,16 @@ struct float3 {
return stream;
}
+ friend bool operator==(const float3 &a, const float3 &b)
+ {
+ return a.x == b.x && a.y == b.y && a.z == b.z;
+ }
+
+ friend bool operator!=(const float3 &a, const float3 &b)
+ {
+ return !(a == b);
+ }
+
float normalize_and_get_length()
{
return normalize_v3(*this);
@@ -178,6 +188,14 @@ struct float3 {
z = -z;
}
+ uint32_t hash() const
+ {
+ uint32_t x1 = *(uint32_t *)&x;
+ uint32_t x2 = *(uint32_t *)&y;
+ uint32_t x3 = *(uint32_t *)&z;
+ return (x1 * 435109) ^ (x2 * 380867) ^ (x3 * 1059217);
+ }
+
static float dot(const float3 &a, const float3 &b)
{
return a.x * b.x + a.y * b.y + a.z * b.z;
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
index 1e9bd12b12b..ef83f9ffc19 100644
--- a/source/blender/blenlib/BLI_float4x4.hh
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -108,6 +108,16 @@ struct float4x4 {
interp_m4_m4m4(result, a.values, b.values, t);
return result;
}
+
+ uint32_t hash() const
+ {
+ uint32_t h = 435109;
+ for (uint i = 0; i < 16; i++) {
+ float value = ((const float *)this)[i];
+ h = h * 33 + (*(uint32_t *)&value);
+ }
+ return h;
+ }
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 141c631381b..31a9658bd7e 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -371,20 +371,6 @@ unsigned int BLI_ghashutil_uinthash_v4_murmur(const unsigned int key[4]);
bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b);
#define BLI_ghashutil_inthash_v4_cmp BLI_ghashutil_uinthash_v4_cmp
-unsigned int BLI_ghashutil_uinthash_v2(const unsigned int key[2]);
-#define BLI_ghashutil_inthash_v2(key) \
- (CHECK_TYPE_ANY(key, int *, const int *), BLI_ghashutil_uinthash_v2((const unsigned int *)key))
-#define BLI_ghashutil_inthash_v2_p ((GSetHashFP)BLI_ghashutil_uinthash_v2)
-#define BLI_ghashutil_uinthash_v2_p ((GSetHashFP)BLI_ghashutil_uinthash_v2)
-unsigned int BLI_ghashutil_uinthash_v2_murmur(const unsigned int key[2]);
-#define BLI_ghashutil_inthash_v2_murmur(key) \
- (CHECK_TYPE_ANY(key, int *, const int *), \
- BLI_ghashutil_uinthash_v2_murmur((const unsigned int *)key))
-#define BLI_ghashutil_inthash_v2_p_murmur ((GSetHashFP)BLI_ghashutil_uinthash_v2_murmur)
-#define BLI_ghashutil_uinthash_v2_p_murmur ((GSetHashFP)BLI_ghashutil_uinthash_v2_murmur)
-bool BLI_ghashutil_uinthash_v2_cmp(const void *a, const void *b);
-#define BLI_ghashutil_inthash_v2_cmp BLI_ghashutil_uinthash_v2_cmp
-
typedef struct GHashPair {
const void *first;
const void *second;
diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index 49e619ff1bc..5cd4ce3c1a9 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -154,6 +154,13 @@ template<> struct DefaultHash<float> {
}
};
+template<> struct DefaultHash<bool> {
+ uint32_t operator()(bool value) const
+ {
+ return (uint32_t)(value != false) * 1298191;
+ }
+};
+
inline uint32_t hash_string(StringRef str)
{
uint32_t hash = 5381;
diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh
index 5f9e06c5a64..aaed772071d 100644
--- a/source/blender/blenlib/BLI_hash_tables.hh
+++ b/source/blender/blenlib/BLI_hash_tables.hh
@@ -65,13 +65,13 @@ inline constexpr uint32_t power_of_2_max_u_constexpr(const uint32_t x)
template<typename IntT> inline constexpr IntT ceil_division(const IntT x, const IntT y)
{
- BLI_STATIC_ASSERT(!std::is_signed<IntT>::value, "");
+ BLI_STATIC_ASSERT(!std::is_signed_v<IntT>, "");
return x / y + ((x % y) != 0);
}
template<typename IntT> inline constexpr IntT floor_division(const IntT x, const IntT y)
{
- BLI_STATIC_ASSERT(!std::is_signed<IntT>::value, "");
+ BLI_STATIC_ASSERT(!std::is_signed_v<IntT>, "");
return x / y;
}
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 70fa633eeac..9e4e30181b9 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -174,6 +174,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
BVHTree_OverlapCallback callback,
void *userdata);
+int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot);
+
int BLI_bvhtree_get_len(const BVHTree *tree);
int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree);
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 06796d6592a..324da859af1 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -55,6 +55,7 @@ int BLI_linklist_count(const LinkNode *list) ATTR_WARN_UNUSED_RESULT;
int BLI_linklist_index(const LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT;
LinkNode *BLI_linklist_find(LinkNode *list, int index) ATTR_WARN_UNUSED_RESULT;
+LinkNode *BLI_linklist_find_last(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index 0a044afe8af..6bbd4ee09db 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -271,10 +271,6 @@ class Map {
{
return this->add_as(std::move(key), std::move(value));
}
-
- /**
- * Same as `add`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey, typename ForwardValue>
bool add_as(ForwardKey &&key, ForwardValue &&value)
{
@@ -305,10 +301,6 @@ class Map {
{
return this->add_overwrite_as(std::move(key), std::move(value));
}
-
- /**
- * Same as `add_overwrite`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey, typename ForwardValue>
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
{
@@ -325,10 +317,6 @@ class Map {
{
return this->contains_as(key);
}
-
- /**
- * Same as `contains`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
{
return this->contains__impl(key, hash_(key));
@@ -344,10 +332,6 @@ class Map {
{
return this->remove_as(key);
}
-
- /**
- * Same as `remove`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool remove_as(const ForwardKey &key)
{
return this->remove__impl(key, hash_(key));
@@ -361,11 +345,6 @@ class Map {
{
this->remove_contained_as(key);
}
-
- /**
- * Same as `remove_contained`, but accepts other key types that are supported by the hash
- * function.
- */
template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
{
this->remove_contained__impl(key, hash_(key));
@@ -379,10 +358,6 @@ class Map {
{
return this->pop_as(key);
}
-
- /**
- * Same as `pop`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> Value pop_as(const ForwardKey &key)
{
return this->pop__impl(key, hash_(key));
@@ -396,10 +371,6 @@ class Map {
{
return this->pop_try_as(key);
}
-
- /**
- * Same as `pop_try`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> std::optional<Value> pop_try_as(const ForwardKey &key)
{
return this->pop_try__impl(key, hash_(key));
@@ -417,10 +388,6 @@ class Map {
{
return this->pop_default_as(key, std::move(default_value));
}
-
- /**
- * Same as `pop_default`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey, typename ForwardValue>
Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
{
@@ -460,10 +427,6 @@ class Map {
{
return this->add_or_modify_as(std::move(key), create_value, modify_value);
}
-
- /**
- * Same as `add_or_modify`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
auto add_or_modify_as(ForwardKey &&key,
const CreateValueF &create_value,
@@ -487,10 +450,6 @@ class Map {
{
return this->lookup_ptr_as(key);
}
-
- /**
- * Same as `lookup_ptr`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> const Value *lookup_ptr_as(const ForwardKey &key) const
{
return this->lookup_ptr__impl(key, hash_(key));
@@ -512,10 +471,6 @@ class Map {
{
return this->lookup_as(key);
}
-
- /**
- * Same as `lookup`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> const Value &lookup_as(const ForwardKey &key) const
{
const Value *ptr = this->lookup_ptr_as(key);
@@ -537,10 +492,6 @@ class Map {
{
return this->lookup_default_as(key, default_value);
}
-
- /**
- * Same as `lookup_default`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey, typename ForwardValue>
Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
{
@@ -573,11 +524,6 @@ class Map {
{
return this->lookup_or_add_as(std::move(key), std::move(value));
}
-
- /**
- * Same as `lookup_or_add`, but accepts other key types that are supported by the hash
- * function.
- */
template<typename ForwardKey, typename ForwardValue>
Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
{
@@ -602,11 +548,6 @@ class Map {
{
return this->lookup_or_add_cb_as(std::move(key), create_value);
}
-
- /**
- * Same as `lookup_or_add_cb`, but accepts other key types that are supported by the hash
- * function.
- */
template<typename ForwardKey, typename CreateValueF>
Value &lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
{
@@ -625,11 +566,6 @@ class Map {
{
return this->lookup_or_add_default_as(std::move(key));
}
-
- /**
- * Same as `lookup_or_add_default`, but accepts other key types that are supported by the hash
- * function.
- */
template<typename ForwardKey> Value &lookup_or_add_default_as(ForwardKey &&key)
{
return this->lookup_or_add_cb_as(std::forward<ForwardKey>(key), []() { return Value(); });
@@ -1114,7 +1050,7 @@ class Map {
{
using CreateReturnT = decltype(create_value(nullptr));
using ModifyReturnT = decltype(modify_value(nullptr));
- BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+ BLI_STATIC_ASSERT((std::is_same_v<CreateReturnT, ModifyReturnT>),
"Both callbacks should return the same type.");
this->ensure_can_add();
diff --git a/source/blender/blenlib/BLI_map_slots.hh b/source/blender/blenlib/BLI_map_slots.hh
index c3d88205e0a..ff3ed34eb9d 100644
--- a/source/blender/blenlib/BLI_map_slots.hh
+++ b/source/blender/blenlib/BLI_map_slots.hh
@@ -53,8 +53,8 @@ template<typename Key, typename Value> class SimpleMapSlot {
};
State state_;
- AlignedBuffer<sizeof(Key), alignof(Key)> key_buffer_;
- AlignedBuffer<sizeof(Value), alignof(Value)> value_buffer_;
+ TypedBuffer<Key> key_buffer_;
+ TypedBuffer<Value> value_buffer_;
public:
/**
@@ -71,8 +71,8 @@ template<typename Key, typename Value> class SimpleMapSlot {
~SimpleMapSlot()
{
if (state_ == Occupied) {
- this->key()->~Key();
- this->value()->~Value();
+ key_buffer_.ref().~Key();
+ value_buffer_.ref().~Value();
}
}
@@ -84,8 +84,8 @@ template<typename Key, typename Value> class SimpleMapSlot {
{
state_ = other.state_;
if (other.state_ == Occupied) {
- new ((void *)this->key()) Key(*other.key());
- new ((void *)this->value()) Value(*other.value());
+ new (&key_buffer_) Key(*other.key_buffer_);
+ new (&value_buffer_) Value(*other.value_buffer_);
}
}
@@ -98,8 +98,8 @@ template<typename Key, typename Value> class SimpleMapSlot {
{
state_ = other.state_;
if (other.state_ == Occupied) {
- new ((void *)this->key()) Key(std::move(*other.key()));
- new ((void *)this->value()) Value(std::move(*other.value()));
+ new (&key_buffer_) Key(std::move(*other.key_buffer_));
+ new (&value_buffer_) Value(std::move(*other.value_buffer_));
}
}
@@ -108,7 +108,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
*/
Key *key()
{
- return (Key *)key_buffer_.ptr();
+ return key_buffer_;
}
/**
@@ -116,7 +116,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
*/
const Key *key() const
{
- return (const Key *)key_buffer_.ptr();
+ return key_buffer_;
}
/**
@@ -124,7 +124,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
*/
Value *value()
{
- return (Value *)value_buffer_.ptr();
+ return value_buffer_;
}
/**
@@ -132,7 +132,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
*/
const Value *value() const
{
- return (const Value *)value_buffer_.ptr();
+ return value_buffer_;
}
/**
@@ -158,7 +158,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
template<typename Hash> uint32_t get_hash(const Hash &hash)
{
BLI_assert(this->is_occupied());
- return hash(*this->key());
+ return hash(*key_buffer_);
}
/**
@@ -170,10 +170,10 @@ template<typename Key, typename Value> class SimpleMapSlot {
BLI_assert(!this->is_occupied());
BLI_assert(other.is_occupied());
state_ = Occupied;
- new ((void *)this->key()) Key(std::move(*other.key()));
- new ((void *)this->value()) Value(std::move(*other.value()));
- other.key()->~Key();
- other.value()->~Value();
+ new (&key_buffer_) Key(std::move(*other.key_buffer_));
+ new (&value_buffer_) Value(std::move(*other.value_buffer_));
+ other.key_buffer_.ref().~Key();
+ other.value_buffer_.ref().~Value();
}
/**
@@ -184,7 +184,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
bool contains(const ForwardKey &key, const IsEqual &is_equal, uint32_t UNUSED(hash)) const
{
if (state_ == Occupied) {
- return is_equal(key, *this->key());
+ return is_equal(key, *key_buffer_);
}
return false;
}
@@ -198,7 +198,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
{
BLI_assert(!this->is_occupied());
this->occupy_without_value(std::forward<ForwardKey>(key), hash);
- new ((void *)this->value()) Value(std::forward<ForwardValue>(value));
+ new (&value_buffer_) Value(std::forward<ForwardValue>(value));
}
/**
@@ -209,7 +209,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
{
BLI_assert(!this->is_occupied());
state_ = Occupied;
- new ((void *)this->key()) Key(std::forward<ForwardKey>(key));
+ new (&key_buffer_) Key(std::forward<ForwardKey>(key));
}
/**
@@ -220,8 +220,8 @@ template<typename Key, typename Value> class SimpleMapSlot {
{
BLI_assert(this->is_occupied());
state_ = Removed;
- this->key()->~Key();
- this->value()->~Value();
+ key_buffer_.ref().~Key();
+ value_buffer_.ref().~Value();
}
};
@@ -236,7 +236,7 @@ template<typename Key, typename Value> class SimpleMapSlot {
template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot {
private:
Key key_ = KeyInfo::get_empty();
- AlignedBuffer<sizeof(Value), alignof(Value)> value_buffer_;
+ TypedBuffer<Value> value_buffer_;
public:
IntrusiveMapSlot() = default;
@@ -244,21 +244,21 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
~IntrusiveMapSlot()
{
if (KeyInfo::is_not_empty_or_removed(key_)) {
- this->value()->~Value();
+ value_buffer_.ref().~Value();
}
}
IntrusiveMapSlot(const IntrusiveMapSlot &other) : key_(other.key_)
{
if (KeyInfo::is_not_empty_or_removed(key_)) {
- new ((void *)this->value()) Value(*other.value());
+ new (&value_buffer_) Value(*other.value_buffer_);
}
}
IntrusiveMapSlot(IntrusiveMapSlot &&other) noexcept : key_(other.key_)
{
if (KeyInfo::is_not_empty_or_removed(key_)) {
- new ((void *)this->value()) Value(std::move(*other.value()));
+ new (&value_buffer_) Value(std::move(*other.value_buffer_));
}
}
@@ -274,12 +274,12 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
Value *value()
{
- return (Value *)value_buffer_.ptr();
+ return value_buffer_;
}
const Value *value() const
{
- return (const Value *)value_buffer_.ptr();
+ return value_buffer_;
}
bool is_occupied() const
@@ -295,7 +295,7 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
template<typename Hash> uint32_t get_hash(const Hash &hash)
{
BLI_assert(this->is_occupied());
- return hash(*this->key());
+ return hash(key_);
}
void relocate_occupied_here(IntrusiveMapSlot &other, uint32_t UNUSED(hash))
@@ -303,9 +303,9 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
BLI_assert(!this->is_occupied());
BLI_assert(other.is_occupied());
key_ = std::move(other.key_);
- new ((void *)this->value()) Value(std::move(*other.value()));
+ new (&value_buffer_) Value(std::move(*other.value_buffer_));
other.key_.~Key();
- other.value()->~Value();
+ other.value_buffer_.ref().~Value();
}
template<typename ForwardKey, typename IsEqual>
@@ -321,7 +321,7 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
BLI_assert(!this->is_occupied());
BLI_assert(KeyInfo::is_not_empty_or_removed(key));
this->occupy_without_value(std::forward<ForwardKey>(key), hash);
- new ((void *)this->value()) Value(std::forward<ForwardValue>(value));
+ new (&value_buffer_) Value(std::forward<ForwardValue>(value));
}
template<typename ForwardKey> void occupy_without_value(ForwardKey &&key, uint32_t UNUSED(hash))
@@ -335,7 +335,7 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
{
BLI_assert(this->is_occupied());
KeyInfo::remove(key_);
- this->value()->~Value();
+ value_buffer_.ref().~Value();
}
};
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index ba95da4092e..48f8e7d31d9 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -148,8 +148,12 @@ void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, fl
/********* lift/gamma/gain / ASC-CDL conversion ***********/
-void lift_gamma_gain_to_asc_cdl(
- float *lift, float *gamma, float *gain, float *offset, float *slope, float *power);
+void lift_gamma_gain_to_asc_cdl(const float *lift,
+ const float *gamma,
+ const float *gain,
+ float *offset,
+ float *slope,
+ float *power);
#if BLI_MATH_DO_INLINE
# include "intern/math_color_inline.c"
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 2d11797bc34..33fcd750aee 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -64,7 +64,7 @@ void swap_m3m3(float A[3][3], float B[3][3]);
void swap_m4m4(float A[4][4], float B[4][4]);
/* Build index shuffle matrix */
-void shuffle_m4(float R[4][4], int index[4]);
+void shuffle_m4(float R[4][4], const int index[4]);
/******************************** Arithmetic *********************************/
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 44d25340778..b73e0e95312 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -19,62 +19,82 @@
/** \file
* \ingroup bli
+ * Some of the functions below have very similar alternatives in the standard library. However, it
+ * is rather annoying to use those when debugging. Therefore, some more specialized and easier to
+ * debug functions are provided here.
*/
#include <memory>
#include <new>
+#include <type_traits>
#include "BLI_utildefines.h"
namespace blender {
/**
- * Call the default constructor on n consecutive elements. For trivially constructible types, this
- * does nothing.
+ * Call the destructor on n consecutive values. For trivially destructible types, this does
+ * nothing.
+ *
+ * Exception Safety: Destructors shouldn't throw exceptions.
*
* Before:
- * ptr: uninitialized
- * After:
* ptr: initialized
+ * After:
+ * ptr: uninitialized
*/
-template<typename T> void default_construct_n(T *ptr, uint n)
+template<typename T> void destruct_n(T *ptr, uint n)
{
+ static_assert(std::is_nothrow_destructible_v<T>,
+ "This should be true for all types. Destructors are noexcept by default.");
+
/* This is not strictly necessary, because the loop below will be optimized away anyway. It is
* nice to make behavior this explicitly, though. */
- if (std::is_trivially_constructible<T>::value) {
+ if (std::is_trivially_destructible_v<T>) {
return;
}
for (uint i = 0; i < n; i++) {
- new ((void *)(ptr + i)) T;
+ ptr[i].~T();
}
}
/**
- * Call the destructor on n consecutive values. For trivially destructible types, this does
- * nothing.
+ * Call the default constructor on n consecutive elements. For trivially constructible types, this
+ * does nothing.
+ *
+ * Exception Safety: Strong.
*
* Before:
- * ptr: initialized
- * After:
* ptr: uninitialized
+ * After:
+ * ptr: initialized
*/
-template<typename T> void destruct_n(T *ptr, uint n)
+template<typename T> void default_construct_n(T *ptr, uint n)
{
/* This is not strictly necessary, because the loop below will be optimized away anyway. It is
* nice to make behavior this explicitly, though. */
- if (std::is_trivially_destructible<T>::value) {
+ if (std::is_trivially_constructible_v<T>) {
return;
}
- for (uint i = 0; i < n; i++) {
- ptr[i].~T();
+ uint current = 0;
+ try {
+ for (; current < n; current++) {
+ new ((void *)(ptr + current)) T;
+ }
+ }
+ catch (...) {
+ destruct_n(ptr, current);
+ throw;
}
}
/**
* Copy n values from src to dst.
*
+ * Exception Safety: Basic.
+ *
* Before:
* src: initialized
* dst: initialized
@@ -92,6 +112,8 @@ template<typename T> void initialized_copy_n(const T *src, uint n, T *dst)
/**
* Copy n values from src to dst.
*
+ * Exception Safety: Strong.
+ *
* Before:
* src: initialized
* dst: uninitialized
@@ -101,14 +123,49 @@ template<typename T> void initialized_copy_n(const T *src, uint n, T *dst)
*/
template<typename T> void uninitialized_copy_n(const T *src, uint n, T *dst)
{
- for (uint i = 0; i < n; i++) {
- new ((void *)(dst + i)) T(src[i]);
+ uint current = 0;
+ try {
+ for (; current < n; current++) {
+ new ((void *)(dst + current)) T(src[current]);
+ }
+ }
+ catch (...) {
+ destruct_n(dst, current);
+ throw;
+ }
+}
+
+/**
+ * Convert n values from type `From` to type `To`.
+ *
+ * Exception Safety: Strong.
+ *
+ * Before:
+ * src: initialized
+ * dst: uninitialized
+ * After:
+ * src: initialized
+ * dst: initialized
+ */
+template<typename From, typename To> void uninitialized_convert_n(const From *src, uint n, To *dst)
+{
+ uint current = 0;
+ try {
+ for (; current < n; current++) {
+ new ((void *)(dst + current)) To((To)src[current]);
+ }
+ }
+ catch (...) {
+ destruct_n(dst, current);
+ throw;
}
}
/**
* Move n values from src to dst.
*
+ * Exception Safety: Basic.
+ *
* Before:
* src: initialized
* dst: initialized
@@ -126,6 +183,8 @@ template<typename T> void initialized_move_n(T *src, uint n, T *dst)
/**
* Move n values from src to dst.
*
+ * Exception Safety: Basic.
+ *
* Before:
* src: initialized
* dst: uninitialized
@@ -135,8 +194,15 @@ template<typename T> void initialized_move_n(T *src, uint n, T *dst)
*/
template<typename T> void uninitialized_move_n(T *src, uint n, T *dst)
{
- for (uint i = 0; i < n; i++) {
- new ((void *)(dst + i)) T(std::move(src[i]));
+ uint current = 0;
+ try {
+ for (; current < n; current++) {
+ new ((void *)(dst + current)) T(std::move(src[current]));
+ }
+ }
+ catch (...) {
+ destruct_n(dst, current);
+ throw;
}
}
@@ -144,6 +210,8 @@ template<typename T> void uninitialized_move_n(T *src, uint n, T *dst)
* Relocate n values from src to dst. Relocation is a move followed by destruction of the src
* value.
*
+ * Exception Safety: Basic.
+ *
* Before:
* src: initialized
* dst: initialized
@@ -161,6 +229,8 @@ template<typename T> void initialized_relocate_n(T *src, uint n, T *dst)
* Relocate n values from src to dst. Relocation is a move followed by destruction of the src
* value.
*
+ * Exception Safety: Basic.
+ *
* Before:
* src: initialized
* dst: uninitialized
@@ -177,6 +247,8 @@ template<typename T> void uninitialized_relocate_n(T *src, uint n, T *dst)
/**
* Copy the value to n consecutive elements.
*
+ * Exception Safety: Basic.
+ *
* Before:
* dst: initialized
* After:
@@ -192,6 +264,8 @@ template<typename T> void initialized_fill_n(T *dst, uint n, const T &value)
/**
* Copy the value to n consecutive elements.
*
+ * Exception Safety: Strong.
+ *
* Before:
* dst: uninitialized
* After:
@@ -199,8 +273,15 @@ template<typename T> void initialized_fill_n(T *dst, uint n, const T &value)
*/
template<typename T> void uninitialized_fill_n(T *dst, uint n, const T &value)
{
- for (uint i = 0; i < n; i++) {
- new ((void *)(dst + i)) T(value);
+ uint current = 0;
+ try {
+ for (; current < n; current++) {
+ new ((void *)(dst + current)) T(value);
+ }
+ }
+ catch (...) {
+ destruct_n(dst, current);
+ throw;
}
}
@@ -218,12 +299,8 @@ template<typename T> struct DestructValueAtAddress {
template<typename T> using destruct_ptr = std::unique_ptr<T, DestructValueAtAddress<T>>;
/**
- * An `AlignedBuffer` is simply a byte array with the given size and alignment. The buffer will
+ * An `AlignedBuffer` is a byte array with at least the given size and alignment. The buffer will
* not be initialized by the default constructor.
- *
- * This can be used to reserve memory for C++ objects whose lifetime is different from the
- * lifetime of the object they are embedded in. It's used by containers with small buffer
- * optimization and hash table implementations.
*/
template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
private:
@@ -231,6 +308,16 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
char buffer_[(Size > 0) ? Size : 1];
public:
+ operator void *()
+ {
+ return (void *)buffer_;
+ }
+
+ operator const void *() const
+ {
+ return (void *)buffer_;
+ }
+
void *ptr()
{
return (void *)buffer_;
@@ -243,12 +330,72 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer {
};
/**
+ * This can be used to reserve memory for C++ objects whose lifetime is different from the
+ * lifetime of the object they are embedded in. It's used by containers with small buffer
+ * optimization and hash table implementations.
+ */
+template<typename T, size_t Size = 1> class TypedBuffer {
+ private:
+ AlignedBuffer<sizeof(T) * Size, alignof(T)> buffer_;
+
+ public:
+ operator T *()
+ {
+ return (T *)&buffer_;
+ }
+
+ operator const T *() const
+ {
+ return (const T *)&buffer_;
+ }
+
+ T &operator*()
+ {
+ return *(T *)&buffer_;
+ }
+
+ const T &operator*() const
+ {
+ return *(const T *)&buffer_;
+ }
+
+ T *ptr()
+ {
+ return (T *)&buffer_;
+ }
+
+ const T *ptr() const
+ {
+ return (const T *)&buffer_;
+ }
+
+ T &ref()
+ {
+ return *(T *)&buffer_;
+ }
+
+ const T &ref() const
+ {
+ return *(const T *)&buffer_;
+ }
+};
+
+/**
* This can be used by container constructors. A parameter of this type should be used to indicate
* that the constructor does not construct the elements.
*/
class NoInitialization {
};
+/**
+ * Helper variable that checks if a pointer type can be converted into another pointer type without
+ * issues. Possible issues are casting away const and casting a pointer to a child class.
+ * Adding const or casting to a parent class is fine.
+ */
+template<typename From, typename To>
+inline constexpr bool is_convertible_pointer_v =
+ std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>;
+
} // namespace blender
#endif /* __BLI_MEMORY_UTILS_HH__ */
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index ae78ea3af16..c55bbd26db5 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -105,12 +105,12 @@ int BLI_rng_thread_rand(RNG_THREAD_ARRAY *rngarr, int thread) ATTR_WARN_UNUSED_R
/** Return the _n_th number of the given low-discrepancy sequence. */
void BLI_halton_1d(unsigned int prime, double offset, int n, double *r);
-void BLI_halton_2d(unsigned int prime[2], double offset[2], int n, double *r);
-void BLI_halton_3d(unsigned int prime[3], double offset[3], int n, double *r);
+void BLI_halton_2d(const unsigned int prime[2], double offset[2], int n, double *r);
+void BLI_halton_3d(const unsigned int prime[3], double offset[3], int n, double *r);
void BLI_hammersley_1d(unsigned int n, double *r);
/** Return the whole low-discrepancy sequence up to _n_. */
-void BLI_halton_2d_sequence(unsigned int prime[2], double offset[2], int n, double *r);
+void BLI_halton_2d_sequence(const unsigned int prime[2], double offset[2], int n, double *r);
void BLI_hammersley_2d_sequence(unsigned int n, double *r);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
new file mode 100644
index 00000000000..bfc4d276165
--- /dev/null
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -0,0 +1,109 @@
+/*
+ * 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 bli
+ */
+
+#ifndef __BLI_RAND_HH__
+#define __BLI_RAND_HH__
+
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "BLI_math.h"
+#include "BLI_span.hh"
+#include "BLI_utildefines.h"
+
+namespace blender {
+
+class RandomNumberGenerator {
+ private:
+ uint64_t x_;
+
+ public:
+ RandomNumberGenerator(uint32_t seed = 0)
+ {
+ this->seed(seed);
+ }
+
+ /**
+ * Set the seed for future random numbers.
+ */
+ void seed(uint32_t seed)
+ {
+ constexpr uint64_t lowseed = 0x330E;
+ x_ = (((uint64_t)seed) << 16) | lowseed;
+ }
+
+ void seed_random(uint32_t seed);
+
+ uint32_t get_uint32()
+ {
+ this->step();
+ return (uint32_t)(x_ >> 17);
+ }
+
+ int32_t get_int32()
+ {
+ this->step();
+ return (int32_t)(x_ >> 17);
+ }
+
+ /**
+ * \return Random value (0..1), but never 1.0.
+ */
+ double get_double()
+ {
+ return (double)this->get_int32() / 0x80000000;
+ }
+
+ /**
+ * \return Random value (0..1), but never 1.0.
+ */
+ float get_float()
+ {
+ return (float)this->get_int32() / 0x80000000;
+ }
+
+ float2 get_unit_float2();
+ float3 get_unit_float3();
+ float2 get_triangle_sample(float2 v1, float2 v2, float2 v3);
+ void get_bytes(MutableSpan<char> r_bytes);
+
+ /**
+ * Simulate getting \a n random values.
+ */
+ void skip(uint n)
+ {
+ while (n--) {
+ this->step();
+ }
+ }
+
+ private:
+ void step()
+ {
+ constexpr uint64_t multiplier = 0x5DEECE66Dll;
+ constexpr uint64_t addend = 0xB;
+ constexpr uint64_t mask = 0x0000FFFFFFFFFFFFll;
+
+ x_ = (multiplier * x_ + addend) & mask;
+ }
+};
+
+} // namespace blender
+
+#endif /* __BLI_RAND_HH__ */
diff --git a/source/blender/blenlib/BLI_resource_collector.hh b/source/blender/blenlib/BLI_resource_collector.hh
new file mode 100644
index 00000000000..672a1269962
--- /dev/null
+++ b/source/blender/blenlib/BLI_resource_collector.hh
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_RESOURCE_COLLECTOR_HH__
+#define __BLI_RESOURCE_COLLECTOR_HH__
+
+/** \file
+ * \ingroup bli
+ *
+ * A ResourceCollector holds an arbitrary set of resources, that will be destructed and/or freed
+ * when the ResourceCollector is destructed. This is useful when some object has to take ownership
+ * of other objects, but it does not know the type of those other objects.
+ *
+ * Resources owned by the ResourceCollector will be freed in reverse order. That allows resources
+ * that are added later to depend on resources that have been added before.
+ */
+
+#include "BLI_linear_allocator.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+namespace blender {
+
+class ResourceCollector : NonCopyable, NonMovable {
+ private:
+ struct ResourceData {
+ void *data;
+ void (*free)(void *data);
+ const char *debug_name;
+ };
+
+ LinearAllocator<> m_allocator;
+ Vector<ResourceData> m_resources;
+
+ public:
+ ResourceCollector() = default;
+
+ ~ResourceCollector()
+ {
+ /* Free in reversed order. */
+ for (uint i = m_resources.size(); i--;) {
+ ResourceData &data = m_resources[i];
+ data.free(data.data);
+ }
+ }
+
+ /**
+ * Pass ownership of the resource to the ResourceCollector. It will be destructed and freed when
+ * the collector is destructed.
+ */
+ template<typename T> void add(std::unique_ptr<T> resource, const char *name)
+ {
+ BLI_assert(resource.get() != nullptr);
+ this->add(
+ resource.release(),
+ [](void *data) {
+ T *typed_data = reinterpret_cast<T *>(data);
+ delete typed_data;
+ },
+ name);
+ }
+
+ /**
+ * Pass ownership of the resource to the ResourceCollector. It will be destructed when the
+ * collector is destructed.
+ */
+ template<typename T> void add(destruct_ptr<T> resource, const char *name)
+ {
+ BLI_assert(resource.get() != nullptr);
+ this->add(
+ resource.release(),
+ [](void *data) {
+ T *typed_data = reinterpret_cast<T *>(data);
+ typed_data->~T();
+ },
+ name);
+ }
+
+ /**
+ * Pass ownership of some resource to the ResourceCollector. The given free function will be
+ * called when the collector is destructed.
+ */
+ void add(void *userdata, void (*free)(void *), const char *name)
+ {
+ ResourceData data;
+ data.debug_name = name;
+ data.data = userdata;
+ data.free = free;
+ m_resources.append(data);
+ }
+
+ /**
+ * Returns a reference to a linear allocator that is owned by the ResourcesCollector. Memory
+ * allocated through this allocator will be freed when the collector is destructed.
+ */
+ LinearAllocator<> &linear_allocator()
+ {
+ return m_allocator;
+ }
+
+ /**
+ * Utility method to construct an instance of type T that will be owned by the ResourceCollector.
+ */
+ template<typename T, typename... Args> T &construct(const char *name, Args &&... args)
+ {
+ T *value = m_allocator.construct<T>(std::forward<Args>(args)...);
+ this->add(destruct_ptr<T>(value), name);
+ return *value;
+ }
+
+ /**
+ * Print the names of all the resources that are owned by this ResourceCollector. This can be
+ * useful for debugging.
+ */
+ void print(StringRef name) const
+ {
+ if (m_resources.size() == 0) {
+ std::cout << "\"" << name << "\" has no resources.\n";
+ return;
+ }
+ else {
+ std::cout << "Resources for \"" << name << "\":\n";
+ for (const ResourceData &data : m_resources) {
+ std::cout << " " << data.data << ": " << data.debug_name << '\n';
+ }
+ }
+ }
+};
+
+} // namespace blender
+
+#endif /* __BLI_RESOURCE_COLLECTOR_HH__ */
diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh
index 09b2d170eea..c5096f84c80 100644
--- a/source/blender/blenlib/BLI_set.hh
+++ b/source/blender/blenlib/BLI_set.hh
@@ -260,10 +260,6 @@ class Set {
{
return this->add_as(std::move(key));
}
-
- /**
- * Same as `add`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool add_as(ForwardKey &&key)
{
return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
@@ -303,13 +299,53 @@ class Set {
{
return this->contains_as(key);
}
+ template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
+ {
+ return this->contains__impl(key, hash_(key));
+ }
/**
- * Same as `contains`, but accepts other key types that are supported by the hash function.
+ * Returns the key that is stored in the set that compares equal to the given key. This invokes
+ * undefined behavior when the key is not in the set.
*/
- template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
+ const Key &lookup_key(const Key &key) const
{
- return this->contains__impl(key, hash_(key));
+ return this->lookup_key_as(key);
+ }
+ template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
+ {
+ return this->lookup_key__impl(key, hash_(key));
+ }
+
+ /**
+ * Returns the key that is stored in the set that compares equal to the given key. If the key is
+ * not in the set, the given default value is returned instead.
+ */
+ const Key &lookup_key_default(const Key &key, const Key &default_value) const
+ {
+ return this->lookup_key_default_as(key, default_value);
+ }
+ template<typename ForwardKey>
+ const Key &lookup_key_default_as(const ForwardKey &key, const Key &default_key) const
+ {
+ const Key *ptr = this->lookup_key_ptr__impl(key, hash_(key));
+ if (ptr == nullptr) {
+ return default_key;
+ }
+ return *ptr;
+ }
+
+ /**
+ * Returns a pointer to the key that is stored in the set that compares equal to the given key.
+ * If the key is not in the set, nullptr is returned instead.
+ */
+ const Key *lookup_key_ptr(const Key &key) const
+ {
+ return this->lookup_key_ptr_as(key);
+ }
+ template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
+ {
+ return this->lookup_key_ptr__impl(key, hash_(key));
}
/**
@@ -321,10 +357,6 @@ class Set {
{
return this->remove_as(key);
}
-
- /**
- * Same as `remove`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool remove_as(const ForwardKey &key)
{
return this->remove__impl(key, hash_(key));
@@ -337,11 +369,6 @@ class Set {
{
this->remove_contained_as(key);
}
-
- /**
- * Same as `remove_contained`, but accepts other key types that are supported by the hash
- * function.
- */
template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
{
this->remove_contained__impl(key, hash_(key));
@@ -596,6 +623,33 @@ class Set {
SET_SLOT_PROBING_END();
}
+ template<typename ForwardKey>
+ const Key &lookup_key__impl(const ForwardKey &key, const uint32_t hash) const
+ {
+ BLI_assert(this->contains_as(key));
+
+ SET_SLOT_PROBING_BEGIN (hash, slot) {
+ if (slot.contains(key, is_equal_, hash)) {
+ return *slot.key();
+ }
+ }
+ SET_SLOT_PROBING_END();
+ }
+
+ template<typename ForwardKey>
+ const Key *lookup_key_ptr__impl(const ForwardKey &key, const uint32_t hash) const
+ {
+ SET_SLOT_PROBING_BEGIN (hash, slot) {
+ if (slot.contains(key, is_equal_, hash)) {
+ return slot.key();
+ }
+ if (slot.is_empty()) {
+ return nullptr;
+ }
+ }
+ SET_SLOT_PROBING_END();
+ }
+
template<typename ForwardKey> void add_new__impl(ForwardKey &&key, const uint32_t hash)
{
BLI_assert(!this->contains_as(key));
diff --git a/source/blender/blenlib/BLI_set_slots.hh b/source/blender/blenlib/BLI_set_slots.hh
index 9719f322693..d3891e78b52 100644
--- a/source/blender/blenlib/BLI_set_slots.hh
+++ b/source/blender/blenlib/BLI_set_slots.hh
@@ -51,7 +51,7 @@ template<typename Key> class SimpleSetSlot {
};
State state_;
- AlignedBuffer<sizeof(Key), alignof(Key)> buffer_;
+ TypedBuffer<Key> key_buffer_;
public:
/**
@@ -68,7 +68,7 @@ template<typename Key> class SimpleSetSlot {
~SimpleSetSlot()
{
if (state_ == Occupied) {
- this->key()->~Key();
+ key_buffer_.ref().~Key();
}
}
@@ -80,7 +80,7 @@ template<typename Key> class SimpleSetSlot {
{
state_ = other.state_;
if (other.state_ == Occupied) {
- new ((void *)this->key()) Key(*other.key());
+ new (&key_buffer_) Key(*other.key_buffer_);
}
}
@@ -93,7 +93,7 @@ template<typename Key> class SimpleSetSlot {
{
state_ = other.state_;
if (other.state_ == Occupied) {
- new ((void *)this->key()) Key(std::move(*other.key()));
+ new (&key_buffer_) Key(std::move(*other.key_buffer_));
}
}
@@ -102,7 +102,7 @@ template<typename Key> class SimpleSetSlot {
*/
Key *key()
{
- return (Key *)buffer_.ptr();
+ return key_buffer_;
}
/**
@@ -110,7 +110,7 @@ template<typename Key> class SimpleSetSlot {
*/
const Key *key() const
{
- return (const Key *)buffer_.ptr();
+ return key_buffer_;
}
/**
@@ -136,7 +136,7 @@ template<typename Key> class SimpleSetSlot {
template<typename Hash> uint32_t get_hash(const Hash &hash) const
{
BLI_assert(this->is_occupied());
- return hash(*this->key());
+ return hash(*key_buffer_);
}
/**
@@ -148,8 +148,8 @@ template<typename Key> class SimpleSetSlot {
BLI_assert(!this->is_occupied());
BLI_assert(other.is_occupied());
state_ = Occupied;
- new ((void *)this->key()) Key(std::move(*other.key()));
- other.key()->~Key();
+ new (&key_buffer_) Key(std::move(*other.key_buffer_));
+ other.key_buffer_.ref().~Key();
}
/**
@@ -160,7 +160,7 @@ template<typename Key> class SimpleSetSlot {
bool contains(const ForwardKey &key, const IsEqual &is_equal, uint32_t UNUSED(hash)) const
{
if (state_ == Occupied) {
- return is_equal(key, *this->key());
+ return is_equal(key, *key_buffer_);
}
return false;
}
@@ -173,7 +173,7 @@ template<typename Key> class SimpleSetSlot {
{
BLI_assert(!this->is_occupied());
state_ = Occupied;
- new ((void *)this->key()) Key(std::forward<ForwardKey>(key));
+ new (&key_buffer_) Key(std::forward<ForwardKey>(key));
}
/**
@@ -183,7 +183,7 @@ template<typename Key> class SimpleSetSlot {
{
BLI_assert(this->is_occupied());
state_ = Removed;
- this->key()->~Key();
+ key_buffer_.ref().~Key();
}
};
@@ -201,7 +201,7 @@ template<typename Key> class HashedSetSlot {
uint32_t hash_;
State state_;
- AlignedBuffer<sizeof(Key), alignof(Key)> buffer_;
+ TypedBuffer<Key> key_buffer_;
public:
HashedSetSlot()
@@ -212,7 +212,7 @@ template<typename Key> class HashedSetSlot {
~HashedSetSlot()
{
if (state_ == Occupied) {
- this->key()->~Key();
+ key_buffer_.ref().~Key();
}
}
@@ -221,7 +221,7 @@ template<typename Key> class HashedSetSlot {
state_ = other.state_;
if (other.state_ == Occupied) {
hash_ = other.hash_;
- new ((void *)this->key()) Key(*other.key());
+ new (&key_buffer_) Key(*other.key_buffer_);
}
}
@@ -230,18 +230,18 @@ template<typename Key> class HashedSetSlot {
state_ = other.state_;
if (other.state_ == Occupied) {
hash_ = other.hash_;
- new ((void *)this->key()) Key(std::move(*other.key()));
+ new (&key_buffer_) Key(std::move(*other.key_buffer_));
}
}
Key *key()
{
- return (Key *)buffer_.ptr();
+ return key_buffer_;
}
const Key *key() const
{
- return (const Key *)buffer_.ptr();
+ return key_buffer_;
}
bool is_occupied() const
@@ -266,8 +266,8 @@ template<typename Key> class HashedSetSlot {
BLI_assert(other.is_occupied());
state_ = Occupied;
hash_ = hash;
- new ((void *)this->key()) Key(std::move(*other.key()));
- other.key()->~Key();
+ new (&key_buffer_) Key(std::move(*other.key_buffer_));
+ key_buffer_.ref().~Key();
}
template<typename ForwardKey, typename IsEqual>
@@ -276,7 +276,7 @@ template<typename Key> class HashedSetSlot {
/* hash_ might be uninitialized here, but that is ok. */
if (hash_ == hash) {
if (state_ == Occupied) {
- return is_equal(key, *this->key());
+ return is_equal(key, *key_buffer_);
}
}
return false;
@@ -287,14 +287,14 @@ template<typename Key> class HashedSetSlot {
BLI_assert(!this->is_occupied());
state_ = Occupied;
hash_ = hash;
- new ((void *)this->key()) Key(std::forward<ForwardKey>(key));
+ new (&key_buffer_) Key(std::forward<ForwardKey>(key));
}
void remove()
{
BLI_assert(this->is_occupied());
state_ = Removed;
- this->key()->~Key();
+ key_buffer_.ref().~Key();
}
};
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 92d3124e01d..57ef9ce9eb6 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -100,6 +100,11 @@ template<typename T> class Span {
{
}
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
+ Span(const U *start, uint size) : start_((const T *)start), size_(size)
+ {
+ }
+
/**
* Reference an initializer_list. Note that the data in the initializer_list is only valid until
* the expression containing it is fully computed.
@@ -128,9 +133,8 @@ template<typename T> class Span {
* Span<T *> -> Span<const T *>
* Span<Derived *> -> Span<Base *>
*/
- template<typename U,
- typename std::enable_if<std::is_convertible<U *, T>::value>::type * = nullptr>
- Span(Span<U *> array) : Span((T *)array.data(), array.size())
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
+ Span(Span<U> array) : start_((T *)array.data()), size_(array.size())
{
}
@@ -436,21 +440,6 @@ template<typename T> class MutableSpan {
{
}
- /**
- * Reference an initializer_list. Note that the data in the initializer_list is only valid until
- * the expression containing it is fully computed.
- *
- * Do:
- * call_function_with_array({1, 2, 3, 4});
- *
- * Don't:
- * MutableSpan<int> span = {1, 2, 3, 4};
- * call_function_with_array(span);
- */
- MutableSpan(std::initializer_list<T> &list) : MutableSpan(list.begin(), list.size())
- {
- }
-
MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
{
}
@@ -607,14 +596,6 @@ template<typename T> class MutableSpan {
};
/**
- * Shorthand to make use of automatic template parameter deduction.
- */
-template<typename T> Span<T> ref_c_array(const T *array, uint size)
-{
- return Span<T>(array, size);
-}
-
-/**
* Utilities to check that arrays have the same size in debug builds.
*/
template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2 &v2)
diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh
index 50be9357a01..a5a95186e37 100644
--- a/source/blender/blenlib/BLI_stack.hh
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -106,7 +106,7 @@ class Stack {
uint size_;
/** The buffer used to implement small object optimization. */
- AlignedBuffer<sizeof(T) * InlineBufferCapacity, alignof(T)> inline_buffer_;
+ TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
/**
* A chunk referencing the inline buffer. This is always the bottom-most chunk.
@@ -123,14 +123,12 @@ class Stack {
*/
Stack(Allocator allocator = {}) : allocator_(allocator)
{
- T *inline_buffer = this->inline_buffer();
-
inline_chunk_.below = nullptr;
inline_chunk_.above = nullptr;
- inline_chunk_.begin = inline_buffer;
- inline_chunk_.capacity_end = inline_buffer + InlineBufferCapacity;
+ inline_chunk_.begin = inline_buffer_;
+ inline_chunk_.capacity_end = inline_buffer_ + InlineBufferCapacity;
- top_ = inline_buffer;
+ top_ = inline_buffer_;
top_chunk_ = &inline_chunk_;
size_ = 0;
}
@@ -168,15 +166,19 @@ class Stack {
Stack(Stack &&other) noexcept : Stack(other.allocator_)
{
- uninitialized_relocate_n(
- other.inline_buffer(), std::min(other.size_, InlineBufferCapacity), this->inline_buffer());
+ uninitialized_relocate_n<T>(
+ other.inline_buffer_, std::min(other.size_, InlineBufferCapacity), inline_buffer_);
inline_chunk_.above = other.inline_chunk_.above;
size_ = other.size_;
+ if (inline_chunk_.above != nullptr) {
+ inline_chunk_.above->below = &inline_chunk_;
+ }
+
if (size_ <= InlineBufferCapacity) {
top_chunk_ = &inline_chunk_;
- top_ = this->inline_buffer() + size_;
+ top_ = inline_buffer_ + size_;
}
else {
top_chunk_ = other.top_chunk_;
@@ -335,11 +337,6 @@ class Stack {
}
private:
- T *inline_buffer() const
- {
- return (T *)inline_buffer_.ptr();
- }
-
/**
* Changes top_chunk_ to point to a new chunk that is above the current one. The new chunk might
* be smaller than the given size_hint. This happens when a chunk that has been allocated before
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 6f810144a48..920a0a8f650 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -107,7 +107,7 @@ typedef uint32_t SpinLock;
#elif defined(__APPLE__)
typedef ThreadMutex SpinLock;
#elif defined(_MSC_VER)
-typedef volatile int SpinLock;
+typedef volatile unsigned int SpinLock;
#else
typedef pthread_spinlock_t SpinLock;
#endif
diff --git a/source/blender/blenlib/BLI_timeit.hh b/source/blender/blenlib/BLI_timeit.hh
index 34c2d63cbd7..f0968587597 100644
--- a/source/blender/blenlib/BLI_timeit.hh
+++ b/source/blender/blenlib/BLI_timeit.hh
@@ -23,8 +23,7 @@
#include "BLI_sys_types.h"
-namespace blender {
-namespace Timeit {
+namespace blender::timeit {
using Clock = std::chrono::steady_clock;
using TimePoint = Clock::time_point;
@@ -54,9 +53,8 @@ class ScopedTimer {
}
};
-} // namespace Timeit
-} // namespace blender
+} // namespace blender::timeit
-#define SCOPED_TIMER(name) blender::Timeit::ScopedTimer scoped_timer(name)
+#define SCOPED_TIMER(name) blender::timeit::ScopedTimer scoped_timer(name)
#endif /* __BLI_TIMEIT_HH__ */
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 1f28f7e80c5..bc35e969e6a 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -627,11 +627,11 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
/** \name String Macros
* \{ */
-/* Macro to convert a value to string in the preprocessor
- * STRINGIFY_ARG: gives the argument as a string
- * STRINGIFY_APPEND: appends any argument 'b' onto the string argument 'a',
- * used by STRINGIFY because some preprocessors warn about zero arguments
- * STRINGIFY: gives the argument's value as a string */
+/* Macro to convert a value to string in the pre-processor:
+ * - `STRINGIFY_ARG`: gives the argument as a string
+ * - `STRINGIFY_APPEND`: appends any argument 'b' onto the string argument 'a',
+ * used by `STRINGIFY` because some preprocessors warn about zero arguments
+ * - `STRINGIFY`: gives the argument's value as a string. */
#define STRINGIFY_ARG(x) "" #x
#define STRINGIFY_APPEND(a, b) "" a #b
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index a06be65685f..1fe38464ad0 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -92,7 +92,7 @@ class Vector {
Allocator allocator_;
/** A placeholder buffer that will remain uninitialized until it is used. */
- AlignedBuffer<(uint)sizeof(T) * InlineBufferCapacity, (uint)alignof(T)> inline_buffer_;
+ TypedBuffer<T, InlineBufferCapacity> inline_buffer_;
/**
* Store the size of the vector explicitly in debug builds. Otherwise you'd always have to call
@@ -118,9 +118,9 @@ class Vector {
* Create an empty vector.
* This does not do any memory allocation.
*/
- Vector()
+ Vector(Allocator allocator = {}) : allocator_(allocator)
{
- begin_ = this->inline_buffer();
+ begin_ = inline_buffer_;
end_ = begin_;
capacity_end_ = begin_ + InlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
@@ -141,9 +141,19 @@ class Vector {
*/
Vector(uint size, const T &value) : Vector()
{
+ this->resize(size, value);
+ }
+
+ /**
+ * Create a vector from an array ref. The values in the vector are copy constructed.
+ */
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Vector(Span<U> values, Allocator allocator = {}) : Vector(allocator)
+ {
+ const uint size = values.size();
this->reserve(size);
this->increase_size_by_unchecked(size);
- blender::uninitialized_fill_n(begin_, size, value);
+ uninitialized_convert_n<U, T>(values.data(), size, begin_);
}
/**
@@ -152,24 +162,25 @@ class Vector {
* This allows you to write code like:
* Vector<int> vec = {3, 4, 5};
*/
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Vector(const std::initializer_list<U> &values) : Vector(Span<U>(values))
+ {
+ }
+
Vector(const std::initializer_list<T> &values) : Vector(Span<T>(values))
{
}
- /**
- * Create a vector from an array ref. The values in the vector are copy constructed.
- */
- Vector(Span<T> values) : Vector()
+ template<typename U,
+ size_t N,
+ typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Vector(const std::array<U, N> &values) : Vector(Span(values))
{
- const uint size = values.size();
- this->reserve(size);
- this->increase_size_by_unchecked(size);
- blender::uninitialized_copy_n(values.data(), size, begin_);
}
/**
- * Create a vector from any container. It must be possible to use the container in a range-for
- * loop.
+ * Create a vector from any container. It must be possible to use the container in a
+ * range-for loop.
*/
template<typename ContainerT> static Vector FromContainer(const ContainerT &container)
{
@@ -198,9 +209,8 @@ class Vector {
* Create a copy of another vector. The other vector will not be changed. If the other vector has
* less than InlineBufferCapacity elements, no allocation will be made.
*/
- Vector(const Vector &other) : allocator_(other.allocator_)
+ Vector(const Vector &other) : Vector(other.as_span(), other.allocator_)
{
- this->init_copy_from_other_vector(other);
}
/**
@@ -209,9 +219,8 @@ class Vector {
*/
template<uint OtherInlineBufferCapacity>
Vector(const Vector<T, OtherInlineBufferCapacity, Allocator> &other)
- : allocator_(other.allocator_)
+ : Vector(other.as_span(), other.allocator_)
{
- this->init_copy_from_other_vector(other);
}
/**
@@ -227,7 +236,7 @@ class Vector {
if (other.is_inline()) {
if (size <= InlineBufferCapacity) {
/* Copy between inline buffers. */
- begin_ = this->inline_buffer();
+ begin_ = inline_buffer_;
end_ = begin_ + size;
capacity_end_ = begin_ + InlineBufferCapacity;
uninitialized_relocate_n(other.begin_, size, begin_);
@@ -248,7 +257,7 @@ class Vector {
capacity_end_ = other.capacity_end_;
}
- other.begin_ = other.inline_buffer();
+ other.begin_ = other.inline_buffer_;
other.end_ = other.begin_;
other.capacity_end_ = other.begin_ + OtherInlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
@@ -315,6 +324,18 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator Span<U>() const
+ {
+ return Span<U>(begin_, this->size());
+ }
+
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator MutableSpan<U>()
+ {
+ return MutableSpan<U>(begin_, this->size());
+ }
+
Span<T> as_span() const
{
return *this;
@@ -399,7 +420,7 @@ class Vector {
allocator_.deallocate(begin_);
}
- begin_ = this->inline_buffer();
+ begin_ = inline_buffer_;
end_ = begin_;
capacity_end_ = begin_ + InlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
@@ -763,14 +784,9 @@ class Vector {
}
private:
- T *inline_buffer() const
- {
- return (T *)inline_buffer_.ptr();
- }
-
bool is_inline() const
{
- return begin_ == this->inline_buffer();
+ return begin_ == inline_buffer_;
}
void ensure_space_for_one()
@@ -804,44 +820,10 @@ class Vector {
end_ = begin_ + size;
capacity_end_ = begin_ + new_capacity;
}
-
- /**
- * Initialize all properties, except for allocator_, which has to be initialized beforehand.
- */
- template<uint OtherInlineBufferCapacity>
- void init_copy_from_other_vector(const Vector<T, OtherInlineBufferCapacity, Allocator> &other)
- {
- allocator_ = other.allocator_;
-
- const uint size = other.size();
- uint capacity;
-
- if (size <= InlineBufferCapacity) {
- begin_ = this->inline_buffer();
- capacity = InlineBufferCapacity;
- }
- else {
- begin_ = (T *)allocator_.allocate(sizeof(T) * size, alignof(T), AT);
- capacity = size;
- }
-
- end_ = begin_ + size;
- capacity_end_ = begin_ + capacity;
-
- uninitialized_copy_n(other.data(), size, begin_);
- UPDATE_VECTOR_SIZE(this);
- }
};
#undef UPDATE_VECTOR_SIZE
-/**
- * Use when the vector is used in the local scope of a function. It has a larger inline storage by
- * default to make allocations less likely.
- */
-template<typename T, uint InlineBufferCapacity = 20>
-using ScopedVector = Vector<T, InlineBufferCapacity, GuardedAllocator>;
-
} /* namespace blender */
#endif /* __BLI_VECTOR_HH__ */
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index a39f6a97f70..dd1b17653c0 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -288,10 +288,6 @@ class VectorSet {
{
return this->add_as(std::move(key));
}
-
- /**
- * Same as `add`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool add_as(ForwardKey &&key)
{
return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
@@ -320,10 +316,6 @@ class VectorSet {
{
return this->contains_as(key);
}
-
- /**
- * Same as `contains`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
{
return this->contains__impl(key, hash_(key));
@@ -339,10 +331,6 @@ class VectorSet {
{
return this->remove_as(key);
}
-
- /**
- * Same as `remove`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> bool remove_as(const ForwardKey &key)
{
return this->remove__impl(key, hash_(key));
@@ -356,11 +344,6 @@ class VectorSet {
{
this->remove_contained_as(key);
}
-
- /**
- * Same as `remove_contained`, but accepts other key types that are supported by the hash
- * function.
- */
template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
{
this->remove_contained__impl(key, hash_(key));
@@ -383,10 +366,6 @@ class VectorSet {
{
return this->index_of_as(key);
}
-
- /**
- * Same as `index_of`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> uint32_t index_of_as(const ForwardKey &key) const
{
return this->index_of__impl(key, hash_(key));
@@ -400,10 +379,6 @@ class VectorSet {
{
return (int32_t)this->index_of_try_as(key);
}
-
- /**
- * Same as `index_of_try`, but accepts other key types that are supported by the hash function.
- */
template<typename ForwardKey> int32_t index_of_try_as(const ForwardKey &key) const
{
return this->index_of_try__impl(key, hash_(key));
diff --git a/source/blender/blenlib/BLI_voxel.h b/source/blender/blenlib/BLI_voxel.h
index 220ab9b3705..82854c57928 100644
--- a/source/blender/blenlib/BLI_voxel.h
+++ b/source/blender/blenlib/BLI_voxel.h
@@ -35,10 +35,13 @@ extern "C" {
(int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1])
/* all input coordinates must be in bounding box 0.0 - 1.0 */
-float BLI_voxel_sample_nearest(float *data, const int res[3], const float co[3]);
-float BLI_voxel_sample_trilinear(float *data, const int res[3], const float co[3]);
-float BLI_voxel_sample_triquadratic(float *data, const int res[3], const float co[3]);
-float BLI_voxel_sample_tricubic(float *data, const int res[3], const float co[3], int bspline);
+float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3]);
+float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3]);
+float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3]);
+float BLI_voxel_sample_tricubic(const float *data,
+ const int res[3],
+ const float co[3],
+ int bspline);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e599b00401a..c352a9ec1ae 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -105,7 +105,7 @@ set(SRC
intern/polyfill_2d.c
intern/polyfill_2d_beautify.c
intern/quadric.c
- intern/rand.c
+ intern/rand.cc
intern/rct.c
intern/scanfill.c
intern/scanfill_utils.c
@@ -163,6 +163,7 @@ set(SRC
BLI_convexhull_2d.h
BLI_delaunay_2d.h
BLI_dial_2d.h
+ BLI_disjoint_set.hh
BLI_dlrbTree.h
BLI_dot_export.hh
BLI_dot_export_attribute_enums.hh
@@ -232,6 +233,7 @@ set(SRC
BLI_quadric.h
BLI_rand.h
BLI_rect.h
+ BLI_resource_collector.hh
BLI_scanfill.h
BLI_set.hh
BLI_set_slots.hh
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index 83bf0373ae7..d6a4b24682f 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -86,25 +86,6 @@ bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b)
return (memcmp(a, b, sizeof(uint[4])) != 0);
}
-uint BLI_ghashutil_uinthash_v2(const uint key[2])
-{
- uint hash;
- hash = key[0];
- hash *= 37;
- hash += key[1];
- return hash;
-}
-
-uint BLI_ghashutil_uinthash_v2_murmur(const uint key[2])
-{
- return BLI_hash_mm2((const unsigned char *)key, sizeof(int) * 2 /* sizeof(key) */, 0);
-}
-
-bool BLI_ghashutil_uinthash_v2_cmp(const void *a, const void *b)
-{
- return (memcmp(a, b, sizeof(uint[2])) != 0);
-}
-
uint BLI_ghashutil_uinthash(uint key)
{
key += ~(key << 16);
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 0707e4c1d2a..a3f93ccc753 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -169,6 +169,12 @@ typedef struct BVHNearestProjectedData {
} BVHNearestProjectedData;
+typedef struct BVHIntersectPlaneData {
+ const BVHTree *tree;
+ float plane[4];
+ struct BLI_Stack *intersect; /* Store indexes. */
+} BVHIntersectPlaneData;
+
/** \} */
/**
@@ -1393,6 +1399,71 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
/** \} */
/* -------------------------------------------------------------------- */
+/** \name BLI_bvhtree_intersect_plane
+ * \{ */
+
+static bool tree_intersect_plane_test(const float *bv, const float plane[4])
+{
+ /* TODO(germano): Support other kdop geometries. */
+ const float bb_min[3] = {bv[0], bv[2], bv[4]};
+ const float bb_max[3] = {bv[1], bv[3], bv[5]};
+ float bb_near[3], bb_far[3];
+ aabb_get_near_far_from_plane(plane, bb_min, bb_max, bb_near, bb_far);
+ if ((plane_point_side_v3(plane, bb_near) > 0.0f) !=
+ (plane_point_side_v3(plane, bb_far) > 0.0f)) {
+ return true;
+ }
+
+ return false;
+}
+
+static void bvhtree_intersect_plane_dfs_recursive(BVHIntersectPlaneData *__restrict data,
+ const BVHNode *node)
+{
+ if (tree_intersect_plane_test(node->bv, data->plane)) {
+ /* check if node is a leaf */
+ if (!node->totnode) {
+ int *intersect = BLI_stack_push_r(data->intersect);
+ *intersect = node->index;
+ }
+ else {
+ for (int j = 0; j < data->tree->tree_type; j++) {
+ if (node->children[j]) {
+ bvhtree_intersect_plane_dfs_recursive(data, node->children[j]);
+ }
+ }
+ }
+ }
+}
+
+int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot)
+{
+ int *intersect = NULL;
+ size_t total = 0;
+
+ if (tree->totleaf) {
+ BVHIntersectPlaneData data;
+ data.tree = tree;
+ copy_v4_v4(data.plane, plane);
+ data.intersect = BLI_stack_new(sizeof(int), __func__);
+
+ BVHNode *root = tree->nodes[tree->totleaf];
+ bvhtree_intersect_plane_dfs_recursive(&data, root);
+
+ total = BLI_stack_count(data.intersect);
+ if (total) {
+ intersect = MEM_mallocN(sizeof(int) * total, __func__);
+ BLI_stack_pop_n(data.intersect, intersect, (uint)total);
+ }
+ BLI_stack_free(data.intersect);
+ }
+ *r_intersect_tot = (uint)total;
+ return intersect;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name BLI_bvhtree_find_nearest
* \{ */
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 5020e06d0b3..dc5d20ece99 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -74,6 +74,16 @@ LinkNode *BLI_linklist_find(LinkNode *list, int index)
return NULL;
}
+LinkNode *BLI_linklist_find_last(LinkNode *list)
+{
+ if (list) {
+ while (list->next) {
+ list = list->next;
+ }
+ }
+ return list;
+}
+
void BLI_linklist_reverse(LinkNode **listp)
{
LinkNode *rhead = NULL, *cur = *listp;
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 08ccff695c1..5f663dcb2e1 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -952,7 +952,7 @@ static void initial_triangulation(CDT_state *cdt)
}
#endif
- /* Now dedup according to user-defined epsilon.
+ /* Now de-duplicate according to user-defined epsilon.
* We will merge a vertex into an earlier-indexed vertex
* that is within epsilon (Euclidean distance).
* Merges may cascade. So we may end up merging two things
@@ -4320,7 +4320,7 @@ static void exactinit(void)
*/
static int fast_expansion_sum_zeroelim(
- int elen, double *e, int flen, double *f, double *h) /* h cannot be e or f. */
+ int elen, const double *e, int flen, const double *f, double *h) /* h cannot be e or f. */
{
double Q;
INEXACT double Qnew;
@@ -4405,7 +4405,7 @@ static int fast_expansion_sum_zeroelim(
*/
static int scale_expansion_zeroelim(int elen,
- double *e,
+ const double *e,
double b,
double *h) /* e and h cannot be the same. */
{
@@ -4451,7 +4451,7 @@ static int scale_expansion_zeroelim(int elen,
* See either version of my paper for details.
*/
-static double estimate(int elen, double *e)
+static double estimate(int elen, const double *e)
{
double Q;
int eindex;
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index e87350ecbb6..e61cbd318fc 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -560,7 +560,7 @@ int BLI_move(const char *file, const char *to)
/* windows doesn't support moving to a directory
* it has to be 'mv filename filename' and not
- * 'mv filename destdir' */
+ * 'mv filename destination_directory' */
BLI_strncpy(str, to, sizeof(str));
/* points 'to' to a directory ? */
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 625849c01df..651a062e3d5 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -503,8 +503,12 @@ int constrain_rgb(float *r, float *g, float *b)
/* ********************** lift/gamma/gain / ASC-CDL conversion ********************************* */
-void lift_gamma_gain_to_asc_cdl(
- float *lift, float *gamma, float *gain, float *offset, float *slope, float *power)
+void lift_gamma_gain_to_asc_cdl(const float *lift,
+ const float *gamma,
+ const float *gain,
+ float *offset,
+ float *slope,
+ float *power)
{
int c;
for (c = 0; c < 3; c++) {
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 92cfd09f191..fadd7d83444 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -248,7 +248,7 @@ void swap_m4m4(float m1[4][4], float m2[4][4])
}
}
-void shuffle_m4(float R[4][4], int index[4])
+void shuffle_m4(float R[4][4], const int index[4])
{
zero_m4(R);
for (int k = 0; k < 4; k++) {
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 6ec7c960d6b..7f1840228e2 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -307,7 +307,7 @@ void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const uint nbr)
/**
* Specialized function for calculating normals.
- * fastpath for:
+ * Fast-path for:
*
* \code{.c}
* add_v3_v3v3(r, a, b);
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index 42b5ba28f5a..1ae1c91a3bd 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -27,7 +27,7 @@
#include "BLI_noise.h"
/* local */
-static float noise3_perlin(float vec[3]);
+static float noise3_perlin(const float vec[3]);
// static float turbulence_perlin(const float point[3], float lofreq, float hifreq);
// static float turbulencep(float noisesize, float x, float y, float z, int nr);
@@ -779,7 +779,7 @@ static const float g_perlin_data_v3[512 + 2][3] = {
} \
(void)0
-static float noise3_perlin(float vec[3])
+static float noise3_perlin(const float vec[3])
{
const char *p = g_perlin_data_ub;
const float(*g)[3] = g_perlin_data_v3;
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 2f51b66725b..d912cb8d464 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -242,7 +242,7 @@ void BLI_path_normalize(const char *relabase, char *path)
/* Note: previous version of following call used an offset of 3 instead of 4,
* which meant that the "/../home/me" example actually became "home/me".
- * Using offset of 3 gives behavior consistent with the abovementioned
+ * Using offset of 3 gives behavior consistent with the aforementioned
* Python routine. */
memmove(path, path + 3, strlen(path + 3) + 1);
}
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.cc
index ab7a972e010..279682ea171 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.cc
@@ -30,6 +30,7 @@
#include "BLI_math.h"
#include "BLI_rand.h"
+#include "BLI_rand.hh"
#include "BLI_threads.h"
/* defines BLI_INLINE */
@@ -38,29 +39,22 @@
#include "BLI_strict_flags.h"
#include "BLI_sys_types.h"
-#define MULTIPLIER 0x5DEECE66Dll
-#define MASK 0x0000FFFFFFFFFFFFll
-#define MASK_BYTES 2
-
-#define ADDEND 0xB
-#define LOWSEED 0x330E
-
-extern unsigned char BLI_noise_hash_uchar_512[512]; /* noise.c */
+extern "C" unsigned char BLI_noise_hash_uchar_512[512]; /* noise.c */
#define hash BLI_noise_hash_uchar_512
/**
* Random Number Generator.
*/
struct RNG {
- uint64_t X;
+ blender::RandomNumberGenerator rng;
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("RNG")
};
RNG *BLI_rng_new(unsigned int seed)
{
- RNG *rng = MEM_mallocN(sizeof(*rng), "rng");
-
- BLI_rng_seed(rng, seed);
-
+ RNG *rng = new RNG();
+ rng->rng.seed(seed);
return rng;
}
@@ -69,26 +63,24 @@ RNG *BLI_rng_new(unsigned int seed)
*/
RNG *BLI_rng_new_srandom(unsigned int seed)
{
- RNG *rng = MEM_mallocN(sizeof(*rng), "rng");
-
- BLI_rng_srandom(rng, seed);
-
+ RNG *rng = new RNG();
+ rng->rng.seed_random(seed);
return rng;
}
RNG *BLI_rng_copy(RNG *rng)
{
- return MEM_dupallocN(rng);
+ return new RNG(*rng);
}
void BLI_rng_free(RNG *rng)
{
- MEM_freeN(rng);
+ delete rng;
}
void BLI_rng_seed(RNG *rng, unsigned int seed)
{
- rng->X = (((uint64_t)seed) << 16) | LOWSEED;
+ rng->rng.seed(seed);
}
/**
@@ -96,67 +88,23 @@ void BLI_rng_seed(RNG *rng, unsigned int seed)
*/
void BLI_rng_srandom(RNG *rng, unsigned int seed)
{
- BLI_rng_seed(rng, seed + hash[seed & 255]);
- seed = BLI_rng_get_uint(rng);
- BLI_rng_seed(rng, seed + hash[seed & 255]);
- seed = BLI_rng_get_uint(rng);
- BLI_rng_seed(rng, seed + hash[seed & 255]);
-}
-
-BLI_INLINE void rng_step(RNG *rng)
-{
- rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK;
+ rng->rng.seed_random(seed);
}
void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len)
{
- size_t last_len = 0;
- size_t trim_len = bytes_len;
-
-#define RAND_STRIDE (sizeof(rng->X) - MASK_BYTES)
-
- if (trim_len > RAND_STRIDE) {
- last_len = trim_len % RAND_STRIDE;
- trim_len = trim_len - last_len;
- }
- else {
- trim_len = 0;
- last_len = bytes_len;
- }
-
- const char *data_src = (void *)&(rng->X);
- size_t i = 0;
- while (i != trim_len) {
- BLI_assert(i < trim_len);
-#ifdef __BIG_ENDIAN__
- for (size_t j = (RAND_STRIDE + MASK_BYTES) - 1; j != MASK_BYTES - 1; j--)
-#else
- for (size_t j = 0; j != RAND_STRIDE; j++)
-#endif
- {
- bytes[i++] = data_src[j];
- }
- rng_step(rng);
- }
- if (last_len) {
- for (size_t j = 0; j != last_len; j++) {
- bytes[i++] = data_src[j];
- }
- }
-
-#undef RAND_STRIDE
+ BLI_assert(bytes_len > UINT32_MAX);
+ rng->rng.get_bytes(blender::MutableSpan(bytes, (uint32_t)bytes_len));
}
int BLI_rng_get_int(RNG *rng)
{
- rng_step(rng);
- return (int)(rng->X >> 17);
+ return rng->rng.get_int32();
}
unsigned int BLI_rng_get_uint(RNG *rng)
{
- rng_step(rng);
- return (unsigned int)(rng->X >> 17);
+ return rng->rng.get_uint32();
}
/**
@@ -164,7 +112,7 @@ unsigned int BLI_rng_get_uint(RNG *rng)
*/
double BLI_rng_get_double(RNG *rng)
{
- return (double)BLI_rng_get_int(rng) / 0x80000000;
+ return rng->rng.get_double();
}
/**
@@ -172,29 +120,17 @@ double BLI_rng_get_double(RNG *rng)
*/
float BLI_rng_get_float(RNG *rng)
{
- return (float)BLI_rng_get_int(rng) / 0x80000000;
+ return rng->rng.get_float();
}
void BLI_rng_get_float_unit_v2(RNG *rng, float v[2])
{
- float a = (float)(M_PI * 2.0) * BLI_rng_get_float(rng);
- v[0] = cosf(a);
- v[1] = sinf(a);
+ copy_v2_v2(v, rng->rng.get_unit_float2());
}
void BLI_rng_get_float_unit_v3(RNG *rng, float v[3])
{
- float r;
- v[2] = (2.0f * BLI_rng_get_float(rng)) - 1.0f;
- if ((r = 1.0f - (v[2] * v[2])) > 0.0f) {
- float a = (float)(M_PI * 2.0) * BLI_rng_get_float(rng);
- r = sqrtf(r);
- v[0] = r * cosf(a);
- v[1] = r * sinf(a);
- }
- else {
- v[2] = 1.0f;
- }
+ copy_v3_v3(v, rng->rng.get_unit_float3());
}
/**
@@ -203,27 +139,12 @@ void BLI_rng_get_float_unit_v3(RNG *rng, float v[3])
void BLI_rng_get_tri_sample_float_v2(
RNG *rng, const float v1[2], const float v2[2], const float v3[2], float r_pt[2])
{
- float u = BLI_rng_get_float(rng);
- float v = BLI_rng_get_float(rng);
-
- float side_u[2], side_v[2];
-
- if ((u + v) > 1.0f) {
- u = 1.0f - u;
- v = 1.0f - v;
- }
-
- sub_v2_v2v2(side_u, v2, v1);
- sub_v2_v2v2(side_v, v3, v1);
-
- copy_v2_v2(r_pt, v1);
- madd_v2_v2fl(r_pt, side_u, u);
- madd_v2_v2fl(r_pt, side_v, v);
+ copy_v2_v2(r_pt, rng->rng.get_triangle_sample(v1, v2, v3));
}
void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot)
{
- const size_t elem_size = (size_t)elem_size_i;
+ const uint elem_size = elem_size_i;
unsigned int i = elem_tot;
void *temp;
@@ -254,9 +175,7 @@ void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsig
*/
void BLI_rng_skip(RNG *rng, int n)
{
- while (n--) {
- rng_step(rng);
- }
+ rng->rng.skip((uint)n);
}
/***/
@@ -326,7 +245,8 @@ struct RNG_THREAD_ARRAY {
RNG_THREAD_ARRAY *BLI_rng_threaded_new(void)
{
unsigned int i;
- RNG_THREAD_ARRAY *rngarr = MEM_mallocN(sizeof(RNG_THREAD_ARRAY), "random_array");
+ RNG_THREAD_ARRAY *rngarr = (RNG_THREAD_ARRAY *)MEM_mallocN(sizeof(RNG_THREAD_ARRAY),
+ "random_array");
for (i = 0; i < BLENDER_MAX_THREADS; i++) {
BLI_rng_srandom(&rngarr->rng_tab[i], (unsigned int)clock());
@@ -382,7 +302,7 @@ void BLI_halton_1d(unsigned int prime, double offset, int n, double *r)
}
}
-void BLI_halton_2d(unsigned int prime[2], double offset[2], int n, double *r)
+void BLI_halton_2d(const unsigned int prime[2], double offset[2], int n, double *r)
{
const double invprimes[2] = {1.0 / (double)prime[0], 1.0 / (double)prime[1]};
@@ -395,7 +315,7 @@ void BLI_halton_2d(unsigned int prime[2], double offset[2], int n, double *r)
}
}
-void BLI_halton_3d(unsigned int prime[3], double offset[3], int n, double *r)
+void BLI_halton_3d(const unsigned int prime[3], double offset[3], int n, double *r)
{
const double invprimes[3] = {
1.0 / (double)prime[0], 1.0 / (double)prime[1], 1.0 / (double)prime[2]};
@@ -409,7 +329,7 @@ void BLI_halton_3d(unsigned int prime[3], double offset[3], int n, double *r)
}
}
-void BLI_halton_2d_sequence(unsigned int prime[2], double offset[2], int n, double *r)
+void BLI_halton_2d_sequence(const unsigned int prime[2], double offset[2], int n, double *r)
{
const double invprimes[2] = {1.0 / (double)prime[0], 1.0 / (double)prime[1]};
@@ -426,7 +346,7 @@ BLI_INLINE double radical_inverse(unsigned int n)
{
double u = 0;
- /* This reverse the bitwise representation
+ /* This reverse the bit-wise representation
* around the decimal point. */
for (double p = 0.5; n; p *= 0.5, n >>= 1) {
if (n & 1) {
@@ -449,3 +369,99 @@ void BLI_hammersley_2d_sequence(unsigned int n, double *r)
r[s * 2 + 1] = radical_inverse(s);
}
}
+
+namespace blender {
+
+/**
+ * Set a randomized hash of the value as seed.
+ */
+void RandomNumberGenerator::seed_random(uint32_t seed)
+{
+ this->seed(seed + hash[seed & 255]);
+ seed = this->get_uint32();
+ this->seed(seed + hash[seed & 255]);
+ seed = this->get_uint32();
+ this->seed(seed + hash[seed & 255]);
+}
+
+float2 RandomNumberGenerator::get_unit_float2()
+{
+ float a = (float)(M_PI * 2.0) * this->get_float();
+ return {cosf(a), sinf(a)};
+}
+
+float3 RandomNumberGenerator::get_unit_float3()
+{
+ float z = (2.0f * this->get_float()) - 1.0f;
+ float r = 1.0f - z * z;
+ if (r > 0.0f) {
+ float a = (float)(M_PI * 2.0) * this->get_float();
+ r = sqrtf(r);
+ float x = r * cosf(a);
+ float y = r * sinf(a);
+ return {x, y, z};
+ }
+ return {0.0f, 0.0f, 1.0f};
+}
+
+/**
+ * Generate a random point inside the given triangle.
+ */
+float2 RandomNumberGenerator::get_triangle_sample(float2 v1, float2 v2, float2 v3)
+{
+ float u = this->get_float();
+ float v = this->get_float();
+
+ if (u + v > 1.0f) {
+ u = 1.0f - u;
+ v = 1.0f - v;
+ }
+
+ float2 side_u = v2 - v1;
+ float2 side_v = v3 - v1;
+
+ float2 sample = v1;
+ sample += side_u * u;
+ sample += side_v * v;
+ return sample;
+}
+
+void RandomNumberGenerator::get_bytes(MutableSpan<char> r_bytes)
+{
+ constexpr uint mask_bytes = 2;
+ constexpr uint rand_stride = (uint)sizeof(x_) - mask_bytes;
+
+ uint last_len = 0;
+ uint trim_len = r_bytes.size();
+
+ if (trim_len > rand_stride) {
+ last_len = trim_len % rand_stride;
+ trim_len = trim_len - last_len;
+ }
+ else {
+ trim_len = 0;
+ last_len = r_bytes.size();
+ }
+
+ const char *data_src = (const char *)&x_;
+ uint i = 0;
+ while (i != trim_len) {
+ BLI_assert(i < trim_len);
+#ifdef __BIG_ENDIAN__
+ for (uint j = (rand_stride + mask_bytes) - 1; j != mask_bytes - 1; j--)
+#else
+ for (uint j = 0; j != rand_stride; j++)
+#endif
+ {
+ r_bytes[i++] = data_src[j];
+ }
+ this->step();
+ }
+ if (last_len) {
+ for (uint j = 0; j != last_len; j++) {
+ r_bytes[i++] = data_src[j];
+ }
+ }
+}
+
+} // namespace blender
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index f2217b1cd1a..d3191148c90 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -53,9 +53,9 @@
# include "BLI_string_utf8.h"
# include "BLI_winstuff.h"
# include "utfconv.h"
+# include <ShObjIdl.h>
# include <direct.h>
# include <io.h>
-# include <shobjidl_core.h>
# include <stdbool.h>
#else
# include <pwd.h>
@@ -275,25 +275,26 @@ eFileAttributes BLI_file_attributes(const char *path)
ret |= FILE_ATTR_REPARSE_POINT;
}
-# endif
+# else
-# ifdef __linux__
UNUSED_VARS(path);
/* TODO:
* If Immutable set FILE_ATTR_READONLY
* If Archived set FILE_ATTR_ARCHIVE
*/
-
# endif
-
return ret;
}
#endif
/* Return alias/shortcut file target. Apple version is defined in storage_apple.mm */
#ifndef __APPLE__
-bool BLI_file_alias_target(char target[FILE_MAXDIR], const char *filepath)
+bool BLI_file_alias_target(
+ /* This parameter can only be const on non-windows platforms.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ char target[FILE_MAXDIR],
+ const char *filepath)
{
# ifdef WIN32
if (!BLI_path_extension_check(filepath, ".lnk")) {
@@ -330,9 +331,7 @@ bool BLI_file_alias_target(char target[FILE_MAXDIR], const char *filepath)
}
return (success && target[0]);
-# endif
-
-# ifdef __linux__
+# else
UNUSED_VARS(target, filepath);
/* File-based redirection not supported. */
return false;
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 53db49aa59c..20edbb97561 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -111,7 +111,11 @@ void BLI_system_backtrace(FILE *fp)
/* NOTE: The code for CPU brand string is adopted from Cycles. */
#if !defined(_WIN32) || defined(FREE_WINDOWS)
-static void __cpuid(int data[4], int selector)
+static void __cpuid(
+ /* Cannot be const, because it is modified below.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ int data[4],
+ int selector)
{
# if defined(__x86_64__)
asm("cpuid" : "=a"(data[0]), "=b"(data[1]), "=c"(data[2]), "=d"(data[3]) : "a"(selector));
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 7acd9b071e1..a8333d0c696 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -176,9 +176,9 @@ void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int t
unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
if (level == 0) {
#ifdef USE_APPLE_OMP_FIX
- /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
- * we copy gomp thread local storage pointer to setting it again
- * inside the thread that we start */
+ /* Workaround for Apple gcc 4.2.1 OMP vs background thread bug,
+ * we copy GOMP thread local storage pointer to setting it again
+ * inside the thread that we start. */
thread_tls_data = pthread_getspecific(gomp_tls_key);
#endif
}
@@ -218,8 +218,8 @@ static void *tslot_thread_start(void *tslot_p)
ThreadSlot *tslot = (ThreadSlot *)tslot_p;
#ifdef USE_APPLE_OMP_FIX
- /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
- * set gomp thread local storage pointer which was copied beforehand */
+ /* Workaround for Apple gcc 4.2.1 OMP vs background thread bug,
+ * set GOMP thread local storage pointer which was copied beforehand */
pthread_setspecific(gomp_tls_key, thread_tls_data);
#endif
@@ -433,7 +433,7 @@ void BLI_mutex_free(ThreadMutex *mutex)
/* Spin Locks */
-#if WITH_TBB
+#ifdef WITH_TBB
static tbb::spin_mutex *tbb_spin_mutex_cast(SpinLock *spin)
{
static_assert(sizeof(SpinLock) >= sizeof(tbb::spin_mutex),
@@ -500,7 +500,7 @@ void BLI_spin_end(SpinLock *spin)
#elif defined(__APPLE__)
BLI_mutex_end(spin);
#elif defined(_MSC_VER)
- BLI_mutex_unlock(spin);
+ /* Nothing to do, spin is a simple integer type. */
#else
pthread_spin_destroy(spin);
#endif
diff --git a/source/blender/blenlib/intern/timeit.cc b/source/blender/blenlib/intern/timeit.cc
index 7938784da67..9e07e44ca12 100644
--- a/source/blender/blenlib/intern/timeit.cc
+++ b/source/blender/blenlib/intern/timeit.cc
@@ -16,8 +16,7 @@
#include "BLI_timeit.hh"
-namespace blender {
-namespace Timeit {
+namespace blender::timeit {
void print_duration(Nanoseconds duration)
{
@@ -32,5 +31,4 @@ void print_duration(Nanoseconds duration)
}
}
-} // namespace Timeit
-} // namespace blender
+} // namespace blender::timeit
diff --git a/source/blender/blenlib/intern/voronoi_2d.c b/source/blender/blenlib/intern/voronoi_2d.c
index 59270c58341..bc11a2c7a1c 100644
--- a/source/blender/blenlib/intern/voronoi_2d.c
+++ b/source/blender/blenlib/intern/voronoi_2d.c
@@ -213,7 +213,7 @@ static void voronoiParabola_setRight(VoronoiParabola *parabola, VoronoiParabola
right->parent = parabola;
}
-static float voronoi_getY(VoronoiProcess *process, float p[2], float x)
+static float voronoi_getY(VoronoiProcess *process, const float p[2], float x)
{
float ly = process->current_y;
diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c
index c7c794957c2..2c8eb9f5a13 100644
--- a/source/blender/blenlib/intern/voxel.c
+++ b/source/blender/blenlib/intern/voxel.c
@@ -26,7 +26,7 @@
#include "BLI_strict_flags.h"
-BLI_INLINE float D(float *data, const int res[3], int x, int y, int z)
+BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
{
CLAMP(x, 0, res[0] - 1);
CLAMP(y, 0, res[1] - 1);
@@ -36,7 +36,7 @@ BLI_INLINE float D(float *data, const int res[3], int x, int y, int z)
/* *** nearest neighbor *** */
/* input coordinates must be in bounding box 0.0 - 1.0 */
-float BLI_voxel_sample_nearest(float *data, const int res[3], const float co[3])
+float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3])
{
int xi, yi, zi;
@@ -65,7 +65,7 @@ BLI_INLINE int64_t _clamp(int a, int b, int c)
return (a < b) ? b : ((a > c) ? c : a);
}
-float BLI_voxel_sample_trilinear(float *data, const int res[3], const float co[3])
+float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3])
{
if (data) {
@@ -106,7 +106,7 @@ float BLI_voxel_sample_trilinear(float *data, const int res[3], const float co[3
return 0.f;
}
-float BLI_voxel_sample_triquadratic(float *data, const int res[3], const float co[3])
+float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3])
{
if (data) {
@@ -161,7 +161,10 @@ float BLI_voxel_sample_triquadratic(float *data, const int res[3], const float c
return 0.f;
}
-float BLI_voxel_sample_tricubic(float *data, const int res[3], const float co[3], int bspline)
+float BLI_voxel_sample_tricubic(const float *data,
+ const int res[3],
+ const float co[3],
+ int bspline)
{
if (data) {
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
index 59116b4eefc..7c9738b67c5 100644
--- a/source/blender/blenloader/BLO_read_write.h
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -180,7 +180,7 @@ bool BLO_write_is_undo(BlendWriter *writer);
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address);
#define BLO_read_data_address(reader, ptr_p) \
- *(ptr_p) = BLO_read_get_new_data_address((reader), *(ptr_p))
+ *((void **)ptr_p) = BLO_read_get_new_data_address((reader), *(ptr_p))
typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data);
void BLO_read_list_cb(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback);
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 09e2f4bf417..7eab0651d97 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -63,8 +63,8 @@ set(SRC
BLO_blend_defs.h
BLO_blend_validate.h
- BLO_readfile.h
BLO_read_write.h
+ BLO_readfile.h
BLO_undofile.h
BLO_writefile.h
intern/readfile.h
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index e4129282a68..cb2094d050f 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -390,12 +390,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
blo_make_old_idmap_from_main(fd, old_mainlist.first);
}
- /* TODO: Move handling of nodetree caches to new system as well... */
- /* makes lookup of existing images in old main */
- blo_make_image_pointer_map(fd, oldmain);
- /* makes lookup of existing video clips in old main */
- blo_make_movieclip_pointer_map(fd, oldmain);
-
/* removed packed data from this trick - it's internal data that needs saves */
/* Store all existing ID caches pointers into a mapping, to allow restoring them into newly
@@ -407,12 +401,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
/* Ensure relinked caches are not freed together with their old IDs. */
blo_cache_storage_old_bmain_clear(fd, oldmain);
- /* TODO: Move handling of nodetree caches to new system as well... */
- /* ensures relinked images are not freed */
- blo_end_image_pointer_map(fd, oldmain);
- /* ensures relinked movie clips are not freed */
- blo_end_movieclip_pointer_map(fd, oldmain);
-
/* Still in-use libraries have already been moved from oldmain to new mainlist,
* but oldmain itself shall *never* be 'transferred' to new mainlist! */
BLI_assert(old_mainlist.first == oldmain);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 836260c46e5..44a1a6ec44a 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1613,21 +1613,6 @@ void blo_filedata_free(FileData *fd)
if (fd->globmap) {
oldnewmap_free(fd->globmap);
}
- if (fd->imamap) {
- oldnewmap_free(fd->imamap);
- }
- if (fd->movieclipmap) {
- oldnewmap_free(fd->movieclipmap);
- }
- if (fd->scenemap) {
- oldnewmap_free(fd->scenemap);
- }
- if (fd->soundmap) {
- oldnewmap_free(fd->soundmap);
- }
- if (fd->volumemap) {
- oldnewmap_free(fd->volumemap);
- }
if (fd->packedmap) {
oldnewmap_free(fd->packedmap);
}
@@ -1804,51 +1789,6 @@ static void *newglobadr(FileData *fd, const void *adr)
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
}
-/* used to restore image data after undo */
-static void *newimaadr(FileData *fd, const void *adr)
-{
- if (fd->imamap && adr) {
- return oldnewmap_lookup_and_inc(fd->imamap, adr, true);
- }
- return NULL;
-}
-
-/* used to restore scene data after undo */
-static void *newsceadr(FileData *fd, const void *adr)
-{
- if (fd->scenemap && adr) {
- return oldnewmap_lookup_and_inc(fd->scenemap, adr, true);
- }
- return NULL;
-}
-
-/* used to restore movie clip data after undo */
-static void *newmclipadr(FileData *fd, const void *adr)
-{
- if (fd->movieclipmap && adr) {
- return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true);
- }
- return NULL;
-}
-
-/* used to restore sound data after undo */
-static void *newsoundadr(FileData *fd, const void *adr)
-{
- if (fd->soundmap && adr) {
- return oldnewmap_lookup_and_inc(fd->soundmap, adr, true);
- }
- return NULL;
-}
-
-/* used to restore volume data after undo */
-static void *newvolumeadr(FileData *fd, const void *adr)
-{
- if (fd->volumemap && adr) {
- return oldnewmap_lookup_and_inc(fd->volumemap, adr, true);
- }
- return NULL;
-}
-
/* used to restore packed data after undo */
static void *newpackedadr(FileData *fd, const void *adr)
{
@@ -1926,201 +1866,6 @@ void blo_clear_proxy_pointers_from_lib(Main *oldmain)
}
}
-void blo_make_scene_pointer_map(FileData *fd, Main *oldmain)
-{
- Scene *sce = oldmain->scenes.first;
-
- fd->scenemap = oldnewmap_new();
-
- for (; sce; sce = sce->id.next) {
- if (sce->eevee.light_cache_data) {
- struct LightCache *light_cache = sce->eevee.light_cache_data;
- oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0);
- }
- }
-}
-
-void blo_end_scene_pointer_map(FileData *fd, Main *oldmain)
-{
- OldNew *entry = fd->scenemap->entries;
- Scene *sce = oldmain->scenes.first;
- int i;
-
- /* used entries were restored, so we put them to zero */
- for (i = 0; i < fd->scenemap->nentries; i++, entry++) {
- if (entry->nr > 0) {
- entry->newp = NULL;
- }
- }
-
- for (; sce; sce = sce->id.next) {
- sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data);
- }
-}
-
-void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
-{
- Scene *sce = oldmain->scenes.first;
- fd->imamap = oldnewmap_new();
-
- for (; sce; sce = sce->id.next) {
- if (sce->nodetree && sce->nodetree->previews) {
- bNodeInstanceHashIterator iter;
- NODE_INSTANCE_HASH_ITER (iter, sce->nodetree->previews) {
- bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- oldnewmap_insert(fd->imamap, preview, preview, 0);
- }
- }
- }
-}
-
-/* set old main image ibufs to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
-void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
-{
- OldNew *entry = fd->imamap->entries;
- Scene *sce = oldmain->scenes.first;
- int i;
-
- /* used entries were restored, so we put them to zero */
- for (i = 0; i < fd->imamap->nentries; i++, entry++) {
- if (entry->nr > 0) {
- entry->newp = NULL;
- }
- }
-
- for (; sce; sce = sce->id.next) {
- if (sce->nodetree && sce->nodetree->previews) {
- bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
- bNodeInstanceHashIterator iter;
-
- /* reconstruct the preview hash, only using remaining pointers */
- NODE_INSTANCE_HASH_ITER (iter, sce->nodetree->previews) {
- bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- if (preview) {
- bNodePreview *new_preview = newimaadr(fd, preview);
- if (new_preview) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- BKE_node_instance_hash_insert(new_previews, key, new_preview);
- }
- }
- }
- BKE_node_instance_hash_free(sce->nodetree->previews, NULL);
- sce->nodetree->previews = new_previews;
- }
- }
-}
-
-void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain)
-{
- Scene *sce = oldmain->scenes.first;
-
- fd->movieclipmap = oldnewmap_new();
-
- for (; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_MOVIEDISTORTION) {
- oldnewmap_insert(fd->movieclipmap, node->storage, node->storage, 0);
- }
- }
- }
- }
-}
-
-/* set old main movie clips caches to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
-void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain)
-{
- OldNew *entry = fd->movieclipmap->entries;
- Scene *sce = oldmain->scenes.first;
- int i;
-
- /* used entries were restored, so we put them to zero */
- for (i = 0; i < fd->movieclipmap->nentries; i++, entry++) {
- if (entry->nr > 0) {
- entry->newp = NULL;
- }
- }
-
- for (; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_MOVIEDISTORTION) {
- node->storage = newmclipadr(fd, node->storage);
- }
- }
- }
- }
-}
-
-void blo_make_sound_pointer_map(FileData *fd, Main *oldmain)
-{
- bSound *sound = oldmain->sounds.first;
-
- fd->soundmap = oldnewmap_new();
-
- for (; sound; sound = sound->id.next) {
- if (sound->waveform) {
- oldnewmap_insert(fd->soundmap, sound->waveform, sound->waveform, 0);
- }
- }
-}
-
-/* set old main sound caches to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
-void blo_end_sound_pointer_map(FileData *fd, Main *oldmain)
-{
- OldNew *entry = fd->soundmap->entries;
- bSound *sound = oldmain->sounds.first;
- int i;
-
- /* used entries were restored, so we put them to zero */
- for (i = 0; i < fd->soundmap->nentries; i++, entry++) {
- if (entry->nr > 0) {
- entry->newp = NULL;
- }
- }
-
- for (; sound; sound = sound->id.next) {
- sound->waveform = newsoundadr(fd, sound->waveform);
- }
-}
-
-void blo_make_volume_pointer_map(FileData *fd, Main *oldmain)
-{
- fd->volumemap = oldnewmap_new();
-
- Volume *volume = oldmain->volumes.first;
- for (; volume; volume = volume->id.next) {
- if (volume->runtime.grids) {
- oldnewmap_insert(fd->volumemap, volume->runtime.grids, volume->runtime.grids, 0);
- }
- }
-}
-
-/* set old main volume caches to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
-void blo_end_volume_pointer_map(FileData *fd, Main *oldmain)
-{
- OldNew *entry = fd->volumemap->entries;
- Volume *volume = oldmain->volumes.first;
- int i;
-
- /* used entries were restored, so we put them to zero */
- for (i = 0; i < fd->volumemap->nentries; i++, entry++) {
- if (entry->nr > 0) {
- entry->newp = NULL;
- }
- }
-
- for (; volume; volume = volume->id.next) {
- volume->runtime.grids = newvolumeadr(fd, volume->runtime.grids);
- }
-}
-
/* XXX disabled this feature - packed files also belong in temp saves and quit.blend,
* to make restore work. */
@@ -2263,6 +2008,7 @@ typedef struct BLOCacheStorage {
static void blo_cache_storage_entry_register(ID *id,
const IDCacheKey *key,
void **UNUSED(cache_p),
+ eIDTypeInfoCacheCallbackFlags UNUSED(flags),
void *cache_storage_v)
{
BLI_assert(key->id_session_uuid == id->session_uuid);
@@ -2280,12 +2026,18 @@ static void blo_cache_storage_entry_register(ID *id,
static void blo_cache_storage_entry_restore_in_new(ID *UNUSED(id),
const IDCacheKey *key,
void **cache_p,
+ eIDTypeInfoCacheCallbackFlags flags,
void *cache_storage_v)
{
BLOCacheStorage *cache_storage = cache_storage_v;
if (cache_storage == NULL) {
- *cache_p = NULL;
+ /* In non-undo case, only clear the pointer if it is a purely runtime one.
+ * If it may be stored in a persistent way in the .blend file, direct_link code is responsible
+ * to properly deal with it. */
+ if ((flags & IDTYPE_CACHE_CB_FLAGS_PERSISTENT) == 0) {
+ *cache_p = NULL;
+ }
return;
}
@@ -2302,6 +2054,7 @@ static void blo_cache_storage_entry_restore_in_new(ID *UNUSED(id),
static void blo_cache_storage_entry_clear_in_old(ID *UNUSED(id),
const IDCacheKey *key,
void **cache_p,
+ eIDTypeInfoCacheCallbackFlags UNUSED(flags),
void *cache_storage_v)
{
BLOCacheStorage *cache_storage = cache_storage_v;
@@ -2341,7 +2094,7 @@ void blo_cache_storage_init(FileData *fd, Main *bmain)
if (ID_IS_LINKED(id)) {
continue;
}
- type_info->foreach_cache(id, blo_cache_storage_entry_register, fd->cache_storage);
+ BKE_idtype_id_foreach_cache(id, blo_cache_storage_entry_register, fd->cache_storage);
}
FOREACH_MAIN_LISTBASE_ID_END;
}
@@ -2371,7 +2124,7 @@ void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
if (ID_IS_LINKED(id)) {
continue;
}
- type_info->foreach_cache(id, blo_cache_storage_entry_clear_in_old, fd->cache_storage);
+ BKE_idtype_id_foreach_cache(id, blo_cache_storage_entry_clear_in_old, fd->cache_storage);
}
FOREACH_MAIN_LISTBASE_ID_END;
}
@@ -3744,7 +3497,8 @@ static void direct_link_nodetree(BlendDataReader *reader, bNodeTree *ntree)
}
if (node->type == CMP_NODE_MOVIEDISTORTION) {
- node->storage = newmclipadr(reader->fd, node->storage);
+ /* Do nothing, this is runtime cache and hence handled by generic code using
+ * `IDTypeInfo.foreach_cache` callback. */
}
else {
BLO_read_data_address(reader, &node->storage);
@@ -3843,28 +3597,8 @@ static void direct_link_nodetree(BlendDataReader *reader, bNodeTree *ntree)
BLO_read_data_address(reader, &link->tosock);
}
-#if 0
- if (ntree->previews) {
- bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews");
- bNodeInstanceHashIterator iter;
-
- NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
- bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter);
- if (preview) {
- bNodePreview* new_preview = newimaadr(fd, preview);
- if (new_preview) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- BKE_node_instance_hash_insert(new_previews, key, new_preview);
- }
- }
- }
- BKE_node_instance_hash_free(ntree->previews, NULL);
- ntree->previews = new_previews;
- }
-#else
- /* XXX TODO */
+ /* TODO, should be dealt by new generic cache handling of IDs... */
ntree->previews = NULL;
-#endif
/* type verification is in lib-link */
}
@@ -8952,6 +8686,7 @@ static void direct_link_simulation(BlendDataReader *reader, Simulation *simulati
BLO_read_list(reader, &simulation->states);
LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
+ BLO_read_data_address(reader, &state->name);
switch ((eSimulationStateType)state->type) {
case SIM_STATE_TYPE_PARTICLES: {
ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
@@ -9234,7 +8969,8 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *
/* try to restore (when undoing) or clear ID's cache pointers. */
if (id_type->foreach_cache != NULL) {
- id_type->foreach_cache(id, blo_cache_storage_entry_restore_in_new, reader.fd->cache_storage);
+ BKE_idtype_id_foreach_cache(
+ id, blo_cache_storage_entry_restore_in_new, reader.fd->cache_storage);
}
return success;
@@ -9249,8 +8985,8 @@ static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *all
void *data;
#if 0
/* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
- short* sp = fd->filesdna->structs[bhead->SDNAnr];
- char* tmp = malloc(100);
+ short *sp = fd->filesdna->structs[bhead->SDNAnr];
+ char *tmp = malloc(100);
allocname = fd->filesdna->types[sp[0]];
strcpy(tmp, allocname);
data = read_struct(fd, bhead, tmp);
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 57c86f7128c..f8c91c77634 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -116,11 +116,6 @@ typedef struct FileData {
struct OldNewMap *datamap;
struct OldNewMap *globmap;
struct OldNewMap *libmap;
- struct OldNewMap *imamap;
- struct OldNewMap *movieclipmap;
- struct OldNewMap *scenemap;
- struct OldNewMap *soundmap;
- struct OldNewMap *volumemap;
struct OldNewMap *packedmap;
struct BLOCacheStorage *cache_storage;
@@ -154,16 +149,6 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile,
struct ReportList *reports);
void blo_clear_proxy_pointers_from_lib(struct Main *oldmain);
-void blo_make_image_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_end_image_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_make_scene_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_end_scene_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_make_movieclip_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_end_movieclip_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_make_sound_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_end_sound_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_make_volume_pointer_map(FileData *fd, struct Main *oldmain);
-void blo_end_volume_pointer_map(FileData *fd, struct Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain);
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 0d16b58d28f..ba92e11cc2a 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -21,6 +21,7 @@
#define DNA_DEPRECATED_ALLOW
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
@@ -36,6 +37,7 @@
#include "BKE_colortools.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BLO_readfile.h"
#include "readfile.h"
@@ -255,6 +257,28 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Initialize parameters of the new Nishita sky model. */
+ if (!DNA_struct_elem_find(fd->filesdna, "NodeTexSky", "float", "sun_size")) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_TEX_SKY && node->storage) {
+ NodeTexSky *tex = (NodeTexSky *)node->storage;
+ tex->sun_disc = true;
+ tex->sun_size = DEG2RADF(0.545);
+ tex->sun_elevation = M_PI_2;
+ tex->sun_rotation = 0.0f;
+ tex->altitude = 0.0f;
+ tex->air_density = 1.0f;
+ tex->dust_density = 1.0f;
+ tex->ozone_density = 1.0f;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
if (!MAIN_VERSION_ATLEAST(bmain, 290, 6)) {
@@ -365,5 +389,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Initialize additional parameter of the Nishita sky model and change altitude unit. */
+ if (!DNA_struct_elem_find(fd->filesdna, "NodeTexSky", "float", "sun_intensity")) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_TEX_SKY && node->storage) {
+ NodeTexSky *tex = (NodeTexSky *)node->storage;
+ tex->sun_intensity = 1.0f;
+ tex->altitude *= 0.001f;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 1217b69f1b5..7f75c0100b8 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -315,7 +315,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
copy_v2_fl2(scene->safe_areas.title, 0.1f, 0.05f);
copy_v2_fl2(scene->safe_areas.action, 0.035f, 0.035f);
- /* Change default cubemap quality. */
+ /* Change default cube-map quality. */
scene->eevee.gi_filter_quality = 3.0f;
/* Enable Soft Shadows by default. */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 2ce8abff3c5..4e2b4fef9a0 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -3832,6 +3832,7 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const
}
LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
+ BLO_write_string(writer, state->name);
switch ((eSimulationStateType)state->type) {
case SIM_STATE_TYPE_PARTICLES: {
ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 7a389c63abd..0943b4a9c2a 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -118,6 +118,8 @@ set(SRC
intern/bmesh_query.c
intern/bmesh_query.h
intern/bmesh_query_inline.h
+ intern/bmesh_query_uv.c
+ intern/bmesh_query_uv.h
intern/bmesh_structure.c
intern/bmesh_structure.h
intern/bmesh_structure_inline.h
@@ -151,6 +153,8 @@ set(SRC
tools/bmesh_path.h
tools/bmesh_path_region.c
tools/bmesh_path_region.h
+ tools/bmesh_path_uv.c
+ tools/bmesh_path_uv.h
tools/bmesh_region_match.c
tools/bmesh_region_match.h
tools/bmesh_separate.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index c0791e6fdbc..c1f4b9daf27 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -223,6 +223,7 @@ extern "C" {
#include "intern/bmesh_polygon.h"
#include "intern/bmesh_polygon_edgenet.h"
#include "intern/bmesh_query.h"
+#include "intern/bmesh_query_uv.h"
#include "intern/bmesh_walkers.h"
#include "intern/bmesh_inline.h"
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index d0e91d033fb..a0dc6abf009 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -36,6 +36,7 @@ extern "C" {
#include "tools/bmesh_edgesplit.h"
#include "tools/bmesh_path.h"
#include "tools/bmesh_path_region.h"
+#include "tools/bmesh_path_uv.h"
#include "tools/bmesh_region_match.h"
#include "tools/bmesh_separate.h"
#include "tools/bmesh_triangulate.h"
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 35fb698eac1..4e9775bcfa7 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -101,6 +101,7 @@ BMVert *BM_vert_create(BMesh *bm,
/* may add to middle of the pool */
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
bm->totvert++;
@@ -190,6 +191,7 @@ BMEdge *BM_edge_create(
/* may add to middle of the pool */
bm->elem_index_dirty |= BM_EDGE;
bm->elem_table_dirty |= BM_EDGE;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
bm->totedge++;
@@ -259,6 +261,7 @@ static BMLoop *bm_loop_create(BMesh *bm,
/* may add to middle of the pool */
bm->elem_index_dirty |= BM_LOOP;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
bm->totloop++;
@@ -402,6 +405,7 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
/* may add to middle of the pool */
bm->elem_index_dirty |= BM_FACE;
bm->elem_table_dirty |= BM_FACE;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
bm->totface++;
@@ -748,6 +752,7 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v)
bm->totvert--;
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
BM_select_history_remove(bm, v);
@@ -770,6 +775,7 @@ static void bm_kill_only_edge(BMesh *bm, BMEdge *e)
bm->totedge--;
bm->elem_index_dirty |= BM_EDGE;
bm->elem_table_dirty |= BM_EDGE;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
BM_select_history_remove(bm, (BMElem *)e);
@@ -796,6 +802,7 @@ static void bm_kill_only_face(BMesh *bm, BMFace *f)
bm->totface--;
bm->elem_index_dirty |= BM_FACE;
bm->elem_table_dirty |= BM_FACE;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
BM_select_history_remove(bm, (BMElem *)f);
@@ -817,6 +824,8 @@ static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
{
bm->totloop--;
bm->elem_index_dirty |= BM_LOOP;
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+
if (l->head.data) {
CustomData_bmesh_free_block(&bm->ldata, &l->head.data);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index ffe84f93679..8eed3141c7f 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -2377,6 +2377,27 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index)
return BLI_mempool_findelem(bm->fpool, index);
}
+BMLoop *BM_loop_at_index_find(BMesh *bm, const int index)
+{
+ BMIter iter;
+ BMFace *f;
+ int i = index;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (i < f->len) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (i == 0) {
+ return l_iter;
+ }
+ i -= 1;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ i -= f->len;
+ }
+ return NULL;
+}
+
/**
* Use lookup table when available, else use slower find functions.
*
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 4ba0d948499..0d665f1d391 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -118,6 +118,7 @@ BLI_INLINE BMFace *BM_face_at_index(BMesh *bm, const int index)
BMVert *BM_vert_at_index_find(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
+BMLoop *BM_loop_at_index_find(BMesh *bm, const int index);
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index fe67abf6aa5..80634618f6f 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -158,6 +158,37 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
}
/**
+ * Return the other loop that uses this edge.
+ *
+ * In this case the loop defines the vertex,
+ * the edge passed in defines the direction to step.
+ *
+ * <pre>
+ * +----------+ <-- Return the face-loop of this vertex.
+ * | |
+ * | e | <-- This edge defines the direction.
+ * | |
+ * +----------+ <-- This loop defines the face and vertex..
+ * l
+ * </pre>
+ *
+ */
+BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
+{
+ BLI_assert(BM_vert_in_edge(e, l->v));
+ if (l->e == e) {
+ return l->next;
+ }
+ else if (l->prev->e == e) {
+ return l->prev;
+ }
+ else {
+ BLI_assert(0);
+ return NULL;
+ }
+}
+
+/**
* Check if verts share a face.
*/
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 7e07059d4d8..0d95efb778f 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -48,6 +48,8 @@ BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSE
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -171,7 +173,6 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e,
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
ATTR_NONNULL();
-
float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.c b/source/blender/bmesh/intern/bmesh_query_uv.c
new file mode 100644
index 00000000000..b9ea51f0c4d
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_query_uv.c
@@ -0,0 +1,169 @@
+/*
+ * 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 bmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_utildefines_stack.h"
+
+#include "BKE_customdata.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_private.h"
+
+static void uv_aspect(const BMLoop *l,
+ const float aspect[2],
+ const int cd_loop_uv_offset,
+ float r_uv[2])
+{
+ const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
+ r_uv[0] = uv[0] * aspect[0];
+ r_uv[1] = uv[1] * aspect[1];
+}
+
+/**
+ * Typically we avoid hiding arguments,
+ * make this an exception since it reads poorly with so many repeated arguments.
+ */
+#define UV_ASPECT(l, r_uv) uv_aspect(l, aspect, cd_loop_uv_offset, r_uv)
+
+/**
+ * Computes the UV center of a face, using the mean average weighted by edge length.
+ *
+ * See #BM_face_calc_center_median_weighted for matching spatial functionality.
+ *
+ * \param aspect: Calculate the center scaling by these values, and finally dividing.
+ * Since correct weighting depends on having the correct aspect.
+ */
+void BM_face_uv_calc_center_median_weighted(const BMFace *f,
+ const float aspect[2],
+ const int cd_loop_uv_offset,
+ float r_cent[2])
+{
+ const BMLoop *l_iter;
+ const BMLoop *l_first;
+ float totw = 0.0f;
+ float w_prev;
+
+ zero_v2(r_cent);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ float uv_prev[2], uv_curr[2];
+ UV_ASPECT(l_iter->prev, uv_prev);
+ UV_ASPECT(l_iter, uv_curr);
+ w_prev = len_v2v2(uv_prev, uv_curr);
+ do {
+ float uv_next[2];
+ UV_ASPECT(l_iter->next, uv_next);
+ const float w_curr = len_v2v2(uv_curr, uv_next);
+ const float w = (w_curr + w_prev);
+ madd_v2_v2fl(r_cent, uv_curr, w);
+ totw += w;
+ w_prev = w_curr;
+ copy_v2_v2(uv_curr, uv_next);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (totw != 0.0f) {
+ mul_v2_fl(r_cent, 1.0f / (float)totw);
+ }
+ /* Reverse aspect. */
+ r_cent[0] /= aspect[0];
+ r_cent[1] /= aspect[1];
+}
+
+#undef UV_ASPECT
+
+/**
+ * Calculate the UV cross product (use the sign to check the winding).
+ */
+float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
+{
+ float(*uvs)[2] = BLI_array_alloca(uvs, f->len);
+ const BMLoop *l_iter;
+ const BMLoop *l_first;
+ int i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ copy_v2_v2(uvs[i++], luv->uv);
+ } while ((l_iter = l_iter->next) != l_first);
+ return cross_poly_v2(uvs, f->len);
+}
+
+/**
+ * Check if two loops that share an edge also have the same UV coordinates.
+ */
+bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
+{
+ BLI_assert(l_a->e == l_b->e);
+ MLoopUV *luv_a_curr = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset);
+ MLoopUV *luv_a_next = BM_ELEM_CD_GET_VOID_P(l_a->next, cd_loop_uv_offset);
+ MLoopUV *luv_b_curr = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset);
+ MLoopUV *luv_b_next = BM_ELEM_CD_GET_VOID_P(l_b->next, cd_loop_uv_offset);
+ if (l_a->v != l_b->v) {
+ SWAP(MLoopUV *, luv_b_curr, luv_b_next);
+ }
+ return (equals_v2v2(luv_a_curr->uv, luv_b_curr->uv) &&
+ equals_v2v2(luv_a_next->uv, luv_b_next->uv));
+}
+
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
+bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
+{
+ BLI_assert(l_a->v == l_b->v);
+ const MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset);
+ const MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset);
+ if (!equals_v2v2(luv_a->uv, luv_b->uv)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
+bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
+{
+ BLI_assert(l_a->v == l_b->v);
+ if (!BM_loop_uv_share_vert_check(l_a, l_b, cd_loop_uv_offset)) {
+ return false;
+ }
+
+ /* No need for NULL checks, these will always succeed. */
+ const BMLoop *l_other_a = BM_loop_other_vert_loop_by_edge(l_a, e);
+ const BMLoop *l_other_b = BM_loop_other_vert_loop_by_edge(l_b, e);
+
+ {
+ const MLoopUV *luv_other_a = BM_ELEM_CD_GET_VOID_P(l_other_a, cd_loop_uv_offset);
+ const MLoopUV *luv_other_b = BM_ELEM_CD_GET_VOID_P(l_other_b, cd_loop_uv_offset);
+ if (!equals_v2v2(luv_other_a->uv, luv_other_b->uv)) {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.h b/source/blender/bmesh/intern/bmesh_query_uv.h
new file mode 100644
index 00000000000..293715a8c69
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_query_uv.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef __BMESH_QUERY_UV_H__
+#define __BMESH_QUERY_UV_H__
+
+/** \file
+ * \ingroup bmesh
+ */
+
+float BM_loop_uv_calc_edge_length_squared(const BMLoop *l,
+ const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+float BM_loop_uv_calc_edge_length(const BMLoop *l,
+ const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
+void BM_face_uv_calc_center_median_weighted(const BMFace *f,
+ const float aspect[2],
+ const int cd_loop_uv_offset,
+ float r_cent[2]) ATTR_NONNULL();
+
+float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
+bool BM_loop_uv_share_edge_check(BMLoop *l_a,
+ BMLoop *l_b,
+ const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
+bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+bool BM_loop_uv_share_vert_check(BMLoop *l_a,
+ BMLoop *l_b,
+ const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
+#endif /* __BMESH_QUERY_UV_H__ */
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index c6813a864a8..0789000969e 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -280,7 +280,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
* last resort when all else fails.
*/
if (totv > 2) {
- /* TODO, some of these vertes may be connected by edges,
+ /* TODO, some of these vertices may be connected by edges,
* this connectivity could be used rather than treating
* them as a bunch of isolated verts. */
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 3c63f4a60d6..eee31969971 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -572,6 +572,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
#endif
+ bm_extrude_copy_face_loop_attributes(bm, f);
if (join_face) {
BMVert *v1 = e->v1;
BMVert *v2 = e->v2;
@@ -583,11 +584,11 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
BMO_elem_flag_enable(bm, v2, EXT_TAG);
dissolve_verts[dissolve_verts_len++] = v2;
}
+ /* Tag the edges that can collapse. */
+ BMO_elem_flag_enable(bm, f_edges[0], EXT_TAG);
+ BMO_elem_flag_enable(bm, f_edges[1], EXT_TAG);
bmesh_kernel_join_face_kill_edge(bm, join_face, f, e);
}
- else {
- bm_extrude_copy_face_loop_attributes(bm, f);
- }
}
/* link isolated vert */
@@ -613,7 +614,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
if ((e_other == e) || (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
/* Lose edge or BMVert is edge pair. */
- BM_edge_collapse(bm, e, v, true, false);
+ BM_edge_collapse(bm, BMO_elem_flag_test(bm, e, EXT_TAG) ? e : e_other, v, true, false);
}
else {
BLI_assert(!BM_vert_is_edge_pair(v));
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index b109dc3199a..626d58f75f8 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -1353,8 +1353,9 @@ static void offset_meet(EdgeHalf *e1,
/**
* Calculate the meeting point between e1 and e2 (one of which should have zero offsets),
- * where e1 precedes e2 in CCW order around their common vertex v (viewed from normal side).
- * If r_angle is provided, return the angle between e and emeet in *r_angle.
+ * where \a e1 precedes \a e2 in CCW order around their common vertex \a v
+ * (viewed from normal side).
+ * If \a r_angle is provided, return the angle between \a e and \a meetco in `*r_angle`.
* If the angle is 0, or it is 180 degrees or larger, there will be no meeting point;
* return false in that case, else true.
*/
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index 99a5a9edb57..52231033fd3 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -833,15 +833,37 @@ bool BM_mesh_intersect_edges(
}
if (pair_array) {
+ BMVert *v_key, *v_val;
pair_iter = &pair_array[0];
for (i = 0; i < pair_len; i++, pair_iter++) {
BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT);
BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT);
BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem);
- BMVert *v_key, *v_val;
v_key = (*pair_iter)[0].vert;
v_val = (*pair_iter)[1].vert;
BLI_ghash_insert(r_targetmap, v_key, v_val);
+ }
+
+ /**
+ * The weld_verts operator works best when all keys in the same group of
+ * collapsed vertices point to the same vertex.
+ * That is, if the pairs of vertices are:
+ * [1, 2], [2, 3] and [3, 4],
+ * They are better adjusted to:
+ * [1, 4], [2, 4] and [3, 4].
+ */
+ pair_iter = &pair_array[0];
+ for (i = 0; i < pair_len; i++, pair_iter++) {
+ v_key = (*pair_iter)[0].vert;
+ v_val = (*pair_iter)[1].vert;
+ BMVert *v_target;
+ while ((v_target = BLI_ghash_lookup(r_targetmap, v_val))) {
+ v_val = v_target;
+ }
+ if (v_val != (*pair_iter)[1].vert) {
+ BMVert **v_val_p = (BMVert **)BLI_ghash_lookup_p(r_targetmap, v_key);
+ *v_val_p = (*pair_iter)[1].vert = v_val;
+ }
if (split_faces) {
/* The vertex index indicates its position in the pair_array flat. */
BM_elem_index_set(v_key, i * 2);
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 713a68969e5..cb75f47acf3 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -18,6 +18,8 @@
* \ingroup bmesh
*
* Find a path between 2 elements.
+ *
+ * \note All 3 functions are similar, changes to one most likely apply to another.
*/
#include "MEM_guardedalloc.h"
@@ -29,8 +31,11 @@
#include "bmesh.h"
#include "bmesh_path.h" /* own include */
+#define COST_INIT_MAX FLT_MAX
+
/* -------------------------------------------------------------------- */
-/* Generic Helpers */
+/** \name Generic Helpers
+ * \{ */
/**
* Use skip options when we want to start measuring from a boundary.
@@ -40,16 +45,15 @@ static float step_cost_3_v3_ex(
{
float d1[3], d2[3];
- /* The cost is based on the simple sum of the length of the two edgees... */
+ /* The cost is based on the simple sum of the length of the two edges. */
sub_v3_v3v3(d1, v2, v1);
sub_v3_v3v3(d2, v3, v2);
const float cost_12 = normalize_v3(d1);
const float cost_23 = normalize_v3(d2);
const float cost = ((skip_12 ? 0.0f : cost_12) + (skip_23 ? 0.0f : cost_23));
- /* but is biased to give higher values to sharp turns, so that it will take
- * paths with fewer "turns" when selecting between equal-weighted paths between
- * the two edges */
+ /* But is biased to give higher values to sharp turns, so that it will take paths with
+ * fewer "turns" when selecting between equal-weighted paths between the two edges. */
return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2)))));
}
@@ -58,8 +62,11 @@ static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3
return step_cost_3_v3_ex(v1, v2, v3, false, false);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* BM_mesh_calc_path_vert */
+/** \name BM_mesh_calc_path_vert
+ * \{ */
static void verttag_add_adjacent(HeapSimple *heap,
BMVert *v_a,
@@ -72,11 +79,11 @@ static void verttag_add_adjacent(HeapSimple *heap,
{
BMIter eiter;
BMEdge *e;
- /* loop over faces of face, but do so by first looping over loops */
+ /* Loop over faces of face, but do so by first looping over loops. */
BM_ITER_ELEM (e, &eiter, v_a, BM_EDGES_OF_VERT) {
BMVert *v_b = BM_edge_other_vert(e, v_a);
if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- /* we know 'v_b' is not visited, check it out! */
+ /* We know 'v_b' is not visited, check it out! */
const int v_b_index = BM_elem_index_get(v_b);
const float cost_cut = params->use_topology_distance ? 1.0f : len_v3v3(v_a->co, v_b->co);
const float cost_new = cost[v_a_index] + cost_cut;
@@ -93,15 +100,15 @@ static void verttag_add_adjacent(HeapSimple *heap,
if (params->use_step_face) {
BMIter liter;
BMLoop *l;
- /* loop over faces of face, but do so by first looping over loops */
+ /* Loop over faces of face, but do so by first looping over loops. */
BM_ITER_ELEM (l, &liter, v_a, BM_LOOPS_OF_VERT) {
if (l->f->len > 3) {
- /* skip loops on adjacent edges */
+ /* Skip loops on adjacent edges. */
BMLoop *l_iter = l->next->next;
do {
BMVert *v_b = l_iter->v;
if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- /* we know 'v_b' is not visited, check it out! */
+ /* We know 'v_b' is not visited, check it out! */
const int v_b_index = BM_elem_index_get(v_b);
const float cost_cut = params->use_topology_distance ? 1.0f :
len_v3v3(v_a->co, v_b->co);
@@ -127,7 +134,7 @@ LinkNode *BM_mesh_calc_path_vert(BMesh *bm,
void *user_data)
{
LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited edges */
+ /* #BM_ELEM_TAG flag is used to store visited edges. */
BMVert *v;
BMIter viter;
HeapSimple *heap;
@@ -135,7 +142,7 @@ LinkNode *BM_mesh_calc_path_vert(BMesh *bm,
BMVert **verts_prev;
int i, totvert;
- /* note, would pass BM_EDGE except we are looping over all faces anyway */
+ /* Note, would pass #BM_EDGE except we are looping over all faces anyway. */
// BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
@@ -144,25 +151,25 @@ LinkNode *BM_mesh_calc_path_vert(BMesh *bm,
}
bm->elem_index_dirty &= ~BM_VERT;
- /* alloc */
+ /* Allocate. */
totvert = bm->totvert;
verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
- copy_vn_fl(cost, totvert, 1e20f);
+ copy_vn_fl(cost, totvert, COST_INIT_MAX);
/*
* Arrays are now filled as follows:
*
- * As the search continues, verts_prev[n] will be the previous verts on the shortest
- * path found so far to face n. BM_ELEM_TAG is used to tag elements we have visited,
- * cost[n] will contain the length of the shortest
+ * As the search continues, `verts_prev[n]` will be the previous verts on the shortest
+ * path found so far to face `n`. #BM_ELEM_TAG is used to tag elements we have visited,
+ * `cost[n]` will contain the length of the shortest
* path to face n found so far, Finally, heap is a priority heap which is built on the
- * the same data as the cost array, but inverted: it is a worklist of faces prioritized
+ * the same data as the cost array, but inverted: it is a work-list of faces prioritized
* by the shortest path found so far to the face.
*/
- /* regular dijkstra shortest path, but over faces instead of vertices */
+ /* Regular dijkstra shortest path, but over faces instead of vertices. */
heap = BLI_heapsimple_new();
BLI_heapsimple_insert(heap, 0.0f, v_src);
cost[BM_elem_index_get(v_src)] = 0.0f;
@@ -193,8 +200,11 @@ LinkNode *BM_mesh_calc_path_vert(BMesh *bm,
return path;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* BM_mesh_calc_path_edge */
+/** \name BM_mesh_calc_path_edge
+ * \{ */
static float edgetag_cut_cost_vert(BMEdge *e_a, BMEdge *e_b, BMVert *v)
{
@@ -223,8 +233,8 @@ static void edgetag_add_adjacent(HeapSimple *heap,
{
const int e_a_index = BM_elem_index_get(e_a);
- /* unlike vert/face, stepping faces disables scanning connected edges
- * and only steps over faces (selecting a ring of edges instead of a loop) */
+ /* Unlike vert/face, stepping faces disables scanning connected edges
+ * and only steps over faces (selecting a ring of edges instead of a loop). */
if (params->use_step_face == false || e_a->l == NULL) {
BMIter viter;
BMVert *v;
@@ -234,14 +244,14 @@ static void edgetag_add_adjacent(HeapSimple *heap,
BM_ITER_ELEM (v, &viter, e_a, BM_VERTS_OF_EDGE) {
- /* don't walk over previous vertex */
+ /* Don't walk over previous vertex. */
if ((edges_prev[e_a_index]) && (BM_vert_in_edge(edges_prev[e_a_index], v))) {
continue;
}
BM_ITER_ELEM (e_b, &eiter, v, BM_EDGES_OF_VERT) {
if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
- /* we know 'e_b' is not visited, check it out! */
+ /* We know 'e_b' is not visited, check it out! */
const int e_b_index = BM_elem_index_get(e_b);
const float cost_cut = params->use_topology_distance ?
1.0f :
@@ -267,7 +277,7 @@ static void edgetag_add_adjacent(HeapSimple *heap,
l_cycle_iter = l_iter->next;
l_cycle_end = l_iter;
- /* good, but we need to allow this otherwise paths may fail to connect at all */
+ /* Good, but we need to allow this otherwise paths may fail to connect at all. */
#if 0
if (l_iter->f->len > 3) {
l_cycle_iter = l_cycle_iter->next;
@@ -278,7 +288,7 @@ static void edgetag_add_adjacent(HeapSimple *heap,
do {
BMEdge *e_b = l_cycle_iter->e;
if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
- /* we know 'e_b' is not visited, check it out! */
+ /* We know 'e_b' is not visited, check it out! */
const int e_b_index = BM_elem_index_get(e_b);
const float cost_cut = params->use_topology_distance ?
1.0f :
@@ -304,7 +314,7 @@ LinkNode *BM_mesh_calc_path_edge(BMesh *bm,
void *user_data)
{
LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited edges */
+ /* #BM_ELEM_TAG flag is used to store visited edges. */
BMEdge *e;
BMIter eiter;
HeapSimple *heap;
@@ -312,7 +322,7 @@ LinkNode *BM_mesh_calc_path_edge(BMesh *bm,
BMEdge **edges_prev;
int i, totedge;
- /* note, would pass BM_EDGE except we are looping over all edges anyway */
+ /* Note, would pass #BM_EDGE except we are looping over all edges anyway. */
BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
@@ -321,25 +331,25 @@ LinkNode *BM_mesh_calc_path_edge(BMesh *bm,
}
bm->elem_index_dirty &= ~BM_EDGE;
- /* alloc */
+ /* Allocate. */
totedge = bm->totedge;
- edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
- cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
+ edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, __func__);
+ cost = MEM_mallocN(sizeof(*cost) * totedge, __func__);
- copy_vn_fl(cost, totedge, 1e20f);
+ copy_vn_fl(cost, totedge, COST_INIT_MAX);
/*
* Arrays are now filled as follows:
*
- * As the search continues, prevedge[n] will be the previous edge on the shortest
- * path found so far to edge n. BM_ELEM_TAG is used to tag elements we have visited,
- * cost[n] will contain the length of the shortest
+ * As the search continues, `edges_prev[n]` will be the previous edge on the shortest
+ * path found so far to edge `n`. #BM_ELEM_TAG is used to tag elements we have visited,
+ * `cost[n]` will contain the length of the shortest
* path to edge n found so far, Finally, heap is a priority heap which is built on the
- * the same data as the cost array, but inverted: it is a worklist of edges prioritized
+ * the same data as the cost array, but inverted: it is a work-list of edges prioritized
* by the shortest path found so far to the edge.
*/
- /* regular dijkstra shortest path, but over edges instead of vertices */
+ /* Regular dijkstra shortest path, but over edges instead of vertices. */
heap = BLI_heapsimple_new();
BLI_heapsimple_insert(heap, 0.0f, e_src);
cost[BM_elem_index_get(e_src)] = 0.0f;
@@ -370,8 +380,11 @@ LinkNode *BM_mesh_calc_path_edge(BMesh *bm,
return path;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* BM_mesh_calc_path_face */
+/** \name BM_mesh_calc_path_face
+ * \{ */
static float facetag_cut_cost_edge(BMFace *f_a,
BMFace *f_b,
@@ -387,15 +400,15 @@ static float facetag_cut_cost_edge(BMFace *f_a,
#if 0
mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
#else
- /* for triangle fans it gives better results to pick a point on the edge */
+ /* For triangle fans it gives better results to pick a point on the edge. */
{
- float ix_e[3], ix_f[3], f;
+ float ix_e[3], ix_f[3];
isect_line_line_v3(e->v1->co, e->v2->co, f_a_cent, f_b_cent, ix_e, ix_f);
- f = line_point_factor_v3(ix_e, e->v1->co, e->v2->co);
- if (f < 0.0f) {
+ const float factor = line_point_factor_v3(ix_e, e->v1->co, e->v2->co);
+ if (factor < 0.0f) {
copy_v3_v3(e_cent, e->v1->co);
}
- else if (f > 1.0f) {
+ else if (factor > 1.0f) {
copy_v3_v3(e_cent, e->v2->co);
}
else {
@@ -432,7 +445,7 @@ static void facetag_add_adjacent(HeapSimple *heap,
{
const int f_a_index = BM_elem_index_get(f_a);
- /* loop over faces of face, but do so by first looping over loops */
+ /* Loop over faces of face, but do so by first looping over loops. */
{
BMIter liter;
BMLoop *l_a;
@@ -444,7 +457,7 @@ static void facetag_add_adjacent(HeapSimple *heap,
do {
BMFace *f_b = l_iter->f;
if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
- /* we know 'f_b' is not visited, check it out! */
+ /* We know 'f_b' is not visited, check it out! */
const int f_b_index = BM_elem_index_get(f_b);
const float cost_cut = params->use_topology_distance ?
1.0f :
@@ -472,7 +485,7 @@ static void facetag_add_adjacent(HeapSimple *heap,
if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
BMFace *f_b = l_b->f;
if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
- /* we know 'f_b' is not visited, check it out! */
+ /* We know 'f_b' is not visited, check it out! */
const int f_b_index = BM_elem_index_get(f_b);
const float cost_cut = params->use_topology_distance ?
1.0f :
@@ -499,7 +512,7 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
void *user_data)
{
LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited edges */
+ /* #BM_ELEM_TAG flag is used to store visited edges. */
BMFace *f;
BMIter fiter;
HeapSimple *heap;
@@ -510,7 +523,7 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
/* Start measuring face path at the face edges, ignoring their centers. */
const void *const f_endpoints[2] = {f_src, f_dst};
- /* note, would pass BM_EDGE except we are looping over all faces anyway */
+ /* Note, would pass #BM_EDGE except we are looping over all faces anyway. */
// BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
@@ -519,25 +532,25 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
}
bm->elem_index_dirty &= ~BM_FACE;
- /* alloc */
+ /* Allocate. */
totface = bm->totface;
faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
- copy_vn_fl(cost, totface, 1e20f);
+ copy_vn_fl(cost, totface, COST_INIT_MAX);
/*
* Arrays are now filled as follows:
*
- * As the search continues, faces_prev[n] will be the previous face on the shortest
- * path found so far to face n. BM_ELEM_TAG is used to tag elements we have visited,
- * cost[n] will contain the length of the shortest
+ * As the search continues, `faces_prev[n]` will be the previous face on the shortest
+ * path found so far to face `n`. #BM_ELEM_TAG is used to tag elements we have visited,
+ * `cost[n]` will contain the length of the shortest
* path to face n found so far, Finally, heap is a priority heap which is built on the
- * the same data as the cost array, but inverted: it is a worklist of faces prioritized
+ * the same data as the cost array, but inverted: it is a work-list of faces prioritized
* by the shortest path found so far to the face.
*/
- /* regular dijkstra shortest path, but over faces instead of vertices */
+ /* Regular dijkstra shortest path, but over faces instead of vertices. */
heap = BLI_heapsimple_new();
BLI_heapsimple_insert(heap, 0.0f, f_src);
cost[BM_elem_index_get(f_src)] = 0.0f;
@@ -567,3 +580,4 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
return path;
}
+/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_uv.c b/source/blender/bmesh/tools/bmesh_path_uv.c
new file mode 100644
index 00000000000..57a70645187
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_path_uv.c
@@ -0,0 +1,433 @@
+/*
+ * 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 bmesh
+ *
+ * Find a path between 2 elements in UV space.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_heap_simple.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "bmesh.h"
+#include "bmesh_path_uv.h" /* own include */
+#include "intern/bmesh_query.h"
+#include "intern/bmesh_query_uv.h"
+
+#define COST_INIT_MAX FLT_MAX
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Helpers
+ * \{ */
+
+/**
+ * Use skip options when we want to start measuring from a boundary.
+ *
+ * See #step_cost_3_v3_ex in bmesh_path.c which follows the same logic.
+ */
+static float step_cost_3_v2_ex(
+ const float v1[2], const float v2[2], const float v3[2], bool skip_12, bool skip_23)
+{
+ float d1[2], d2[2];
+
+ /* The cost is based on the simple sum of the length of the two edges. */
+ sub_v2_v2v2(d1, v2, v1);
+ sub_v2_v2v2(d2, v3, v2);
+ const float cost_12 = normalize_v2(d1);
+ const float cost_23 = normalize_v2(d2);
+ const float cost = ((skip_12 ? 0.0f : cost_12) + (skip_23 ? 0.0f : cost_23));
+
+ /* But is biased to give higher values to sharp turns, so that it will take paths with
+ * fewer "turns" when selecting between equal-weighted paths between the two edges. */
+ return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v2v2(d1, d2)))));
+}
+
+static float UNUSED_FUNCTION(step_cost_3_v2)(const float v1[2],
+ const float v2[2],
+ const float v3[2])
+{
+ return step_cost_3_v2_ex(v1, v2, v3, false, false);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BM_mesh_calc_path_uv_vert
+ * \{ */
+
+static void looptag_add_adjacent_uv(HeapSimple *heap,
+ BMLoop *l_a,
+ BMLoop **loops_prev,
+ float *cost,
+ const struct BMCalcPathUVParams *params)
+{
+ BLI_assert(params->aspect_y != 0.0f);
+ const uint cd_loop_uv_offset = params->cd_loop_uv_offset;
+ const int l_a_index = BM_elem_index_get(l_a);
+ const MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset);
+ const float uv_a[2] = {luv_a->uv[0], luv_a->uv[1] / params->aspect_y};
+
+ {
+ BMIter liter;
+ BMLoop *l;
+ /* Loop over faces of face, but do so by first looping over loops. */
+ BM_ITER_ELEM (l, &liter, l_a->v, BM_LOOPS_OF_VERT) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (equals_v2v2(luv_a->uv, luv->uv)) {
+ /* 'l_a' is already tagged, tag all adjacent. */
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
+ BMLoop *l_b = l->next;
+ do {
+ if (!BM_elem_flag_test(l_b, BM_ELEM_TAG)) {
+ const MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset);
+ const float uv_b[2] = {luv_b->uv[0], luv_b->uv[1] / params->aspect_y};
+ /* We know 'l_b' is not visited, check it out! */
+ const int l_b_index = BM_elem_index_get(l_b);
+ const float cost_cut = params->use_topology_distance ? 1.0f : len_v2v2(uv_a, uv_b);
+ const float cost_new = cost[l_a_index] + cost_cut;
+
+ if (cost[l_b_index] > cost_new) {
+ cost[l_b_index] = cost_new;
+ loops_prev[l_b_index] = l_a;
+ BLI_heapsimple_insert(heap, cost_new, l_b);
+ }
+ }
+ /* This means we only step onto `l->prev` & `l->next`. */
+ if (params->use_step_face == false) {
+ if (l_b == l->next) {
+ l_b = l->prev->prev;
+ }
+ }
+ } while ((l_b = l_b->next) != l);
+ }
+ }
+ }
+}
+
+struct LinkNode *BM_mesh_calc_path_uv_vert(BMesh *bm,
+ BMLoop *l_src,
+ BMLoop *l_dst,
+ const struct BMCalcPathUVParams *params,
+ bool (*filter_fn)(BMLoop *, void *),
+ void *user_data)
+{
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited edges */
+ BMIter viter;
+ HeapSimple *heap;
+ float *cost;
+ BMLoop **loops_prev;
+ int i = 0, totloop;
+ BMFace *f;
+
+ /* Note, would pass BM_EDGE except we are looping over all faces anyway. */
+ // BM_mesh_elem_index_ensure(bm, BM_LOOP); // NOT NEEDED FOR FACETAG
+
+ BM_ITER_MESH (f, &viter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+ BM_elem_flag_set(l_iter, BM_ELEM_TAG, !filter_fn(l_iter, user_data));
+ BM_elem_index_set(l_iter, i); /* set_inline */
+ i += 1;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ bm->elem_index_dirty &= ~BM_LOOP;
+
+ /* Allocate. */
+ totloop = bm->totloop;
+ loops_prev = MEM_callocN(sizeof(*loops_prev) * totloop, __func__);
+ cost = MEM_mallocN(sizeof(*cost) * totloop, __func__);
+
+ copy_vn_fl(cost, totloop, COST_INIT_MAX);
+
+ /* Regular dijkstra shortest path, but over UV loops instead of vertices. */
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, l_src);
+ cost[BM_elem_index_get(l_src)] = 0.0f;
+
+ BMLoop *l = NULL;
+ while (!BLI_heapsimple_is_empty(heap)) {
+ l = BLI_heapsimple_pop_min(heap);
+
+ if ((l->v == l_dst->v) && BM_loop_uv_share_vert_check(l, l_dst, params->cd_loop_uv_offset)) {
+ break;
+ }
+
+ if (!BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ /* Adjacent loops are tagged while stepping to avoid 2x loops. */
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
+ looptag_add_adjacent_uv(heap, l, loops_prev, cost, params);
+ }
+ }
+
+ if ((l->v == l_dst->v) && BM_loop_uv_share_vert_check(l, l_dst, params->cd_loop_uv_offset)) {
+ do {
+ BLI_linklist_prepend(&path, l);
+ } while ((l = loops_prev[BM_elem_index_get(l)]));
+ }
+
+ MEM_freeN(loops_prev);
+ MEM_freeN(cost);
+ BLI_heapsimple_free(heap, NULL);
+
+ return path;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BM_mesh_calc_path_uv_edge
+ * \{ */
+/* TODO(campbell): not very urgent, since the operator fakes this using vertex path. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BM_mesh_calc_path_uv_face
+ * \{ */
+
+static float facetag_cut_cost_edge_uv(BMFace *f_a,
+ BMFace *f_b,
+ BMLoop *l_edge,
+ const void *const f_endpoints[2],
+ const float aspect_v2[2],
+ const int cd_loop_uv_offset)
+{
+ float f_a_cent[2];
+ float f_b_cent[2];
+ float e_cent[2];
+
+ BM_face_uv_calc_center_median_weighted(f_a, aspect_v2, cd_loop_uv_offset, f_a_cent);
+ BM_face_uv_calc_center_median_weighted(f_b, aspect_v2, cd_loop_uv_offset, f_b_cent);
+
+ const float *co_v1 = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_edge, cd_loop_uv_offset))->uv;
+ const float *co_v2 =
+ ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_edge->next, cd_loop_uv_offset))->uv;
+
+#if 0
+ mid_v2_v2v2(e_cent, co_v1, co_v2);
+#else
+ /* For triangle fans it gives better results to pick a point on the edge. */
+ {
+ float ix_e[2];
+ isect_line_line_v2_point(co_v1, co_v2, f_a_cent, f_b_cent, ix_e);
+ const float factor = line_point_factor_v2(ix_e, co_v1, co_v2);
+ if (factor < 0.0f) {
+ copy_v2_v2(e_cent, co_v1);
+ }
+ else if (factor > 1.0f) {
+ copy_v2_v2(e_cent, co_v2);
+ }
+ else {
+ copy_v2_v2(e_cent, ix_e);
+ }
+ }
+#endif
+
+ /* Apply aspect before calculating cost. */
+ mul_v2_v2(f_a_cent, aspect_v2);
+ mul_v2_v2(f_b_cent, aspect_v2);
+ mul_v2_v2(e_cent, aspect_v2);
+
+ return step_cost_3_v2_ex(
+ f_a_cent, e_cent, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
+}
+
+static float facetag_cut_cost_vert_uv(BMFace *f_a,
+ BMFace *f_b,
+ BMLoop *l_vert,
+ const void *const f_endpoints[2],
+ const float aspect_v2[2],
+ const int cd_loop_uv_offset)
+{
+ float f_a_cent[2];
+ float f_b_cent[2];
+ float v_cent[2];
+
+ BM_face_uv_calc_center_median_weighted(f_a, aspect_v2, cd_loop_uv_offset, f_a_cent);
+ BM_face_uv_calc_center_median_weighted(f_b, aspect_v2, cd_loop_uv_offset, f_b_cent);
+
+ copy_v2_v2(v_cent, ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_vert, cd_loop_uv_offset))->uv);
+
+ mul_v2_v2(f_a_cent, aspect_v2);
+ mul_v2_v2(f_b_cent, aspect_v2);
+ mul_v2_v2(v_cent, aspect_v2);
+
+ return step_cost_3_v2_ex(
+ f_a_cent, v_cent, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
+}
+
+static void facetag_add_adjacent_uv(HeapSimple *heap,
+ BMFace *f_a,
+ BMFace **faces_prev,
+ float *cost,
+ const void *const f_endpoints[2],
+ const float aspect_v2[2],
+ const struct BMCalcPathUVParams *params)
+{
+ const uint cd_loop_uv_offset = params->cd_loop_uv_offset;
+ const int f_a_index = BM_elem_index_get(f_a);
+
+ /* Loop over faces of face, but do so by first looping over loops. */
+ {
+ BMIter liter;
+ BMLoop *l_a;
+
+ BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
+ BMLoop *l_first, *l_iter;
+
+ /* Check there is an adjacent face to loop over. */
+ if (l_a != l_a->radial_next) {
+ l_iter = l_first = l_a->radial_next;
+ do {
+ BMFace *f_b = l_iter->f;
+ if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
+ if (BM_loop_uv_share_edge_check(l_a, l_iter, cd_loop_uv_offset)) {
+ /* We know 'f_b' is not visited, check it out! */
+ const int f_b_index = BM_elem_index_get(f_b);
+ const float cost_cut =
+ params->use_topology_distance ?
+ 1.0f :
+ facetag_cut_cost_edge_uv(
+ f_a, f_b, l_iter, f_endpoints, aspect_v2, cd_loop_uv_offset);
+ const float cost_new = cost[f_a_index] + cost_cut;
+
+ if (cost[f_b_index] > cost_new) {
+ cost[f_b_index] = cost_new;
+ faces_prev[f_b_index] = f_a;
+ BLI_heapsimple_insert(heap, cost_new, f_b);
+ }
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ }
+ }
+
+ if (params->use_step_face) {
+ BMIter liter;
+ BMLoop *l_a;
+
+ BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
+ BMIter litersub;
+ BMLoop *l_b;
+ BM_ITER_ELEM (l_b, &litersub, l_a->v, BM_LOOPS_OF_VERT) {
+ if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
+ BMFace *f_b = l_b->f;
+ if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
+ if (BM_loop_uv_share_vert_check(l_a, l_b, cd_loop_uv_offset)) {
+ /* We know 'f_b' is not visited, check it out! */
+ const int f_b_index = BM_elem_index_get(f_b);
+ const float cost_cut =
+ params->use_topology_distance ?
+ 1.0f :
+ facetag_cut_cost_vert_uv(
+ f_a, f_b, l_a, f_endpoints, aspect_v2, cd_loop_uv_offset);
+ const float cost_new = cost[f_a_index] + cost_cut;
+
+ if (cost[f_b_index] > cost_new) {
+ cost[f_b_index] = cost_new;
+ faces_prev[f_b_index] = f_a;
+ BLI_heapsimple_insert(heap, cost_new, f_b);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+struct LinkNode *BM_mesh_calc_path_uv_face(BMesh *bm,
+ BMFace *f_src,
+ BMFace *f_dst,
+ const struct BMCalcPathUVParams *params,
+ bool (*filter_fn)(BMFace *, void *),
+ void *user_data)
+{
+ const float aspect_v2[2] = {1.0f, 1.0f / params->aspect_y};
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited edges */
+ BMIter fiter;
+ HeapSimple *heap;
+ float *cost;
+ BMFace **faces_prev;
+ int i = 0, totface;
+
+ /* Start measuring face path at the face edges, ignoring their centers. */
+ const void *const f_endpoints[2] = {f_src, f_dst};
+
+ /* Note, would pass BM_EDGE except we are looping over all faces anyway. */
+ // BM_mesh_elem_index_ensure(bm, BM_LOOP); // NOT NEEDED FOR FACETAG
+
+ {
+ BMFace *f;
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, !filter_fn(f, user_data));
+ BM_elem_index_set(f, i); /* set_inline */
+ i += 1;
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+ }
+
+ /* Allocate. */
+ totface = bm->totface;
+ faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
+ cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
+
+ copy_vn_fl(cost, totface, COST_INIT_MAX);
+
+ /* Regular dijkstra shortest path, but over UV faces instead of vertices. */
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, f_src);
+ cost[BM_elem_index_get(f_src)] = 0.0f;
+
+ BMFace *f = NULL;
+ while (!BLI_heapsimple_is_empty(heap)) {
+ f = BLI_heapsimple_pop_min(heap);
+
+ if (f == f_dst) {
+ break;
+ }
+
+ if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ /* Adjacent loops are tagged while stepping to avoid 2x loops. */
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ facetag_add_adjacent_uv(heap, f, faces_prev, cost, f_endpoints, aspect_v2, params);
+ }
+ }
+
+ if (f == f_dst) {
+ do {
+ BLI_linklist_prepend(&path, f);
+ } while ((f = faces_prev[BM_elem_index_get(f)]));
+ }
+
+ MEM_freeN(faces_prev);
+ MEM_freeN(cost);
+ BLI_heapsimple_free(heap, NULL);
+
+ return path;
+}
+
+/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_uv.h b/source/blender/bmesh/tools/bmesh_path_uv.h
new file mode 100644
index 00000000000..c7c5768f7d0
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_path_uv.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __BMESH_PATH_UV_H__
+#define __BMESH_PATH_UV_H__
+
+/** \file
+ * \ingroup bmesh
+ */
+
+struct BMCalcPathUVParams {
+ uint use_topology_distance : 1;
+ uint use_step_face : 1;
+ uint cd_loop_uv_offset;
+ float aspect_y;
+};
+
+struct LinkNode *BM_mesh_calc_path_uv_vert(BMesh *bm,
+ BMLoop *l_src,
+ BMLoop *l_dst,
+ const struct BMCalcPathUVParams *params,
+ bool (*filter_fn)(BMLoop *, void *),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3, 5);
+
+struct LinkNode *BM_mesh_calc_path_uv_face(BMesh *bm,
+ BMFace *f_src,
+ BMFace *f_dst,
+ const struct BMCalcPathUVParams *params,
+ bool (*filter_fn)(BMFace *, void *),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3, 5);
+
+#endif /* __BMESH_PATH_UV_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 8de23b696bf..d222ea214c4 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -1299,7 +1299,9 @@ static UUIDFashMatch *bm_vert_fasthash_create(BMesh *bm, const uint depth)
return id_curr;
}
-static void bm_vert_fasthash_edge_order(UUIDFashMatch *fm, const BMEdge *e, UUIDFashMatch e_fm[2])
+static void bm_vert_fasthash_edge_order(const UUIDFashMatch *fm,
+ const BMEdge *e,
+ UUIDFashMatch e_fm[2])
{
e_fm[0] = fm[BM_elem_index_get(e->v1)];
e_fm[1] = fm[BM_elem_index_get(e->v2)];
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index ae6f49bffcd..84f7fe2d225 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -26,8 +26,8 @@
// this part has been copied from the double edge mask
static void do_adjacentKeepBorders(unsigned int t,
unsigned int rw,
- unsigned int *limask,
- unsigned int *lomask,
+ const unsigned int *limask,
+ const unsigned int *lomask,
unsigned int *lres,
float *res,
unsigned int *rsize)
@@ -196,8 +196,8 @@ static void do_adjacentKeepBorders(unsigned int t,
static void do_adjacentBleedBorders(unsigned int t,
unsigned int rw,
- unsigned int *limask,
- unsigned int *lomask,
+ const unsigned int *limask,
+ const unsigned int *lomask,
unsigned int *lres,
float *res,
unsigned int *rsize)
@@ -417,8 +417,8 @@ static void do_adjacentBleedBorders(unsigned int t,
static void do_allKeepBorders(unsigned int t,
unsigned int rw,
- unsigned int *limask,
- unsigned int *lomask,
+ const unsigned int *limask,
+ const unsigned int *lomask,
unsigned int *lres,
float *res,
unsigned int *rsize)
@@ -579,8 +579,8 @@ static void do_allKeepBorders(unsigned int t,
static void do_allBleedBorders(unsigned int t,
unsigned int rw,
- unsigned int *limask,
- unsigned int *lomask,
+ const unsigned int *limask,
+ const unsigned int *lomask,
unsigned int *lres,
float *res,
unsigned int *rsize)
@@ -793,8 +793,8 @@ static void do_allBleedBorders(unsigned int t,
static void do_allEdgeDetection(unsigned int t,
unsigned int rw,
- unsigned int *limask,
- unsigned int *lomask,
+ const unsigned int *limask,
+ const unsigned int *lomask,
unsigned int *lres,
float *res,
unsigned int *rsize,
@@ -863,8 +863,8 @@ static void do_allEdgeDetection(unsigned int t,
static void do_adjacentEdgeDetection(unsigned int t,
unsigned int rw,
- unsigned int *limask,
- unsigned int *lomask,
+ const unsigned int *limask,
+ const unsigned int *lomask,
unsigned int *lres,
float *res,
unsigned int *rsize,
@@ -935,7 +935,7 @@ static void do_adjacentEdgeDetection(unsigned int t,
static void do_createEdgeLocationBuffer(unsigned int t,
unsigned int rw,
- unsigned int *lres,
+ const unsigned int *lres,
float *res,
unsigned short *gbuf,
unsigned int *innerEdgeOffset,
@@ -1060,7 +1060,7 @@ static void do_createEdgeLocationBuffer(unsigned int t,
static void do_fillGradientBuffer(unsigned int rw,
float *res,
- unsigned short *gbuf,
+ const unsigned short *gbuf,
unsigned int isz,
unsigned int osz,
unsigned int gsz,
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
index b43b94af06a..0087c720ac0 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
@@ -198,7 +198,7 @@ static void FHT2D(
//------------------------------------------------------------------------------
/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */
-static void fht_convolve(fREAL *d1, fREAL *d2, unsigned int M, unsigned int N)
+static void fht_convolve(fREAL *d1, const fREAL *d2, unsigned int M, unsigned int N)
{
fREAL a, b;
unsigned int i, j, k, L, mj, mL;
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
index 56caa68fd35..56e0ab9b93f 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
@@ -514,7 +514,7 @@ void antialias_tagbuf(int xsize, int ysize, char *rectmove)
/* we make this into 3 points, center point is (0, 0) */
/* and offset the center point just enough to make curve go through midpoint */
-static void quad_bezier_2d(float *result, float *v1, float *v2, float *ipodata)
+static void quad_bezier_2d(float *result, const float *v1, const float *v2, const float *ipodata)
{
float p1[2], p2[2], p3[2];
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 50c52a519b4..8054946777c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -2949,7 +2949,7 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node)
}
add_operation_relation(
- op_from->get_exit_operation(), op_to->get_entry_operation(), "Driver Serialisation");
+ op_from->get_exit_operation(), op_to->get_entry_operation(), "Driver Serialization");
break;
}
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 38350d50da6..79d6c8d6a77 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -711,13 +711,6 @@ void update_modifiers_orig_pointers(const Object *object_orig, Object *object_co
&object_orig->modifiers, &object_cow->modifiers, &ModifierData::orig_modifier_data);
}
-void update_simulation_states_orig_pointers(const Simulation *simulation_orig,
- Simulation *simulation_cow)
-{
- update_list_orig_pointers(
- &simulation_orig->states, &simulation_cow->states, &SimulationState::orig_state);
-}
-
void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *strips_cow)
{
NlaStrip *strip_orig = reinterpret_cast<NlaStrip *>(strips_orig->first);
@@ -817,12 +810,6 @@ void update_id_after_copy(const Depsgraph *depsgraph,
update_scene_orig_pointers(scene_orig, scene_cow);
break;
}
- case ID_SIM: {
- Simulation *simulation_cow = (Simulation *)id_cow;
- const Simulation *simulation_orig = (const Simulation *)id_orig;
- update_simulation_states_orig_pointers(simulation_orig, simulation_cow);
- break;
- }
default:
break;
}
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 8c48ae65d9b..f6e74c6822c 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -486,7 +486,7 @@ void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int le
}
/**
- * Simple down-sampling algorithm for cubemap. Reconstruct mip chain up to mip level.
+ * Simple down-sampling algorithm for cube-map. Reconstruct mip chain up to mip level.
*/
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
{
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 78d50a02fc7..93d60d7518f 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -113,7 +113,7 @@ typedef struct EEVEE_LightBake {
float samples_ct, invsamples_ct;
/** Sampling bias during convolution step. */
float lod_factor;
- /** Max cubemap LOD to sample when convolving. */
+ /** Max cube-map LOD to sample when convolving. */
float lod_max;
/** Number of probes to render + world probe. */
int cube_len, grid_len;
@@ -121,7 +121,7 @@ typedef struct EEVEE_LightBake {
/* Irradiance grid */
/** Current probe being rendered (UBO data). */
EEVEE_LightGrid *grid;
- /** Target cubemap at MIP 0. */
+ /** Target cube-map at MIP 0. */
int irr_cube_res;
/** Size of the irradiance texture. */
int irr_size[3];
@@ -145,7 +145,7 @@ typedef struct EEVEE_LightBake {
/* Reflection probe */
/** Current probe being rendered (UBO data). */
EEVEE_LightProbe *cube;
- /** Target cubemap at MIP 0. */
+ /** Target cube-map at MIP 0. */
int ref_cube_res;
/** Index of the current cube. */
int cube_offset;
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index 18365d69514..b89772441fa 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -107,9 +107,9 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_PrivateData *g_data = stl->g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- View3DShading *shading = &v3d->shading;
- Scene *scene = draw_ctx->scene;
+ /* The view will be NULL when rendering previews. */
+ const View3D *v3d = draw_ctx->v3d;
+ const Scene *scene = draw_ctx->scene;
const bool probe_render = pinfo != NULL;
@@ -150,6 +150,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
}
if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) {
+ const View3DShading *shading = &v3d->shading;
StudioLight *sl = BKE_studiolight_find(shading->lookdev_light,
STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE);
if (sl && (sl->flag & STUDIOLIGHT_TYPE_WORLD)) {
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 8c17ecd3905..143945b637a 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -114,8 +114,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
- int *ssr_id,
- float *refract_depth,
+ const int *ssr_id,
+ const float *refract_depth,
bool use_ssrefraction,
bool use_alpha_blend)
{
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index a67593773ab..1b1355fdecd 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -589,7 +589,7 @@ typedef struct EEVEE_ObjectKey {
/** Parent object for duplis */
struct Object *parent;
/** Dupli objects recursive unique identifier */
- int id[16]; /* 2*MAX_DUPLI_RECUR */
+ int id[8]; /* MAX_DUPLI_RECUR */
} EEVEE_ObjectKey;
typedef struct EEVEE_ObjectMotionData {
@@ -1012,8 +1012,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
struct GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
- int *ssr_id,
- float *refract_depth,
+ const int *ssr_id,
+ const float *refract_depth,
bool use_ssrefraction,
bool use_alpha_blend);
/* eevee_lights.c */
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index 714481c39f1..997f9a5be9d 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -96,7 +96,7 @@ static void invert_cdf(const float cdf[FILTER_CDF_TABLE_SIZE],
}
/* Evaluate a discrete function table with linear interpolation. */
-static float eval_table(float *table, float x)
+static float eval_table(const float *table, float x)
{
CLAMP(x, 0.0f, 1.0f);
x = x * (FILTER_CDF_TABLE_SIZE - 1);
@@ -240,9 +240,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL);
}
- effects->taa_total_sample = EEVEE_renderpasses_only_first_sample_pass_active(vedata) ?
- 1 :
- scene_eval->eevee.taa_samples;
+ const bool first_sample_only = EEVEE_renderpasses_only_first_sample_pass_active(vedata);
+ view_is_valid = view_is_valid && !first_sample_only;
+ effects->taa_total_sample = first_sample_only ? 1 : scene_eval->eevee.taa_samples;
MAX2(effects->taa_total_sample, 0);
DRW_view_persmat_get(NULL, persmat, false);
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 7ccb5d5a753..daf83e11e17 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -2118,7 +2118,7 @@ static void armature_context_setup(ArmatureDrawContext *ctx,
const bool do_envelope_dist,
const bool is_edit_mode,
const bool is_pose_mode,
- float *const_color)
+ const float *const_color)
{
const bool is_object_mode = !do_envelope_dist;
const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0 || (pd->armature.do_pose_xray && is_pose_mode);
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index c0407345729..f096c9657c7 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -1356,7 +1356,7 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
Object *ob,
ModifierData *md,
Scene *scene,
- float *color)
+ const float *color)
{
FluidModifierData *fmd = (FluidModifierData *)md;
FluidDomainSettings *fds = fmd->domain;
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 7b08e97ac31..9e4d77429d5 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -256,6 +256,8 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
}
else if (XRAY_ENABLED(v3d)) {
wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
+ /* Disable shading options that aren't supported in transparency mode. */
+ wpd->shading.flag &= ~(V3D_SHADING_SHADOW | V3D_SHADING_CAVITY | V3D_SHADING_DEPTH_OF_FIELD);
}
else {
wpd->shading.xray_alpha = 1.0f;
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 5f453e765b1..5fff55e2f26 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -191,7 +191,12 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
geom = DRW_cache_mesh_surface_vertpaint_get(ob);
}
else {
- geom = DRW_cache_mesh_surface_sculptcolors_get(ob);
+ if (U.experimental.use_sculpt_vertex_colors) {
+ geom = DRW_cache_mesh_surface_sculptcolors_get(ob);
+ }
+ else {
+ geom = DRW_cache_mesh_surface_vertpaint_get(ob);
+ }
}
}
else {
@@ -272,8 +277,15 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
}
}
else if (color_type == V3D_SHADING_VERTEX_COLOR) {
- if ((me == NULL) || !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) {
- color_type = V3D_SHADING_OBJECT_COLOR;
+ if (U.experimental.use_sculpt_vertex_colors) {
+ if ((me == NULL) || !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) {
+ color_type = V3D_SHADING_OBJECT_COLOR;
+ }
+ }
+ else {
+ if ((me == NULL) || !CustomData_has_layer(&me->ldata, CD_MLOOPCOL)) {
+ color_type = V3D_SHADING_OBJECT_COLOR;
+ }
}
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 555043ab408..1ab5ec18f65 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -623,7 +623,7 @@ void DRW_render_object_iter(void *vedata,
struct RenderEngine *engine,
struct Depsgraph *depsgraph));
void DRW_render_instance_buffer_finish(void);
-void DRW_render_viewport_size_set(int size[2]);
+void DRW_render_viewport_size_set(const int size[2]);
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 302f9a0d3a8..f05e8e2f9d6 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -60,6 +60,10 @@ typedef struct DRW_MeshCDMask {
* modifiers could remove it. (see T68857) */
uint32_t edit_uv : 1;
} DRW_MeshCDMask;
+/* Keep `DRW_MeshCDMask` struct within an `uint64_t`.
+ * bit-wise and atomic operations are used to compare and update the struct.
+ * See `mesh_cd_layers_type_*` functions. */
+BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits")
typedef enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index 98da668f78f..a27ee90b148 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -2534,26 +2534,28 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
}
/* Sculpt Vertex Colors */
- for (int i = 0; i < 8; i++) {
- if (svcol_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
- GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
-
- BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "c");
- }
- if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "ac");
- }
- /* Gather number of auto layers. */
- /* We only do `vcols` that are not overridden by `uvs`. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
- BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ if (U.experimental.use_sculpt_vertex_colors) {
+ for (int i = 0; i < 8; i++) {
+ if (svcol_layers & (1 << i)) {
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+
+ BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
+ GPU_vertformat_alias_add(&format, "c");
+ }
+ if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ /* Gather number of auto layers. */
+ /* We only do `vcols` that are not overridden by `uvs`. */
+ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(&format, attr_name);
+ }
}
}
}
@@ -2599,7 +2601,7 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
}
}
- if (svcol_layers & (1 << i)) {
+ if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) {
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i);
BMIter f_iter;
@@ -4384,10 +4386,6 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf)
GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
- if (!mr->use_subsurf_fdots) {
- /* Clear so we can accumulate on it. */
- memset(vbo->data, 0x0, mr->poly_len * vbo->format.stride);
- }
return vbo->data;
}
@@ -4396,12 +4394,20 @@ static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr,
void *data)
{
float(*center)[3] = data;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
+
+ EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
{
- float w = 1.0f / (float)l->f->len;
- madd_v3_v3fl(center[BM_elem_index_get(l->f)], bm_vert_co_get(mr, l->v), w);
+ float *co = center[f_index];
+ zero_v3(co);
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ add_v3_v3(co, bm_vert_co_get(mr, l_iter->v));
+ } while ((l_iter = l_iter->next) != l_first);
+ mul_v3_fl(co, 1.0f / (float)f->len);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ EXTRACT_POLY_FOREACH_BM_END;
}
static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
@@ -4409,20 +4415,34 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
void *data)
{
float(*center)[3] = (float(*)[3])data;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
- const MVert *mv = &mr->mvert[ml->v];
- if (mr->use_subsurf_fdots) {
+ const MVert *mvert = mr->mvert;
+ const MLoop *mloop = mr->mloop;
+
+ if (mr->use_subsurf_fdots) {
+ EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
+ {
+ const MVert *mv = &mr->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
copy_v3_v3(center[mp_index], mv->co);
}
}
- else {
- float w = 1.0f / (float)mp->totloop;
- madd_v3_v3fl(center[mp_index], mv->co, w);
+ EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
+ }
+ else {
+ EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
+ {
+ float *co = center[mp_index];
+ zero_v3(co);
+
+ const MLoop *ml = &mloop[mp->loopstart];
+ for (int i = 0; i < mp->totloop; i++, ml++) {
+ const MVert *mv = &mvert[ml->v];
+ add_v3_v3(center[mp_index], mv->co);
+ }
+ mul_v3_fl(co, 1.0f / (float)mp->totloop);
}
+ EXTRACT_POLY_FOREACH_MESH_END;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static const MeshExtract extract_fdots_pos = {
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index ea1717f0684..40de0794b9e 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -74,22 +74,25 @@ static void mesh_batch_cache_clear(Mesh *me);
/* Return true is all layers in _b_ are inside _a_. */
BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
- return (*((uint32_t *)&a) & *((uint32_t *)&b)) == *((uint32_t *)&b);
+ return (*((uint64_t *)&a) & *((uint64_t *)&b)) == *((uint64_t *)&b);
}
BLI_INLINE bool mesh_cd_layers_type_equal(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
- return *((uint32_t *)&a) == *((uint32_t *)&b);
+ return *((uint64_t *)&a) == *((uint64_t *)&b);
}
BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b)
{
- atomic_fetch_and_or_uint32((uint32_t *)a, *(uint32_t *)&b);
+ uint32_t *a_p = (uint32_t *)a;
+ uint32_t *b_p = (uint32_t *)&b;
+ atomic_fetch_and_or_uint32(a_p, *b_p);
+ atomic_fetch_and_or_uint32(a_p + 1, *(b_p + 1));
}
BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
{
- *((uint32_t *)a) = 0;
+ *((uint64_t *)a) = 0;
}
static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used)
@@ -205,8 +208,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
}
if (layer == -1) {
- layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
- type = CD_PROP_COLOR;
+ if (U.experimental.use_sculpt_vertex_colors) {
+ layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
+ type = CD_PROP_COLOR;
+ }
}
#if 0 /* Tangents are always from UV's - this will never happen. */
if (layer == -1) {
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 3e42c4cdb23..5359f649d6b 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -369,7 +369,7 @@ void DRW_engine_viewport_data_size_get(
}
/* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */
-void DRW_render_viewport_size_set(int size[2])
+void DRW_render_viewport_size_set(const int size[2])
{
DST.size[0] = size[0];
DST.size[1] = size[1];
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 31a2dd7f0fe..ab87760942c 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -583,7 +583,7 @@ void drw_state_set(DRWState state);
void drw_debug_draw(void);
void drw_debug_init(void);
-eDRWCommandType command_type_get(uint64_t *command_type_bits, int index);
+eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index);
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 14d77ab1b21..43fec503301 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -623,7 +623,7 @@ static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommand
command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4);
}
-eDRWCommandType command_type_get(uint64_t *command_type_bits, int index)
+eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index)
{
return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF);
}
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 6304b707cb9..592b030c45e 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -91,10 +91,13 @@ static void drw_deferred_shader_queue_free(ListBase *queue)
}
}
-static void drw_deferred_shader_compilation_exec(void *custom_data,
- short *stop,
- short *do_update,
- float *progress)
+static void drw_deferred_shader_compilation_exec(
+ void *custom_data,
+ /* Cannot be const, this function implements wm_jobs_start_callback.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ short *stop,
+ short *do_update,
+ float *progress)
{
DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
void *gl_context = comp->gl_context;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index d823b976a47..bcdbf4c74f0 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -540,7 +540,7 @@ static void draw_markers_background(rctf *rect)
immUnbindProgram();
}
-static bool marker_is_in_frame_range(TimeMarker *marker, int frame_range[2])
+static bool marker_is_in_frame_range(TimeMarker *marker, const int frame_range[2])
{
if (marker->frame < frame_range[0]) {
return false;
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 23fb6c0ab27..11066595e2e 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -655,7 +655,7 @@ void heat_bone_weighting(Object *ob,
bDeformGroup **dgroupflip,
float (*root)[3],
float (*tip)[3],
- int *selected,
+ const int *selected,
const char **err_str)
{
LaplacianSystem *sys;
@@ -1236,7 +1236,7 @@ static float meshdeform_boundary_phi(const MeshDeformBind *mdb,
}
static float meshdeform_interp_w(MeshDeformBind *mdb,
- float *gridvec,
+ const float *gridvec,
float *UNUSED(vec),
int UNUSED(cagevert))
{
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index ef4759eab4a..0a9e6e878e4 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -56,7 +56,7 @@ void heat_bone_weighting(struct Object *ob,
struct bDeformGroup **dgroupflip,
float (*root)[3],
float (*tip)[3],
- int *selected,
+ const int *selected,
const char **error);
#ifdef RIGID_DEFORM
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 9d70f8877c6..6ce9ed06f1a 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -87,12 +87,12 @@ static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUS
* It acts as a kind of "glorified clipboard for poses", allowing for naming of poses.
*
* Features:
- * - PoseLibs are simply normal Actions.
- * - Each "pose" is simply a set of keyframes that occur on a particular frame.
- * - A set of TimeMarkers that belong to each Action, help 'label' where a 'pose' can be
+ * - Pose-libs are simply normal Actions.
+ * - Each "pose" is simply a set of key-frames that occur on a particular frame.
+ * - A set of #TimeMarker that belong to each Action, help 'label' where a 'pose' can be
* found in the Action.
- * - The Scrollwheel or PageUp/Down buttons when used in a special mode or after pressing/holding
- * [a modifier] key, cycles through the poses available for the active pose's poselib,
+ * - The Scroll-wheel or PageUp/Down buttons when used in a special mode or after pressing/holding
+ * [a modifier] key, cycles through the poses available for the active pose's pose-lib,
* allowing the animator to preview what action best suits that pose.
*/
/* ************************************************************* */
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 38ab917ba72..3e428eaffc2 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5498,6 +5498,7 @@ static int ed_editcurve_addvert(Curve *cu,
if (nu) {
nurb_new = BKE_nurb_copy(nu, 1, 1);
+ memcpy(nurb_new->bezt, nu->bezt, sizeof(BezTriple));
}
else {
nurb_new = MEM_callocN(sizeof(Nurb), "BLI_editcurve_addvert new_bezt_nurb 2");
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index e6333d7d3e0..f31e004264c 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -88,7 +88,8 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
const int draw_style = RNA_enum_get(arrow->gizmo.ptr, "draw_style");
const int draw_options = RNA_enum_get(arrow->gizmo.ptr, "draw_options");
- immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immBindBuiltinProgram(select ? GPU_SHADER_3D_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
float viewport[4];
GPU_viewport_size_get_f(viewport);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index fd24149e9ea..85f84af5f14 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -637,7 +637,7 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
}
if (select) {
- /* expand for hotspot */
+ /* Expand for hot-spot. */
const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2};
if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE) {
@@ -694,7 +694,7 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
bool show = false;
if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
/* Only show if we're drawing the center handle
- * otherwise the entire rectangle is the hotspot. */
+ * otherwise the entire rectangle is the hot-spot. */
if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
show = true;
}
@@ -805,7 +805,7 @@ static int gizmo_cage2d_test_select(bContext *C, wmGizmo *gz, const int mval[2])
return -1;
}
- /* expand for hotspot */
+ /* Expand for hots-pot. */
const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2};
const int transform_flag = RNA_enum_get(gz->ptr, "transform");
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index b0af8641767..8955a666e22 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -314,7 +314,7 @@ static void gizmo_cage3d_draw_intern(
}
if (select) {
- /* expand for hotspot */
+ /* Expand for hot-spot. */
#if 0
const float size[3] = {
size_real[0] + margin[0] / 2,
diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c
index 763f5687edf..68ab5100bf4 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.c
+++ b/source/blender/editors/gpencil/gpencil_mesh.c
@@ -82,7 +82,7 @@ static bool gpencil_bake_mesh_animation_poll(bContext *C)
}
typedef struct GpBakeOb {
- struct GPBakelist *next, *prev;
+ struct GpBakeOb *next, *prev;
Object *ob;
} GpBakeOb;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index dd5e16a9d9b..a695d2e4cf2 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -2245,7 +2245,7 @@ static void gpencil_copy_points(
}
static void gpencil_insert_point(
- bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], float co_b[3])
+ bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], const float co_b[3])
{
bGPDspoint *temp_points;
int totnewpoints, oldtotpoints;
@@ -2764,7 +2764,7 @@ void ED_gpencil_init_random_settings(Brush *brush,
}
static void gpencil_sbuffer_vertex_color_random(
- bGPdata *gpd, Brush *brush, tGPspoint *tpt, float random_color[3], float pen_pressure)
+ bGPdata *gpd, Brush *brush, tGPspoint *tpt, const float random_color[3], float pen_pressure)
{
BrushGpencilSettings *brush_settings = brush->gpencil_settings;
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
@@ -2895,7 +2895,7 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
/* Check if the stroke collides with brush. */
bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc,
bGPDstroke *gps,
- float mouse[2],
+ const float mouse[2],
const int radius,
const float diff_mat[4][4])
{
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 5f8ff228d4d..c36bc4388d7 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -348,7 +348,7 @@ static void gpencil_grid_cell_average_color_idx_get(tGP_BrushVertexpaintData *gs
}
}
-static int gpencil_grid_cell_index_get(tGP_BrushVertexpaintData *gso, int pc[2])
+static int gpencil_grid_cell_index_get(tGP_BrushVertexpaintData *gso, const int pc[2])
{
float bottom[2], top[2];
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 3aecec0d6b6..bffa11a32f2 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -708,7 +708,7 @@ void getcolor_fcurve_rainbow(int cur, int tot, float out[3]);
/* ----------------- NLA Drawing ----------------------- */
/* NOTE: Technically, this is not in the animation module (it's in space_nla)
- * but these are sometimes needed by various animation apis.
+ * but these are sometimes needed by various animation API's.
*/
/* Get color to use for NLA Action channel's background */
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index a523e924e54..8a239559627 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -106,7 +106,7 @@ struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile);
short ED_fileselect_set_params(struct SpaceFile *sfile);
void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
- int temp_win_size[],
+ const int temp_win_size[],
const bool is_maximized);
void ED_fileselect_reset_params(struct SpaceFile *sfile);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index f961f835f12..64276706759 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -351,7 +351,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
- float mouse[2],
+ const float mouse[2],
const int radius,
const float diff_mat[4][4]);
bool ED_gpencil_stroke_point_is_inside(struct bGPDstroke *gps,
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index a8476e3d1ca..e8343fbbc19 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -125,8 +125,8 @@ void ED_image_draw_info(struct Scene *scene,
const unsigned char cp[4],
const float fp[4],
const float linearcol[4],
- int *zp,
- float *zpf);
+ const int *zp,
+ const float *zpf);
bool ED_space_image_show_cache(struct SpaceImage *sima);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 47ccc0788c2..382902cd2de 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -121,7 +121,7 @@ void ED_operatormacros_node(void);
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
- int mval[2],
+ const int mval[2],
float r_col[3]);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index a851eb735b8..d8f55a0f60a 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -362,9 +362,10 @@ struct ModifierData *ED_object_modifier_add(struct ReportList *reports,
int type);
bool ED_object_modifier_remove(struct ReportList *reports,
struct Main *bmain,
+ struct Scene *scene,
struct Object *ob,
struct ModifierData *md);
-void ED_object_modifier_clear(struct Main *bmain, struct Object *ob);
+void ED_object_modifier_clear(struct Main *bmain, struct Scene *scene, struct Object *ob);
bool ED_object_modifier_move_down(struct ReportList *reports,
struct Object *ob,
struct ModifierData *md);
@@ -389,8 +390,11 @@ bool ED_object_modifier_apply(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
struct ModifierData *md,
- int mode);
+ int mode,
+ bool keep_modifier);
int ED_object_modifier_copy(struct ReportList *reports,
+ struct Main *bmain,
+ struct Scene *scene,
struct Object *ob,
struct ModifierData *md);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index bc6a4b23609..71b7d35908b 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -349,6 +349,7 @@ bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
+bool ED_operator_object_active_local_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
bool ED_operator_object_active_editable_font(struct bContext *C);
bool ED_operator_editable_mesh(struct bContext *C);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index f656aaf9c07..ec41e785714 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -47,6 +47,7 @@ struct wmKeyConfig;
/* uvedit_ops.c */
void ED_operatortypes_uvedit(void);
+void ED_operatormacros_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
bool ED_uvedit_minmax(const struct Scene *scene,
@@ -174,8 +175,26 @@ bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
float *dist_sq,
float r_uv[2]);
-void ED_uvedit_get_aspect(
- const struct Scene *scene, struct Object *ob, struct BMesh *em, float *r_aspx, float *r_aspy);
+struct BMFace **ED_uvedit_selected_faces(struct Scene *scene,
+ struct BMesh *bm,
+ int len_max,
+ int *r_faces_len);
+struct BMLoop **ED_uvedit_selected_edges(struct Scene *scene,
+ struct BMesh *bm,
+ int len_max,
+ int *r_edges_len);
+struct BMLoop **ED_uvedit_selected_verts(struct Scene *scene,
+ struct BMesh *bm,
+ int len_max,
+ int *r_verts_len);
+
+void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
+
+void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l);
+struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
+
+void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l);
+struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
/* uvedit_unwrap_ops.c */
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 5e706856738..f8a4884c594 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -150,7 +150,7 @@ void ED_view3d_cursor3d_update(struct bContext *C,
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
-void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist);
+void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist);
void ED_view3d_from_object(
const struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens);
@@ -502,7 +502,7 @@ bool ED_view3d_autodist_simple(struct ARegion *region,
const int mval[2],
float mouse_worldloc[3],
int margin,
- float *force_depth);
+ const float *force_depth);
bool ED_view3d_autodist_depth(struct ARegion *region, const int mval[2], int margin, float *depth);
bool ED_view3d_autodist_depth_seg(struct ARegion *region,
const int mval_sta[2],
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7fd45e06fbf..7ce74a87ea0 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -293,12 +293,13 @@ enum {
/* 16 to copy ICON_DEFAULT_HEIGHT */
#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
-/* Button types, bits stored in 1 value... and a short even!
- * - bits 0-4: bitnr (0-31)
+/**
+ * Button types, bits stored in 1 value... and a short even!
+ * - bits 0-4: #uiBut.bitnr (0-31)
* - bits 5-7: pointer type
* - bit 8: for 'bit'
* - bit 9-15: button type (now 6 bits, 64 types)
- * */
+ */
typedef enum {
UI_BUT_POIN_CHAR = 32,
UI_BUT_POIN_SHORT = 64,
@@ -1505,7 +1506,7 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
short width,
short height,
short *keypoin,
- short *modkeypoin,
+ const short *modkeypoin,
const char *tip);
uiBut *uiDefSearchBut(uiBlock *block,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 6c1f9d4f017..ca89c5f606f 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -737,8 +737,8 @@ static bool ui_but_update_from_old_block(const bContext *C,
#else
BLI_assert(*but_old_p == NULL || BLI_findindex(&oldblock->buttons, *but_old_p) != -1);
- /* fastpath - avoid loop-in-loop, calling 'ui_but_find_old'
- * as long as old/new buttons are aligned */
+ /* Fast-path - avoid loop-in-loop, calling #ui_but_find_old
+ * as long as old/new buttons are aligned. */
if (LIKELY(*but_old_p && ui_but_equals_old(but, *but_old_p))) {
oldbut = *but_old_p;
}
@@ -2308,7 +2308,7 @@ bool ui_but_is_rna_valid(uiBut *but)
}
/**
- * Checks if the button supports ctrl+mousewheel cycling
+ * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
*/
bool ui_but_supports_cycling(const uiBut *but)
{
@@ -6262,7 +6262,7 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
short width,
short height,
short *keypoin,
- short *modkeypoin,
+ const short *modkeypoin,
const char *tip)
{
uiBut *but = ui_def_but(block,
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index ccbbaf40992..bad833265d9 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -8935,11 +8935,11 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
my = event->y;
ui_window_to_block(region, listbox->block, &mx, &my);
- /* convert pan to scrollwheel */
+ /* Convert pan to scroll-wheel. */
if (type == MOUSEPAN) {
ui_pan_to_scroll(event, &type, &val);
- /* if type still is mousepan, we call it handled, since delta-y accumulate */
+ /* If type still is mouse-pan, we call it handled, since delta-y accumulate. */
/* also see wm_event_system.c do_wheel_ui hack */
if (type == MOUSEPAN) {
retval = WM_UI_HANDLER_BREAK;
@@ -9666,7 +9666,7 @@ static int ui_handle_menu_event(bContext *C,
int type = event->type;
int val = event->val;
- /* convert pan to scrollwheel */
+ /* Convert pan to scroll-wheel. */
if (type == MOUSEPAN) {
ui_pan_to_scroll(event, &type, &val);
}
@@ -9691,7 +9691,7 @@ static int ui_handle_menu_event(bContext *C,
case EVT_PAGEDOWNKEY:
case EVT_HOMEKEY:
case EVT_ENDKEY:
- /* arrowkeys: only handle for block_loop blocks */
+ /* Arrow-keys: only handle for block_loop blocks. */
if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
}
@@ -9699,7 +9699,7 @@ static int ui_handle_menu_event(bContext *C,
int type = event->type;
int val = event->val;
- /* convert pan to scrollwheel */
+ /* Convert pan to scroll-wheel. */
if (type == MOUSEPAN) {
ui_pan_to_scroll(event, &type, &val);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 8f98f380854..3c0b5bd3027 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -362,12 +362,13 @@ static bool id_search_add(const bContext *C,
*/
char name_ui[MAX_ID_FULL_NAME_UI];
int iconid = ui_id_icon_get(C, id, template_ui->preview);
- bool has_sep_char = (id->lib != NULL);
+ const bool use_lib_prefix = template_ui->preview || iconid;
+ const bool has_sep_char = (id->lib != NULL);
/* When using previews, the library hint (linked, overridden, missing) is added with a
* character prefix, otherwise we can use a icon. */
- BKE_id_full_name_ui_prefix_get(name_ui, id, template_ui->preview, UI_SEP_CHAR);
- if (!template_ui->preview) {
+ BKE_id_full_name_ui_prefix_get(name_ui, id, use_lib_prefix, UI_SEP_CHAR);
+ if (!use_lib_prefix) {
iconid = UI_library_icon_get(id);
}
@@ -521,7 +522,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
switch (event) {
case UI_ID_BROWSE:
case UI_ID_PIN:
- RNA_warning("warning, id event %d shouldnt come here", event);
+ RNA_warning("warning, id event %d shouldn't come here", event);
break;
case UI_ID_OPEN:
case UI_ID_ADD_NEW:
@@ -558,7 +559,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
case UI_ID_LOCAL:
if (id) {
Main *bmain = CTX_data_main(C);
- if (BKE_lib_override_library_is_enabled() && CTX_wm_window(C)->eventstate->shift) {
+ if (CTX_wm_window(C)->eventstate->shift) {
if (ID_IS_OVERRIDABLE_LIBRARY(id)) {
/* Only remap that specific ID usage to overriding local data-block. */
ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false);
@@ -568,6 +569,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
/* Assign new pointer, takes care of updates/notifiers */
RNA_id_pointer_create(override_id, &idptr);
}
+ undo_push_label = "Make Library Override";
}
}
else {
@@ -576,11 +578,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ undo_push_label = "Make Local";
}
}
- RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL);
- RNA_property_update(C, &template_ui->ptr, template_ui->prop);
- undo_push_label = "Make Local";
+ if (undo_push_label != NULL) {
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
+ }
}
break;
case UI_ID_OVERRIDE:
@@ -930,10 +934,8 @@ static void template_ID(const bContext *C,
0,
0,
0,
- BKE_lib_override_library_is_enabled() ?
- TIP_("Direct linked library data-block, click to make local, "
- "Shift + Click to create a library override") :
- TIP_("Direct linked library data-block, click to make local"));
+ TIP_("Direct linked library data-block, click to make local, "
+ "Shift + Click to create a library override"));
if (disabled) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
@@ -2186,8 +2188,13 @@ void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C)
char panel_idname[MAX_NAME];
shaderfx_panel_id(fx, panel_idname);
+ /* Create custom data RNA pointer. */
+ PointerRNA *fx_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata");
+ RNA_pointer_create(&ob->id, &RNA_ShaderFx, fx, fx_ptr);
+
Panel *new_panel = UI_panel_add_instanced(
- sa, region, &region->panels, panel_idname, i, NULL);
+ sa, region, &region->panels, panel_idname, i, fx_ptr);
+
if (new_panel != NULL) {
UI_panel_set_expand_from_list_data(C, new_panel);
}
@@ -2200,6 +2207,27 @@ void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C)
UI_panel_set_expand_from_list_data(C, panel);
}
}
+
+ /* Assuming there's only one group of instanced panels, update the custom data pointers. */
+ Panel *panel = region->panels.first;
+ LISTBASE_FOREACH (ShaderFxData *, fx, shaderfx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
+ if (fxi->panelRegister == NULL) {
+ continue;
+ }
+
+ /* Move to the next instanced panel corresponding to the next modifier. */
+ while ((panel->type == NULL) || !(panel->type->flag & PNL_INSTANCED)) {
+ panel = panel->next;
+ BLI_assert(panel != NULL); /* There shouldn't be fewer panels than modifiers with UIs. */
+ }
+
+ PointerRNA *fx_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata");
+ RNA_pointer_create(&ob->id, &RNA_ShaderFx, fx, fx_ptr);
+ UI_panel_custom_data_set(panel, fx_ptr);
+
+ panel = panel->next;
+ }
}
}
@@ -4821,6 +4849,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
/* Preset selector */
/* There is probably potential to use simpler "uiItemR" functions here, but automatic updating
* after a preset is selected would be more complicated. */
+ row = uiLayoutRow(layout, true);
bt = uiDefBlockBut(
block, CurveProfile_buttons_presets, profile, "Preset", 0, 0, UI_UNIT_X, UI_UNIT_X, "");
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 31f8c89c2bc..c8f2bec145b 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -4584,7 +4584,7 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
but->drawflag |= UI_BUT_TEXT_LEFT;
}
- /* widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
+ /* #widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
* text drawing were to add its own padding, DPI and zoom factor would be applied twice
* in the final padding, so it's difficult to control it. */
but->drawflag |= UI_BUT_NO_TEXT_PADDING;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index a2c83c24e96..c37a7279773 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -68,7 +68,7 @@ static bool view2d_poll(bContext *C)
/**
* This group of operators come in several forms:
* -# Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
- * -# Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
+ * -# Scroll-wheel 'steps' - rolling mouse-wheel by one step moves view by predefined amount
*
* In order to make sure this works, each operator must define the following RNA-Operator Props:
* - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
@@ -738,8 +738,8 @@ static void VIEW2D_OT_scroll_up(wmOperatorType *ot)
/**
* This group of operators come in several forms:
- * -# Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount.
- * -# Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y).
+ * -# Scroll-wheel 'steps' - rolling mouse-wheel by one step zooms view by predefined amount.
+ * -# Scroll-wheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y).
* XXX this could be implemented...
* -# Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount.
*
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index 0b62934d190..49cf4779496 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -268,7 +268,7 @@ void LATTICE_OT_select_mirror(wmOperatorType *ot)
* \{ */
static bool lattice_test_bitmap_uvw(
- Lattice *lt, BLI_bitmap *selpoints, int u, int v, int w, const bool selected)
+ Lattice *lt, const BLI_bitmap *selpoints, int u, int v, int w, const bool selected)
{
if ((u < 0 || u >= lt->pntsu) || (v < 0 || v >= lt->pntsv) || (w < 0 || w >= lt->pntsw)) {
return false;
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index b7fd661d8e6..c19a5b8ef68 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -439,7 +439,7 @@ static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer,
/* Convert coordinate from normalized space to pixel one.
* TODO(sergey): Make the function more generally available. */
static void mask_point_make_pixel_space(bContext *C,
- float point_normalized[2],
+ const float point_normalized[2],
float point_pixel[2])
{
ScrArea *area = CTX_wm_area(C);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index adc3be6b2ac..0394874e8c1 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -102,7 +102,7 @@ typedef struct KnifeVert {
ListBase edges;
ListBase faces;
- float co[3], cageco[3], sco[2]; /* sco is screen coordinates for cageco */
+ float co[3], cageco[3];
bool is_face, in_space;
bool is_cut; /* along a cut created by user input (will draw too) */
} KnifeVert;
@@ -429,8 +429,6 @@ static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const
copy_v3_v3(kfv->co, co);
copy_v3_v3(kfv->cageco, cageco);
- knife_project_v2(kcd, kfv->cageco, kfv->sco);
-
return kfv;
}
@@ -1548,8 +1546,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
{
SmallHash faces, kfes, kfvs;
float v1[3], v2[3], v3[3], v4[3], s1[2], s2[2];
- BVHTree *planetree, *tree;
- BVHTreeOverlap *results, *result;
+ BVHTree *tree;
+ int *results, *result;
BMLoop **ls;
BMFace *f;
KnifeEdge *kfe;
@@ -1562,7 +1560,6 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
KnifeLineHit hit;
void *val;
void **val_p;
- float plane_cos[12];
float s[2], se1[2], se2[2], sint[2];
float r1[3], r2[3];
float d, d1, d2, lambda;
@@ -1623,22 +1620,22 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
}
+ float plane[4];
+ {
+ float v1_v2[3], v1_v3[3];
+ sub_v3_v3v3(v1_v2, v2, v1);
+ sub_v3_v3v3(v1_v3, v3, v1);
+ cross_v3_v3v3(plane, v1_v2, v1_v3);
+ plane_from_point_normal_v3(plane, v1, plane);
+ }
+
/* First use bvh tree to find faces, knife edges, and knife verts that might
* intersect the cut plane with rays v1-v3 and v2-v4.
* This deduplicates the candidates before doing more expensive intersection tests. */
tree = BKE_bmbvh_tree_get(kcd->bmbvh);
- planetree = BLI_bvhtree_new(4, FLT_EPSILON * 4, 8, 8);
- copy_v3_v3(plane_cos + 0, v1);
- copy_v3_v3(plane_cos + 3, v2);
- copy_v3_v3(plane_cos + 6, v3);
- copy_v3_v3(plane_cos + 9, v4);
- BLI_bvhtree_insert(planetree, 0, plane_cos, 4);
- BLI_bvhtree_balance(planetree);
-
- results = BLI_bvhtree_overlap(tree, planetree, &tot, NULL, NULL);
+ results = BLI_bvhtree_intersect_plane(tree, plane, &tot);
if (!results) {
- BLI_bvhtree_free(planetree);
return;
}
@@ -1647,9 +1644,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
BLI_smallhash_init(&kfvs);
for (i = 0, result = results; i < tot; i++, result++) {
- ls = (BMLoop **)kcd->em->looptris[result->indexA];
+ ls = (BMLoop **)kcd->em->looptris[*result];
f = ls[0]->f;
- set_lowest_face_tri(kcd, f, result->indexA);
+ set_lowest_face_tri(kcd, f, *result);
/* occlude but never cut unselected faces (when only_select is used) */
if (kcd->only_select && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
@@ -1834,7 +1831,6 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
BLI_smallhash_release(&faces);
BLI_smallhash_release(&kfes);
BLI_smallhash_release(&kfvs);
- BLI_bvhtree_free(planetree);
if (results) {
MEM_freeN(results);
}
@@ -1928,10 +1924,11 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius
for (i = 0; i < 2; i++) {
KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+ float kfv_sco[2];
- knife_project_v2(kcd, kfv->cageco, kfv->sco);
+ knife_project_v2(kcd, kfv->cageco, kfv_sco);
- dis_sq = len_squared_v2v2(kfv->sco, sco);
+ dis_sq = len_squared_v2v2(kfv_sco, sco);
if (dis_sq < radius_sq) {
if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
@@ -1961,11 +1958,12 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
}
/* p is closest point on edge to the mouse cursor */
-static KnifeEdge *knife_find_closest_edge(
- KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space)
+static KnifeEdge *knife_find_closest_edge_of_face(KnifeTool_OpData *kcd,
+ BMFace *f,
+ float p[3],
+ float cagep[3])
{
- BMFace *f;
- float co[3], cageco[3], sco[2];
+ float sco[2];
float maxdist;
if (kcd->is_interactive) {
@@ -1979,127 +1977,105 @@ static KnifeEdge *knife_find_closest_edge(
maxdist = KNIFE_FLT_EPS;
}
- f = knife_find_closest_face(kcd, co, cageco, NULL);
- *is_space = !f;
-
- kcd->curr.bmface = f;
-
- if (f) {
- const float maxdist_sq = maxdist * maxdist;
- KnifeEdge *cure = NULL;
- float cur_cagep[3];
- ListBase *lst;
- Ref *ref;
- float dis_sq, curdis_sq = FLT_MAX;
-
- /* set p to co, in case we don't find anything, means a face cut */
- copy_v3_v3(p, co);
- copy_v3_v3(cagep, cageco);
-
- knife_project_v2(kcd, cageco, sco);
-
- /* look through all edges associated with this face */
- lst = knife_get_face_kedges(kcd, f);
- for (ref = lst->first; ref; ref = ref->next) {
- KnifeEdge *kfe = ref->ref;
- float test_cagep[3];
- float lambda;
-
- /* project edge vertices into screen space */
- knife_project_v2(kcd, kfe->v1->cageco, kfe->v1->sco);
- knife_project_v2(kcd, kfe->v2->cageco, kfe->v2->sco);
-
- /* check if we're close enough and calculate 'lambda' */
- if (kcd->is_angle_snapping) {
- /* if snapping, check we're in bounds */
- float sco_snap[2];
- isect_line_line_v2_point(
- kfe->v1->sco, kfe->v2->sco, kcd->prev.mval, kcd->curr.mval, sco_snap);
- lambda = line_point_factor_v2(sco_snap, kfe->v1->sco, kfe->v2->sco);
-
- /* be strict about angle-snapping within edge */
- if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) {
- continue;
- }
+ const float maxdist_sq = maxdist * maxdist;
+ KnifeEdge *cure = NULL;
+ float cur_cagep[3];
+ ListBase *lst;
+ Ref *ref;
+ float dis_sq, curdis_sq = FLT_MAX;
+
+ knife_project_v2(kcd, cagep, sco);
+
+ /* look through all edges associated with this face */
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref = lst->first; ref; ref = ref->next) {
+ KnifeEdge *kfe = ref->ref;
+ float kfv1_sco[2], kfv2_sco[2], test_cagep[3];
+ float lambda;
+
+ /* project edge vertices into screen space */
+ knife_project_v2(kcd, kfe->v1->cageco, kfv1_sco);
+ knife_project_v2(kcd, kfe->v2->cageco, kfv2_sco);
+
+ /* check if we're close enough and calculate 'lambda' */
+ if (kcd->is_angle_snapping) {
+ /* if snapping, check we're in bounds */
+ float sco_snap[2];
+ isect_line_line_v2_point(kfv1_sco, kfv2_sco, kcd->prev.mval, kcd->curr.mval, sco_snap);
+ lambda = line_point_factor_v2(sco_snap, kfv1_sco, kfv2_sco);
+
+ /* be strict about angle-snapping within edge */
+ if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) {
+ continue;
+ }
- dis_sq = len_squared_v2v2(sco, sco_snap);
- if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
- /* we already have 'lambda' */
- }
- else {
- continue;
- }
+ dis_sq = len_squared_v2v2(sco, sco_snap);
+ if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+ /* we already have 'lambda' */
}
else {
- dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
- if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
- lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
- }
- else {
- continue;
- }
+ continue;
}
-
- /* now we have 'lambda' calculated (in screen-space) */
- knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
-
- if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
- /* check we're in the view */
- if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
- continue;
- }
+ }
+ else {
+ dis_sq = dist_squared_to_line_segment_v2(sco, kfv1_sco, kfv2_sco);
+ if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+ lambda = line_point_factor_v2(sco, kfv1_sco, kfv2_sco);
+ }
+ else {
+ continue;
}
-
- cure = kfe;
- curdis_sq = dis_sq;
- copy_v3_v3(cur_cagep, test_cagep);
}
- if (fptr) {
- *fptr = f;
+ /* now we have 'lambda' calculated (in screen-space) */
+ knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
+
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
+ /* check we're in the view */
+ if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
+ continue;
+ }
}
- if (cure) {
- if (!kcd->ignore_edge_snapping || !(cure->e)) {
- KnifeVert *edgesnap = NULL;
+ cure = kfe;
+ curdis_sq = dis_sq;
+ copy_v3_v3(cur_cagep, test_cagep);
+ }
- if (kcd->snap_midpoints) {
- mid_v3_v3v3(p, cure->v1->co, cure->v2->co);
- mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
- }
- else {
- float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco);
- copy_v3_v3(cagep, cur_cagep);
- interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda);
- }
+ if (cure) {
+ if (!kcd->ignore_edge_snapping || !(cure->e)) {
+ KnifeVert *edgesnap = NULL;
- /* update mouse coordinates to the snapped-to edge's screen coordinates
- * this is important for angle snap, which uses the previous mouse position */
- edgesnap = new_knife_vert(kcd, p, cagep);
- kcd->curr.mval[0] = edgesnap->sco[0];
- kcd->curr.mval[1] = edgesnap->sco[1];
+ if (kcd->snap_midpoints) {
+ mid_v3_v3v3(p, cure->v1->co, cure->v2->co);
+ mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
}
else {
- return NULL;
+ float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco);
+ copy_v3_v3(cagep, cur_cagep);
+ interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda);
}
- }
-
- return cure;
- }
- if (fptr) {
- *fptr = NULL;
+ /* update mouse coordinates to the snapped-to edge's screen coordinates
+ * this is important for angle snap, which uses the previous mouse position */
+ edgesnap = new_knife_vert(kcd, p, cagep);
+ knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval);
+ }
+ else {
+ return NULL;
+ }
}
- return NULL;
+ return cure;
}
/* find a vertex near the mouse cursor, if it exists */
-static KnifeVert *knife_find_closest_vert(
- KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space)
+static KnifeVert *knife_find_closest_vert_of_face(KnifeTool_OpData *kcd,
+ BMFace *f,
+ float p[3],
+ float cagep[3])
{
- BMFace *f;
- float co[3], cageco[3], sco[2];
+ float sco[2];
float maxdist;
if (kcd->is_interactive) {
@@ -2112,84 +2088,58 @@ static KnifeVert *knife_find_closest_vert(
maxdist = KNIFE_FLT_EPS;
}
- f = knife_find_closest_face(kcd, co, cageco, is_space);
-
- kcd->curr.bmface = f;
-
- if (f) {
- const float maxdist_sq = maxdist * maxdist;
- ListBase *lst;
- Ref *ref;
- KnifeVert *curv = NULL;
- float dis_sq, curdis_sq = FLT_MAX;
-
- /* set p to co, in case we don't find anything, means a face cut */
- copy_v3_v3(p, co);
- copy_v3_v3(cagep, cageco);
+ const float maxdist_sq = maxdist * maxdist;
+ ListBase *lst;
+ Ref *ref;
+ KnifeVert *curv = NULL;
+ float cur_kfv_sco[2];
+ float dis_sq, curdis_sq = FLT_MAX;
- knife_project_v2(kcd, cageco, sco);
+ knife_project_v2(kcd, cagep, sco);
- lst = knife_get_face_kedges(kcd, f);
- for (ref = lst->first; ref; ref = ref->next) {
- KnifeEdge *kfe = ref->ref;
- int i;
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref = lst->first; ref; ref = ref->next) {
+ KnifeEdge *kfe = ref->ref;
+ int i;
- for (i = 0; i < 2; i++) {
- KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+ for (i = 0; i < 2; i++) {
+ KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+ float kfv_sco[2];
- knife_project_v2(kcd, kfv->cageco, kfv->sco);
+ knife_project_v2(kcd, kfv->cageco, kfv_sco);
- /* be strict about angle snapping, the vertex needs to be very close to the angle,
- * or we ignore */
- if (kcd->is_angle_snapping) {
- if (dist_squared_to_line_segment_v2(kfv->sco, kcd->prev.mval, kcd->curr.mval) >
- KNIFE_FLT_EPSBIG) {
- continue;
- }
+ /* be strict about angle snapping, the vertex needs to be very close to the angle,
+ * or we ignore */
+ if (kcd->is_angle_snapping) {
+ if (dist_squared_to_line_segment_v2(kfv_sco, kcd->prev.mval, kcd->curr.mval) >
+ KNIFE_FLT_EPSBIG) {
+ continue;
}
+ }
- dis_sq = len_squared_v2v2(kfv->sco, sco);
- if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
- if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
- if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
- curv = kfv;
- curdis_sq = dis_sq;
- }
- }
- else {
- curv = kfv;
- curdis_sq = dis_sq;
- }
+ dis_sq = len_squared_v2v2(kfv_sco, sco);
+ if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+ if (!RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) ||
+ !ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true)) {
+ curv = kfv;
+ curdis_sq = dis_sq;
+ copy_v2_v2(cur_kfv_sco, kfv_sco);
}
}
}
+ }
- if (!kcd->ignore_vert_snapping || !(curv && curv->v)) {
- if (fptr) {
- *fptr = f;
- }
-
- if (curv) {
- copy_v3_v3(p, curv->co);
- copy_v3_v3(cagep, curv->cageco);
-
- /* update mouse coordinates to the snapped-to vertex's screen coordinates
- * this is important for angle snap, which uses the previous mouse position */
- kcd->curr.mval[0] = curv->sco[0];
- kcd->curr.mval[1] = curv->sco[1];
- }
-
- return curv;
- }
+ if (!kcd->ignore_vert_snapping || !(curv && curv->v)) {
+ if (curv) {
+ copy_v3_v3(p, curv->co);
+ copy_v3_v3(cagep, curv->cageco);
- if (fptr) {
- *fptr = f;
+ /* update mouse coordinates to the snapped-to vertex's screen coordinates
+ * this is important for angle snap, which uses the previous mouse position */
+ copy_v2_v2(kcd->curr.mval, cur_kfv_sco);
}
- return NULL;
- }
- if (fptr) {
- *fptr = NULL;
+ return curv;
}
return NULL;
@@ -2236,11 +2186,10 @@ static bool knife_snap_angle(KnifeTool_OpData *kcd)
return true;
}
-/* update active knife edge/vert pointers */
-static int knife_update_active(KnifeTool_OpData *kcd)
+static void knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2])
{
knife_pos_data_clear(&kcd->curr);
- copy_v2_v2(kcd->curr.mval, kcd->mval);
+ copy_v2_v2(kcd->curr.mval, mval);
/* view matrix may have changed, reproject */
knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval);
@@ -2252,15 +2201,26 @@ static int knife_update_active(KnifeTool_OpData *kcd)
kcd->is_angle_snapping = false;
}
- kcd->curr.vert = knife_find_closest_vert(
- kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
+ kcd->curr.bmface = knife_find_closest_face(
+ kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.is_space);
+
+ if (kcd->curr.bmface) {
+ kcd->curr.vert = knife_find_closest_vert_of_face(
+ kcd, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
- if (!kcd->curr.vert &&
- /* no edge snapping while dragging (edges are too sticky when cuts are immediate) */
- !kcd->is_drag_hold) {
- kcd->curr.edge = knife_find_closest_edge(
- kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
+ if (!kcd->curr.vert &&
+ /* no edge snapping while dragging (edges are too sticky when cuts are immediate) */
+ !kcd->is_drag_hold) {
+ kcd->curr.edge = knife_find_closest_edge_of_face(
+ kcd, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
+ }
}
+}
+
+/* update active knife edge/vert pointers */
+static int knife_update_active(KnifeTool_OpData *kcd)
+{
+ knife_snap_update_from_mval(kcd, kcd->mval);
/* if no hits are found this would normally default to (0, 0, 0) so instead
* get a point at the mouse ray closest to the previous point.
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index b60e0074512..0cc4dcef442 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -778,6 +778,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
UvElement *newvlist = NULL, *vlist = element_map->vert[i];
UvElement *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
+ bool uv_vert_sel, uv2_vert_sel;
while (vlist) {
v = vlist;
@@ -788,6 +789,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
l = v->l;
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
uv = luv->uv;
+ uv_vert_sel = luv->flag & MLOOPUV_VERTSEL;
lastv = NULL;
iterv = vlist;
@@ -798,12 +800,17 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
l = iterv->l;
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
uv2 = luv->uv;
+ uv2_vert_sel = luv->flag & MLOOPUV_VERTSEL;
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT &&
- (!use_winding ||
- winding[BM_elem_index_get(iterv->l->f)] == winding[BM_elem_index_get(v->l->f)])) {
+ /* Check if the uv loops share the same selection state (if not, they are not connected as
+ * they have been ripped or other edit commands have seperated them). */
+ bool connected = uv_vert_sel == uv2_vert_sel && fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT &&
+ fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT;
+
+ if (connected && (!use_winding || winding[BM_elem_index_get(iterv->l->f)] ==
+ winding[BM_elem_index_get(v->l->f)])) {
if (lastv) {
lastv->next = next;
}
@@ -1029,7 +1036,7 @@ bool EDBM_vert_color_check(BMEditMesh *em)
/** \name Mirror Cache API
* \{ */
-static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
+static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int index)
{
intptr_t eve_i = index_lookup[index];
return (eve_i == -1) ? NULL : (BMVert *)eve_i;
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index bebad312454..cec425d687d 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -76,6 +76,7 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
struct BMVert *eve,
struct BMEdge *eed,
struct BMFace *efa);
+
int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, int index);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index b0730b32bed..4d84db9b35b 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -297,6 +297,37 @@ static void join_mesh_single(Depsgraph *depsgraph,
*mpoly_pp += me->totpoly;
}
+/* Face Sets IDs are a sparse sequence, so this function offsets all the IDs by face_set_offset and
+ * updates face_set_offset with the maximum ID value. This way, when used in multiple meshes, all
+ * of them will have different IDs for their Face Sets. */
+static void mesh_join_offset_face_sets_ID(const Mesh *mesh, int *face_set_offset)
+{
+ if (!mesh->totpoly) {
+ return;
+ }
+
+ int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ if (!face_sets) {
+ return;
+ }
+
+ int max_face_set = 0;
+ for (int f = 0; f < mesh->totpoly; f++) {
+ /* As face sets encode the visibility in the integer sign, the offset needs to be added or
+ * subtracted depending on the initial sign of the integer to get the new ID. */
+ if (abs(face_sets[f]) <= *face_set_offset) {
+ if (face_sets[f] > 0) {
+ face_sets[f] += *face_set_offset;
+ }
+ else {
+ face_sets[f] -= *face_set_offset;
+ }
+ }
+ max_face_set = max_ii(max_face_set, abs(face_sets[f]));
+ }
+ *face_set_offset = max_face_set;
+}
+
int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -431,7 +462,13 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
key->type = KEY_RELATIVE;
}
- /* First pass over objects: Copying materials, vertex-groups & face-maps across. */
+ /* Update face_set_id_offset with the face set data in the active object first. This way the Face
+ * Sets IDs in the active object are not the ones that are modified. */
+ Mesh *mesh_active = BKE_mesh_from_object(ob);
+ int face_set_id_offset = 0;
+ mesh_join_offset_face_sets_ID(mesh_active, &face_set_id_offset);
+
+ /* Copy materials, vertex-groups, face sets & face-maps across objects. */
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
/* only act if a mesh, and not the one we're joining to */
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
@@ -463,6 +500,8 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
ob->actfmap = 1;
}
+ mesh_join_offset_face_sets_ID(me, &face_set_id_offset);
+
if (me->totvert) {
/* Add this object's materials to the base one's if they don't exist already
* (but only if limits not exceeded yet) */
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 3618eae7db9..90ea71ae5c5 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -670,12 +670,12 @@ static bool edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
if (!ob) {
CTX_wm_operator_poll_msg_set(C, "Context missing active object");
- return 0;
+ return false;
}
if (ID_IS_LINKED(ob) || (ptr.owner_id && ID_IS_LINKED(ptr.owner_id))) {
CTX_wm_operator_poll_msg_set(C, "Cannot edit library data");
- return 0;
+ return false;
}
if (ID_IS_OVERRIDE_LIBRARY(ob) && ptr.data != NULL) {
@@ -683,7 +683,7 @@ static bool edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
return (((bConstraint *)ptr.data)->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) != 0;
}
- return 1;
+ return true;
}
static bool edit_constraint_poll(bContext *C)
@@ -702,7 +702,7 @@ static void edit_constraint_properties(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-static int edit_constraint_invoke_properties(bContext *C, wmOperator *op)
+static bool edit_constraint_invoke_properties(bContext *C, wmOperator *op)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint);
Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
@@ -711,7 +711,7 @@ static int edit_constraint_invoke_properties(bContext *C, wmOperator *op)
if (RNA_struct_property_is_set(op->ptr, "constraint") &&
RNA_struct_property_is_set(op->ptr, "owner")) {
- return 1;
+ return true;
}
if (ptr.data) {
@@ -727,10 +727,10 @@ static int edit_constraint_invoke_properties(bContext *C, wmOperator *op)
RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_BONE);
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int type)
@@ -1683,7 +1683,7 @@ void OBJECT_OT_constraints_clear(wmOperatorType *ot)
/* callbacks */
ot->exec = object_constraints_clear_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
}
/** \} */
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index a9eb454eb04..04113f70e52 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -895,7 +895,7 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
else {
if (!pd || (pd->shape != PFIELD_SHAPE_SURFACE) ||
ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) {
- ED_object_modifier_remove(NULL, bmain, object, md);
+ ED_object_modifier_remove(NULL, bmain, scene, object, md);
}
}
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index afc87c0caba..9dc204b9083 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -167,6 +167,7 @@ void OBJECT_OT_modifier_move_up(struct wmOperatorType *ot);
void OBJECT_OT_modifier_move_down(struct wmOperatorType *ot);
void OBJECT_OT_modifier_move_to_index(struct wmOperatorType *ot);
void OBJECT_OT_modifier_apply(struct wmOperatorType *ot);
+void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot);
void OBJECT_OT_modifier_convert(struct wmOperatorType *ot);
void OBJECT_OT_modifier_copy(struct wmOperatorType *ot);
void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 74109563929..6f254ea9400 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -330,10 +330,8 @@ static bool object_modifier_safe_to_delete(Main *bmain,
!ED_object_iter_other(bmain, ob, false, object_has_modifier_cb, &type));
}
-static bool object_modifier_remove(Main *bmain,
- Object *ob,
- ModifierData *md,
- bool *r_sort_depsgraph)
+static bool object_modifier_remove(
+ Main *bmain, Scene *scene, Object *ob, ModifierData *md, bool *r_sort_depsgraph)
{
/* It seems on rapid delete it is possible to
* get called twice on same modifier, so make
@@ -344,11 +342,8 @@ static bool object_modifier_remove(Main *bmain,
/* special cases */
if (md->type == eModifierType_ParticleSystem) {
- ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
-
- BLI_remlink(&ob->particlesystem, psmd->psys);
- psys_free(ob, psmd->psys);
- psmd->psys = NULL;
+ object_remove_particle_system(bmain, scene, ob);
+ return true;
}
else if (md->type == eModifierType_Softbody) {
if (ob->soft) {
@@ -391,12 +386,13 @@ static bool object_modifier_remove(Main *bmain,
return 1;
}
-bool ED_object_modifier_remove(ReportList *reports, Main *bmain, Object *ob, ModifierData *md)
+bool ED_object_modifier_remove(
+ ReportList *reports, Main *bmain, Scene *scene, Object *ob, ModifierData *md)
{
bool sort_depsgraph = false;
bool ok;
- ok = object_modifier_remove(bmain, ob, md, &sort_depsgraph);
+ ok = object_modifier_remove(bmain, scene, ob, md, &sort_depsgraph);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name);
@@ -409,7 +405,7 @@ bool ED_object_modifier_remove(ReportList *reports, Main *bmain, Object *ob, Mod
return 1;
}
-void ED_object_modifier_clear(Main *bmain, Object *ob)
+void ED_object_modifier_clear(Main *bmain, Scene *scene, Object *ob)
{
ModifierData *md = ob->modifiers.first;
bool sort_depsgraph = false;
@@ -423,7 +419,7 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
next_md = md->next;
- object_modifier_remove(bmain, ob, md, &sort_depsgraph);
+ object_modifier_remove(bmain, scene, ob, md, &sort_depsgraph);
md = next_md;
}
@@ -822,7 +818,8 @@ bool ED_object_modifier_apply(Main *bmain,
Scene *scene,
Object *ob,
ModifierData *md,
- int mode)
+ int mode,
+ bool keep_modifier)
{
int prev_mode;
@@ -830,7 +827,7 @@ bool ED_object_modifier_apply(Main *bmain,
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode");
return false;
}
- if (ID_REAL_USERS(ob->data) > 1) {
+ if (mode != MODIFIER_APPLY_SHAPE && ID_REAL_USERS(ob->data) > 1) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
return false;
}
@@ -869,22 +866,34 @@ bool ED_object_modifier_apply(Main *bmain,
}
md_eval->mode = prev_mode;
- BLI_remlink(&ob->modifiers, md);
- BKE_modifier_free(md);
+
+ if (!keep_modifier) {
+ BLI_remlink(&ob->modifiers, md);
+ BKE_modifier_free(md);
+ }
BKE_object_free_derived_caches(ob);
return true;
}
-int ED_object_modifier_copy(ReportList *UNUSED(reports), Object *ob, ModifierData *md)
+int ED_object_modifier_copy(
+ ReportList *UNUSED(reports), Main *bmain, Scene *scene, Object *ob, ModifierData *md)
{
ModifierData *nmd;
- nmd = BKE_modifier_new(md->type);
- BKE_modifier_copydata(md, nmd);
- BLI_insertlinkafter(&ob->modifiers, md, nmd);
- BKE_modifier_unique_name(&ob->modifiers, nmd);
+ if (md->type == eModifierType_ParticleSystem) {
+ nmd = object_copy_particle_system(bmain, scene, ob, ((ParticleSystemModifierData *)md)->psys);
+ BLI_remlink(&ob->modifiers, nmd);
+ BLI_insertlinkafter(&ob->modifiers, md, nmd);
+ return true;
+ }
+ else {
+ nmd = BKE_modifier_new(md->type);
+ BKE_modifier_copydata(md, nmd);
+ BLI_insertlinkafter(&ob->modifiers, md, nmd);
+ BKE_modifier_unique_name(&ob->modifiers, nmd);
+ }
return 1;
}
@@ -1116,6 +1125,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
static int modifier_remove_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
@@ -1129,7 +1139,7 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
char name[MAX_NAME];
strcpy(name, md->name);
- if (!ED_object_modifier_remove(op->reports, bmain, ob, md)) {
+ if (!ED_object_modifier_remove(op->reports, bmain, scene, ob, md)) {
return OPERATOR_CANCELLED;
}
@@ -1326,7 +1336,7 @@ void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot)
/** \name Apply Modifier Operator
* \{ */
-static bool modifier_apply_poll(bContext *C)
+static bool modifier_apply_poll_ex(bContext *C, bool allow_shared)
{
if (!edit_modifier_poll_generic(C, &RNA_Modifier, 0, false)) {
return false;
@@ -1341,7 +1351,7 @@ static bool modifier_apply_poll(bContext *C)
CTX_wm_operator_poll_msg_set(C, "Modifiers cannot be applied on override data");
return false;
}
- if ((ob->data != NULL) && ID_REAL_USERS(ob->data) > 1) {
+ if (!allow_shared && (ob->data != NULL) && ID_REAL_USERS(ob->data) > 1) {
CTX_wm_operator_poll_msg_set(C, "Modifiers cannot be applied to multi-user data");
return false;
}
@@ -1356,14 +1366,18 @@ static bool modifier_apply_poll(bContext *C)
return true;
}
-static int modifier_apply_exec(bContext *C, wmOperator *op)
+static bool modifier_apply_poll(bContext *C)
+{
+ return modifier_apply_poll_ex(C, false);
+}
+
+static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, bool keep_modifier)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
- int apply_as = RNA_enum_get(op->ptr, "apply_as");
if (md == NULL) {
return OPERATOR_CANCELLED;
@@ -1373,7 +1387,8 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
char name[MAX_NAME];
strcpy(name, md->name);
- if (!ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) {
+ if (!ED_object_modifier_apply(
+ bmain, op->reports, depsgraph, scene, ob, md, apply_as, keep_modifier)) {
return OPERATOR_CANCELLED;
}
@@ -1388,6 +1403,11 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int modifier_apply_exec(bContext *C, wmOperator *op)
+{
+ return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_DATA, false);
+}
+
static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
@@ -1397,16 +1417,6 @@ static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return retval;
}
-static const EnumPropertyItem modifier_apply_as_items[] = {
- {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
- {MODIFIER_APPLY_SHAPE,
- "SHAPE",
- 0,
- "New Shape",
- "Apply deform-only modifier to a new shape on this object"},
- {0, NULL, 0, NULL, NULL},
-};
-
void OBJECT_OT_modifier_apply(wmOperatorType *ot)
{
ot->name = "Apply Modifier";
@@ -1420,12 +1430,68 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_enum(ot->srna,
- "apply_as",
- modifier_apply_as_items,
- MODIFIER_APPLY_DATA,
- "Apply as",
- "How to apply the modifier to the geometry");
+ edit_modifier_properties(ot);
+ edit_modifier_report_property(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Apply Modifier As Shapekey Operator
+ * \{ */
+
+static bool modifier_apply_as_shapekey_poll(bContext *C)
+{
+ return modifier_apply_poll_ex(C, true);
+}
+
+static int modifier_apply_as_shapekey_exec(bContext *C, wmOperator *op)
+{
+ bool keep = RNA_boolean_get(op->ptr, "keep_modifier");
+
+ return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_SHAPE, keep);
+}
+
+static int modifier_apply_as_shapekey_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int retval;
+ if (edit_modifier_invoke_properties(C, op, event, &retval)) {
+ return modifier_apply_as_shapekey_exec(C, op);
+ }
+ else {
+ return retval;
+ }
+}
+
+static char *modifier_apply_as_shapekey_get_description(struct bContext *UNUSED(C),
+ struct wmOperatorType *UNUSED(op),
+ struct PointerRNA *values)
+{
+ bool keep = RNA_boolean_get(values, "keep_modifier");
+
+ if (keep) {
+ return BLI_strdup("Apply modifier as a new shapekey and keep it in the stack");
+ }
+
+ return NULL;
+}
+
+void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot)
+{
+ ot->name = "Apply Modifier As Shapekey";
+ ot->description = "Apply modifier as a new shapekey and remove from the stack";
+ ot->idname = "OBJECT_OT_modifier_apply_as_shapekey";
+
+ ot->invoke = modifier_apply_as_shapekey_invoke;
+ ot->exec = modifier_apply_as_shapekey_exec;
+ ot->poll = modifier_apply_as_shapekey_poll;
+ ot->get_description = modifier_apply_as_shapekey_get_description;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_boolean(
+ ot->srna, "keep_modifier", false, "Keep Modifier", "Do not remove the modifier from stack");
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
}
@@ -1487,10 +1553,12 @@ void OBJECT_OT_modifier_convert(wmOperatorType *ot)
static int modifier_copy_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
- if (!md || !ED_object_modifier_copy(op->reports, ob, md)) {
+ if (!md || !ED_object_modifier_copy(op->reports, bmain, scene, ob, md)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index e28bbb3fb1c..92880e5a114 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -130,6 +130,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_modifier_move_down);
WM_operatortype_append(OBJECT_OT_modifier_move_to_index);
WM_operatortype_append(OBJECT_OT_modifier_apply);
+ WM_operatortype_append(OBJECT_OT_modifier_apply_as_shapekey);
WM_operatortype_append(OBJECT_OT_modifier_convert);
WM_operatortype_append(OBJECT_OT_modifier_copy);
WM_operatortype_append(OBJECT_OT_multires_subdivide);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d37f03b7f55..945c7e87eb1 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1878,7 +1878,7 @@ static void single_obdata_users(
/* Needed to remap texcomesh below. */
me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data));
if (me->key) { /* We do not need to set me->key->id.newid here... */
- BKE_animdata_copy_id_action(bmain, (ID *)me->key, false);
+ BKE_animdata_copy_id_action(bmain, (ID *)me->key);
}
break;
case OB_MBALL:
@@ -1891,13 +1891,13 @@ static void single_obdata_users(
ID_NEW_REMAP(cu->bevobj);
ID_NEW_REMAP(cu->taperobj);
if (cu->key) { /* We do not need to set cu->key->id.newid here... */
- BKE_animdata_copy_id_action(bmain, (ID *)cu->key, false);
+ BKE_animdata_copy_id_action(bmain, (ID *)cu->key);
}
break;
case OB_LATTICE:
ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data));
if (lat->key) { /* We do not need to set lat->key->id.newid here... */
- BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false);
+ BKE_animdata_copy_id_action(bmain, (ID *)lat->key);
}
break;
case OB_ARMATURE:
@@ -1937,7 +1937,7 @@ static void single_obdata_users(
* AnimData structure, which is not what we want.
* (sergey)
*/
- BKE_animdata_copy_id_action(bmain, (ID *)ob->data, false);
+ BKE_animdata_copy_id_action(bmain, (ID *)ob->data);
id_us_min(id);
}
@@ -1958,7 +1958,7 @@ static void single_object_action_users(
FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
if (!ID_IS_LINKED(ob)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_animdata_copy_id_action(bmain, &ob->id, false);
+ BKE_animdata_copy_id_action(bmain, &ob->id);
}
}
FOREACH_OBJECT_FLAG_END;
@@ -1980,7 +1980,7 @@ static void single_mat_users(
if (ma->id.us > 1) {
man = BKE_material_copy(bmain, ma);
- BKE_animdata_copy_id_action(bmain, &man->id, false);
+ BKE_animdata_copy_id_action(bmain, &man->id);
man->id.us = 0;
BKE_object_material_assign(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -2242,28 +2242,6 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
/** \name Make Library Override Operator
* \{ */
-static bool make_override_hierarchy_recursive_tag(Main *bmain, ID *id)
-{
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
-
- /* This way we won't process again that ID should we encounter it again through another
- * relationship hierarchy.
- * Note that this does not free any memory from relations, so we can still use the entries.
- */
- BKE_main_relations_ID_remove(bmain, id);
-
- for (; entry != NULL; entry = entry->next) {
- /* We only consider IDs from the same library. */
- if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
- if (make_override_hierarchy_recursive_tag(bmain, *entry->id_pointer)) {
- id->tag |= LIB_TAG_DOIT;
- }
- }
- }
-
- return (id->tag & LIB_TAG_DOIT) != 0;
-}
-
static int make_override_tag_ids_cb(LibraryIDLinkCallbackData *cb_data)
{
if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) {
@@ -2315,14 +2293,9 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve
return OPERATOR_CANCELLED;
}
- /* Get object to work on - use a menu if we need to... */
- if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
- ID_IS_LINKED(obact->instance_collection)) {
- /* Gives menu with list of objects in group. */
- WM_enum_search_invoke(C, op, event);
- return OPERATOR_CANCELLED;
- }
- if (ID_IS_LINKED(obact)) {
+ if ((!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) ||
+ ID_IS_OVERRIDABLE_LIBRARY(obact)) {
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
uiLayout *layout = UI_popup_menu_layout(pup);
@@ -2337,6 +2310,11 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve
/* This invoke just calls another instance of this operator... */
return OPERATOR_INTERFACE;
}
+ else if (ID_IS_LINKED(obact)) {
+ /* Show menu with list of directly linked collections containing the active object. */
+ WM_enum_search_invoke(C, op, event);
+ return OPERATOR_CANCELLED;
+ }
/* Error.. cannot continue. */
BKE_report(op->reports,
@@ -2366,11 +2344,28 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
id_root = &obact->instance_collection->id;
}
else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) {
- BKE_reportf(op->reports,
- RPT_ERROR_INVALID_INPUT,
- "Active object '%s' is not overridable",
- obact->id.name + 2);
- return OPERATOR_CANCELLED;
+ const int i = RNA_property_enum_get(op->ptr, op->type->prop);
+ const uint collection_session_uuid = *((uint *)&i);
+ if (collection_session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Active object '%s' is not overridable",
+ obact->id.name + 2);
+ return OPERATOR_CANCELLED;
+ }
+
+ Collection *collection = BLI_listbase_bytes_find(&bmain->collections,
+ &collection_session_uuid,
+ sizeof(collection_session_uuid),
+ offsetof(ID, session_uuid));
+ if (!ID_IS_OVERRIDABLE_LIBRARY(collection)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Could not find an overridable collection containing object '%s'",
+ obact->id.name + 2);
+ return OPERATOR_CANCELLED;
+ }
+ id_root = &collection->id;
}
/* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
else {
@@ -2399,12 +2394,8 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
}
}
- /* Then we tag all intermediary data-blocks in-between two overridden ones (e.g. if a shapekey
- * has a driver using an armature object's bone, we need to override the shapekey/obdata, the
- * objects using them, etc.) */
- make_override_hierarchy_recursive_tag(bmain, id_root);
-
- BKE_main_relations_free(bmain);
+ /* Note that this call will also free the main relations data we created above. */
+ BKE_lib_override_library_dependencies_tag(bmain, id_root, LIB_TAG_DOIT, false);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -2523,10 +2514,40 @@ static bool make_override_library_poll(bContext *C)
Object *obact = CTX_data_active_object(C);
/* Object must be directly linked to be overridable. */
- return (BKE_lib_override_library_is_enabled() && ED_operator_objectmode(C) && obact != NULL &&
- ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) ||
- (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
- ID_IS_LINKED(obact->instance_collection))));
+ return (ED_operator_objectmode(C) && obact != NULL &&
+ (ID_IS_LINKED(obact) || (obact->instance_collection != NULL &&
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection))));
+}
+
+static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem item_tmp = {0}, *item = NULL;
+ int totitem = 0;
+
+ Object *object = ED_object_active_context(C);
+ Main *bmain = CTX_data_main(C);
+
+ if (!object || !ID_IS_LINKED(object)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ /* Only check for directly linked collections. */
+ if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0) {
+ continue;
+ }
+ if (BKE_collection_has_object_recursive(collection, object)) {
+ item_tmp.identifier = item_tmp.name = collection->id.name + 2;
+ item_tmp.value = *((int *)&collection->id.session_uuid);
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
void OBJECT_OT_make_override_library(wmOperatorType *ot)
@@ -2547,12 +2568,13 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
prop = RNA_def_enum(ot->srna,
- "object",
+ "collection",
DummyRNA_DEFAULT_items,
- 0,
- "Override Object",
- "Name of lib-linked/collection object to make an override from");
- RNA_def_enum_funcs(prop, proxy_collection_object_itemf);
+ MAIN_ID_SESSION_UUID_UNSET,
+ "Override Collection",
+ "Name of directly linked collection containing the selected object, to make "
+ "an override from");
+ RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
}
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index 8df87a8a2f9..977d4abd4d4 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -24,6 +24,7 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
@@ -55,6 +56,8 @@
#include "ED_object.h"
#include "ED_screen.h"
+#include "UI_interface.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -247,7 +250,7 @@ static int shaderfx_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
return OPERATOR_FINISHED;
}
@@ -360,21 +363,57 @@ static void edit_shaderfx_properties(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-static int edit_shaderfx_invoke_properties(bContext *C, wmOperator *op)
+static void edit_shaderfx_report_property(wmOperatorType *ot)
{
- ShaderFxData *fx;
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "report", false, "Report", "Create a notification after the operation");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+/**
+ * \param event: If this isn't NULL, the operator will also look for panels underneath
+ * the cursor with customdata set to a modifier.
+ * \param r_retval: This should be used if #event is used in order to to return
+ * #OPERATOR_PASS_THROUGH to check other operators with the same key set.
+ */
+static bool edit_shaderfx_invoke_properties(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ int *r_retval)
+{
if (RNA_struct_property_is_set(op->ptr, "shaderfx")) {
return true;
}
- PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx);
- if (ptr.data) {
- fx = ptr.data;
+ PointerRNA ctx_ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx);
+ if (ctx_ptr.data != NULL) {
+ ShaderFxData *fx = ctx_ptr.data;
RNA_string_set(op->ptr, "shaderfx", fx->name);
return true;
}
+ /* Check the custom data of panels under the mouse for an effect. */
+ if (event != NULL) {
+ PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event);
+
+ if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) {
+ if (RNA_struct_is_a(panel_ptr->type, &RNA_ShaderFx)) {
+ ShaderFxData *fx = panel_ptr->data;
+ RNA_string_set(op->ptr, "shaderfx", fx->name);
+ return true;
+ }
+
+ BLI_assert(r_retval != NULL); /* We need the return value in this case. */
+ if (r_retval != NULL) {
+ *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED);
+ }
+ return false;
+ }
+ }
+
+ if (r_retval != NULL) {
+ *r_retval = OPERATOR_CANCELLED;
+ }
return false;
}
@@ -403,21 +442,30 @@ static int shaderfx_remove_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_active_context(C);
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+ /* Store name temporarily for report. */
+ char name[MAX_NAME];
+ strcpy(name, fx->name);
+
if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) {
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ if (RNA_boolean_get(op->ptr, "report")) {
+ BKE_reportf(op->reports, RPT_INFO, "Removed effect: %s", name);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
return OPERATOR_FINISHED;
}
-static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (edit_shaderfx_invoke_properties(C, op)) {
+ int retval;
+ if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
return shaderfx_remove_exec(C, op);
}
- return OPERATOR_CANCELLED;
+ return retval;
}
void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
@@ -433,6 +481,7 @@ void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_shaderfx_properties(ot);
+ edit_shaderfx_report_property(ot);
}
/************************ move up shaderfx operator *********************/
@@ -447,17 +496,18 @@ static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
return OPERATOR_FINISHED;
}
-static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (edit_shaderfx_invoke_properties(C, op)) {
+ int retval;
+ if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
return shaderfx_move_up_exec(C, op);
}
- return OPERATOR_CANCELLED;
+ return retval;
}
void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
@@ -487,17 +537,18 @@ static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
return OPERATOR_FINISHED;
}
-static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (edit_shaderfx_invoke_properties(C, op)) {
+ int retval;
+ if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
return shaderfx_move_down_exec(C, op);
}
- return OPERATOR_CANCELLED;
+ return retval;
}
void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
@@ -533,17 +584,18 @@ static int shaderfx_move_to_index_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
return OPERATOR_FINISHED;
}
-static int shaderfx_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int shaderfx_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (edit_shaderfx_invoke_properties(C, op)) {
+ int retval;
+ if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
return shaderfx_move_to_index_exec(C, op);
}
- return OPERATOR_CANCELLED;
+ return retval;
}
void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot)
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 6922a03b12f..381bf317bee 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -102,7 +102,7 @@ void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = surface_slot_add_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -151,7 +151,7 @@ void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = surface_slot_remove_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -203,7 +203,7 @@ void DPAINT_OT_type_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = type_toggle_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -286,7 +286,7 @@ void DPAINT_OT_output_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = output_toggle_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -538,5 +538,5 @@ void DPAINT_OT_bake(wmOperatorType *ot)
/* api callbacks */
ot->exec = dynamicpaint_bake_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
}
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index e75169a476b..41e30adf724 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -104,7 +104,7 @@ void OBJECT_OT_particle_system_add(wmOperatorType *ot)
ot->description = "Add a particle system";
/* api callbacks */
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
ot->exec = particle_system_add_exec;
/* flags */
@@ -151,7 +151,7 @@ void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
ot->description = "Remove the selected particle system";
/* api callbacks */
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
ot->exec = particle_system_remove_exec;
/* flags */
@@ -1210,7 +1210,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
static bool copy_particle_systems_poll(bContext *C)
{
Object *ob;
- if (!ED_operator_object_active_editable(C)) {
+ if (!ED_operator_object_active_local_editable(C)) {
return false;
}
@@ -1311,7 +1311,7 @@ void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
static bool duplicate_particle_systems_poll(bContext *C)
{
- if (!ED_operator_object_active_editable(C)) {
+ if (!ED_operator_object_active_local_editable(C)) {
return false;
}
Object *ob = ED_object_active_context(C);
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 583c68cb284..26b5f7fb2af 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -546,6 +546,7 @@ static int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
return OPERATOR_CANCELLED;
}
if (!fluid_validatepaths(job, op->reports)) {
+ fluid_bake_free(job);
return OPERATOR_CANCELLED;
}
WM_report_banners_cancel(job->bmain);
@@ -574,6 +575,7 @@ static int fluid_bake_invoke(struct bContext *C,
}
if (!fluid_validatepaths(job, op->reports)) {
+ fluid_bake_free(job);
return OPERATOR_CANCELLED;
}
@@ -651,6 +653,7 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
job->name = op->type->name;
if (!fluid_validatepaths(job, op->reports)) {
+ fluid_bake_free(job);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 754f8226684..149bae718a0 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -162,7 +162,7 @@ void OBJECT_OT_material_slot_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = material_slot_add_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -207,7 +207,7 @@ void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = material_slot_remove_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -310,7 +310,7 @@ void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
/* api callbacks */
ot->exec = material_slot_assign_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -564,6 +564,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
ot->description = "Move the active material up/down in the list";
/* api callbacks */
+ ot->poll = ED_operator_object_active_local_editable;
ot->exec = material_slot_move_exec;
/* flags */
@@ -638,7 +639,7 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
/* api callbacks */
ot->exec = material_slot_remove_unused_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = ED_operator_object_active_local_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -707,6 +708,7 @@ void MATERIAL_OT_new(wmOperatorType *ot)
ot->description = "Add a new material";
/* api callbacks */
+ ot->poll = ED_operator_object_active_local_editable;
ot->exec = new_material_exec;
/* flags */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f32dd0c8703..b034fb186d2 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -360,6 +360,13 @@ bool ED_operator_object_active_editable(bContext *C)
return ED_operator_object_active_editable_ex(C, ob);
}
+/** Object must be editable and fully local (i.e. not an override). */
+bool ED_operator_object_active_local_editable(bContext *C)
+{
+ Object *ob = ED_object_active_context(C);
+ return ED_operator_object_active_editable_ex(C, ob) && !ID_IS_OVERRIDE_LIBRARY(ob);
+}
+
bool ED_operator_object_active_editable_mesh(bContext *C)
{
Object *ob = ED_object_active_context(C);
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 892aea6048f..be7b824fc3e 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -875,8 +875,12 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
return alpha_overlay_active;
}
-BLI_INLINE void draw_tri_point(
- uint pos, const float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_tri_point(uint pos,
+ const float sel_col[4],
+ const float pivot_col[4],
+ float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : pivot_col);
@@ -905,8 +909,12 @@ BLI_INLINE void draw_tri_point(
immEnd();
}
-BLI_INLINE void draw_rect_point(
- uint pos, const float sel_col[4], float handle_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_rect_point(uint pos,
+ const float sel_col[4],
+ const float handle_col[4],
+ const float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : handle_col);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 16ccfaf8286..a7f09390a3d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -257,7 +257,7 @@ static ushort *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size
/* update rectangular section of the brush image */
static void brush_painter_mask_imbuf_update(BrushPainter *painter,
ImagePaintTile *tile,
- ushort *tex_mask_old,
+ const ushort *tex_mask_old,
int origx,
int origy,
int w,
@@ -1052,7 +1052,7 @@ static void paint_2d_lift_soften(ImagePaintState *s,
ImagePaintTile *tile,
ImBuf *ibuf,
ImBuf *ibufb,
- int *pos,
+ const int *pos,
const short paint_tile)
{
bool sharpen = (tile->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
@@ -1255,7 +1255,7 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short paint
}
}
-static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, const int *pos)
{
/* note: allocImbuf returns zero'd memory, so regions outside image will
* have zero alpha, and hence not be blended onto the image */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 83620b4bc56..5af3a3f4241 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1426,7 +1426,7 @@ static void insert_seam_vert_array(const ProjPaintState *ps,
* Be tricky with flags, first 4 bits are #PROJ_FACE_SEAM0 to 4,
* last 4 bits are #PROJ_FACE_NOSEAM0 to 4. `1 << i` - where i is `(0..3)`.
*
- * If we're multithreadng, make sure threads are locked when this is called.
+ * If we're multi-threading, make sure threads are locked when this is called.
*/
static void project_face_seams_init(const ProjPaintState *ps,
MemArena *arena,
@@ -3566,8 +3566,8 @@ static bool project_bucket_face_isect(ProjPaintState *ps,
int bucket_y,
const MLoopTri *lt)
{
- /* TODO - replace this with a tricker method that uses sideofline for all
- * screenCoords's edges against the closest bucket corner */
+ /* TODO - replace this with a trickier method that uses side-of-line for all
+ * #ProjPaintState.screenCoords edges against the closest bucket corner. */
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
rctf bucket_bounds;
float p1[2], p2[2], p3[2], p4[2];
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index be545600e6e..d65f158174f 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -246,7 +246,11 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
color = BKE_palette_color_add(palette);
palette->active_color = BLI_listbase_count(&palette->colors) - 1;
- if (ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX)) {
+ if (ELEM(mode,
+ PAINT_MODE_TEXTURE_3D,
+ PAINT_MODE_TEXTURE_2D,
+ PAINT_MODE_VERTEX,
+ PAINT_MODE_SCULPT)) {
copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
color->value = 0.0;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 048f11c92d7..d05b1673c9a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -206,7 +206,7 @@ void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
/** \name Smooth Vertex Colors Operator
* \{ */
-static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag)
+static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
{
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const MPoly *mp;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 6d83e88b556..ffdf2c1e7c0 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -547,28 +547,81 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
}
}
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- int face_set = -1;
- for (int i = 0; i < ss->pmap[index].count; i++) {
- if (face_set == -1) {
- face_set = abs(ss->face_sets[vert_map->indices[i]]);
+ MeshElemMap *vert_map = &ss->pmap[index];
+ int face_set = -1;
+ for (int i = 0; i < ss->pmap[index].count; i++) {
+ if (face_set == -1) {
+ face_set = abs(ss->face_sets[vert_map->indices[i]]);
+ }
+ else {
+ if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * Checks if the face sets of the adjacent faces to the edge between \a v1 and \a v2
+ * in the base mesh are equal.
+ */
+static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2)
+{
+ MeshElemMap *vert_map = &ss->pmap[v1];
+ int p1 = -1, p2 = -1;
+ for (int i = 0; i < ss->pmap[v1].count; i++) {
+ MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ for (int l = 0; l < p->totloop; l++) {
+ MLoop *loop = &ss->mloop[p->loopstart + l];
+ if (loop->v == v2) {
+ if (p1 == -1) {
+ p1 = vert_map->indices[i];
+ break;
}
- else {
- if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) {
- return false;
- }
+ else if (p2 == -1) {
+ p2 = vert_map->indices[i];
+ break;
}
}
- return true;
+ }
+ }
+
+ if (p1 != -1 && p2 != -1) {
+ return abs(ss->face_sets[p1]) == (ss->face_sets[p2]);
+ }
+ return true;
+}
+
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES: {
+ return sculpt_check_unique_face_set_in_base_mesh(ss, index);
}
case PBVH_BMESH:
return false;
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ const SubdivCCGCoord coord = {.grid_index = grid_index,
+ .x = vertex_index % key->grid_size,
+ .y = vertex_index / key->grid_size};
+ int v1, v2;
+ const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
+ ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
+ switch (adjacency) {
+ case SUBDIV_CCG_ADJACENT_VERTEX:
+ return sculpt_check_unique_face_set_in_base_mesh(ss, v1);
+ case SUBDIV_CCG_ADJACENT_EDGE:
+ return sculpt_check_unique_face_set_for_edge_in_base_mesh(ss, v1, v2);
+ case SUBDIV_CCG_ADJACENT_NONE:
+ return true;
+ }
+ }
}
return false;
}
@@ -735,44 +788,64 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
}
}
+static bool sculpt_check_boundary_vertex_in_base_mesh(SculptSession *ss, const int index)
+{
+ const MeshElemMap *vert_map = &ss->pmap[index];
+ if (vert_map->count <= 1) {
+ return true;
+ }
+ for (int i = 0; i < vert_map->count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ unsigned f_adj_v[2];
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
+ int j;
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ if (!(vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- const MeshElemMap *vert_map = &ss->pmap[index];
-
- if (vert_map->count <= 1) {
- return false;
- }
-
if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) {
- return false;
- }
-
- for (int i = 0; i < vert_map->count; i++) {
- const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[2];
- if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
- int j;
- for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (!(vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2)) {
- return false;
- }
- }
- }
+ return true;
}
- return true;
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, index);
}
case PBVH_BMESH: {
BMVert *v = BM_vert_at_index(ss->bm, index);
return BM_vert_is_boundary(v);
}
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ const SubdivCCGCoord coord = {.grid_index = grid_index,
+ .x = vertex_index % key->grid_size,
+ .y = vertex_index / key->grid_size};
+ int v1, v2;
+ const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
+ ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
+ switch (adjacency) {
+ case SUBDIV_CCG_ADJACENT_VERTEX:
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, v1);
+ case SUBDIV_CCG_ADJACENT_EDGE:
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, v1) &&
+ sculpt_check_boundary_vertex_in_base_mesh(ss, v2);
+ case SUBDIV_CCG_ADJACENT_NONE:
+ return false;
+ }
+ }
}
- return true;
+ return false;
}
/* Utilities */
@@ -2400,7 +2473,10 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
}
float t[3], bb_min[3], bb_max[3];
- if (data->ignore_fully_masked) {
+ if (data->ignore_fully_ineffective) {
+ if (BKE_pbvh_node_fully_hidden_get(node)) {
+ return false;
+ }
if (BKE_pbvh_node_fully_masked_get(node)) {
return false;
}
@@ -2436,7 +2512,7 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
SculptSearchCircleData *data = data_v;
float bb_min[3], bb_max[3];
- if (data->ignore_fully_masked) {
+ if (data->ignore_fully_ineffective) {
if (BKE_pbvh_node_fully_masked_get(node)) {
return false;
}
@@ -2489,7 +2565,7 @@ static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
.sd = sd,
.radius_squared = ss->cursor_radius,
.original = use_original,
- .ignore_fully_masked = false,
+ .ignore_fully_ineffective = false,
.center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
@@ -2514,7 +2590,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
.sd = sd,
.radius_squared = square_f(ss->cache->radius * radius_scale),
.original = use_original,
- .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
+ .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
.center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
@@ -2530,7 +2606,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
ss->cursor_radius,
.original = use_original,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
- .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
+ .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode);
}
@@ -5387,11 +5463,15 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
if (brush->sculpt_tool == SCULPT_TOOL_PAINT && type != PBVH_FACES) {
- return;
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return;
+ }
}
if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && type != PBVH_FACES) {
- return;
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return;
+ }
}
/* Build a list of all nodes that are potentially within the brush's area of influence */
@@ -5411,7 +5491,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.sd = sd,
.radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)),
.original = false,
- .ignore_fully_masked = false,
+ .ignore_fully_ineffective = false,
.center = ss->cache->initial_location,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
@@ -6046,6 +6126,14 @@ bool SCULPT_mode_poll(bContext *C)
return ob && ob->mode & OB_MODE_SCULPT;
}
+bool SCULPT_vertex_colors_poll(bContext *C)
+{
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return false;
+ }
+ return SCULPT_mode_poll(C);
+}
+
bool SCULPT_mode_poll_view3d(bContext *C)
{
return (SCULPT_mode_poll(C) && CTX_wm_region_view3d(C));
@@ -8096,7 +8184,7 @@ static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_vertex_to_loop_colors";
/* api callbacks */
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->exec = vertex_to_loop_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8159,7 +8247,7 @@ static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_loop_to_vertex_colors";
/* api callbacks */
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->exec = loop_to_vertex_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8184,7 +8272,6 @@ static int sculpt_sample_color_invoke(bContext *C,
copy_v3_v3(color_srgb, active_vertex_color);
IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
BKE_brush_color_set(scene, brush, color_srgb);
- BKE_brush_alpha_set(scene, brush, active_vertex_color[3]);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
@@ -8200,7 +8287,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->flag = OPTYPE_REGISTER;
}
@@ -8209,7 +8296,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
/* This allows the sculpt tools to work on meshes with multiple connected components as they had
* only one connected component. When initialized and enabled, the sculpt API will return extra
* connectivity neighbors that are not in the real mesh. These neighbors are calculated for each
- * vertex using the minimun distance to a vertex that is in a different connected component. */
+ * vertex using the minimum distance to a vertex that is in a different connected component. */
/* The fake neighbors first need to be ensured to be initialized.
* After that tools which needs fake neighbors functionality need to
@@ -8224,7 +8311,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
* }
*
* Such approach allows to keep all the connectivity information ready for reuse
- * (withouy having lag prior to every stroke), but also makes it so the affect
+ * (without having lag prior to every stroke), but also makes it so the affect
* is localized to a specific brushes and tools only. */
enum {
@@ -8681,6 +8768,11 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+ /* Color data is not available in Multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return OPERATOR_CANCELLED;
+ }
+
if (!ss->vcol) {
return OPERATOR_CANCELLED;
}
@@ -8726,12 +8818,12 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_mask_by_color_invoke;
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->flag = OPTYPE_REGISTER;
ot->prop = RNA_def_boolean(
- ot->srna, "contiguous", false, "Contiguous", "Mask only contiguos color areas");
+ ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
ot->prop = RNA_def_boolean(
@@ -8774,6 +8866,7 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_face_sets_init);
WM_operatortype_append(SCULPT_OT_cloth_filter);
WM_operatortype_append(SCULPT_OT_face_sets_edit);
+
WM_operatortype_append(SCULPT_OT_sample_color);
WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c
index 7c79c1d7a2f..48b278e52b6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c
@@ -209,7 +209,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
{
SculptSession *ss = ob->sculpt;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ if (!ss->pmap) {
BLI_assert(!"Boundary Edges masking: pmap missing");
return NULL;
}
@@ -221,7 +221,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
- if (!SCULPT_vertex_is_boundary(ss, i)) {
+ if (SCULPT_vertex_is_boundary(ss, i)) {
edge_distance[i] = 0;
}
break;
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 6ca45ee0fb8..6a2137b6626 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -437,13 +437,16 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
BKE_pbvh_vertex_iter_end;
}
-static void cloth_brush_build_nodes_constraints(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- int totnode,
- SculptClothSimulation *cloth_sim,
- float initial_location[3],
- const float radius)
+static void cloth_brush_build_nodes_constraints(
+ Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ SculptClothSimulation *cloth_sim,
+ /* Cannot be const, because it is assigned to a non-const variable.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ float initial_location[3],
+ const float radius)
{
Brush *brush = BKE_paint_brush(&sd->paint);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 5f7805af347..556b73b0ea5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -308,7 +308,7 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_color_filter_invoke;
ot->modal = sculpt_color_filter_modal;
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 494588d0996..27dd0ab3e71 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -87,7 +87,7 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd, const int undo_type)
.original = true,
.center = center,
.radius_squared = FLT_MAX,
- .ignore_fully_masked = true,
+ .ignore_fully_ineffective = true,
};
BKE_pbvh_search_gather(pbvh,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index c7e07721eb7..e943bd280a3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -51,6 +51,8 @@ bool SCULPT_mode_poll_view3d(struct bContext *C);
bool SCULPT_poll(struct bContext *C);
bool SCULPT_poll_view3d(struct bContext *C);
+bool SCULPT_vertex_colors_poll(struct bContext *C);
+
/* Updates */
typedef enum SculptUpdateType {
@@ -676,7 +678,8 @@ typedef struct {
float radius_squared;
const float *center;
bool original;
- bool ignore_fully_masked;
+ /* This ignores fully masked and fully hidden nodes. */
+ bool ignore_fully_ineffective;
} SculptSearchSphereData;
typedef struct {
@@ -684,7 +687,7 @@ typedef struct {
struct SculptSession *ss;
float radius_squared;
bool original;
- bool ignore_fully_masked;
+ bool ignore_fully_ineffective;
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 5cf6a053382..608ba1b934e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -388,7 +388,17 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
float interp_color[4];
copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]);
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
normalize_v3_v3(current_disp_norm, current_disp);
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index e084d5fcdf2..49dbba5eba9 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -159,6 +159,7 @@ void ED_spacemacros_init(void)
* We need to have them go after python operators too */
ED_operatormacros_armature();
ED_operatormacros_mesh();
+ ED_operatormacros_uvedit();
ED_operatormacros_metaball();
ED_operatormacros_node();
ED_operatormacros_object();
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 71b86996989..88c2c6e82b6 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -422,6 +422,9 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
buttons_area_redraw(area, BCONTEXT_CONSTRAINT);
buttons_area_redraw(area, BCONTEXT_BONE_CONSTRAINT);
break;
+ case ND_SHADERFX:
+ buttons_area_redraw(area, BCONTEXT_SHADERFX);
+ break;
case ND_PARTICLE:
if (wmn->action == NA_EDITED) {
buttons_area_redraw(area, BCONTEXT_PARTICLE);
@@ -435,13 +438,6 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
/* Needed to refresh context path when changing active particle system index. */
buttons_area_redraw(area, BCONTEXT_PARTICLE);
break;
- case ND_SHADING:
- case ND_SHADING_DRAW:
- case ND_SHADING_LINKS:
- case ND_SHADING_PREVIEW:
- /* currently works by redraws... if preview is set, it (re)starts job */
- sbuts->preview = 1;
- break;
default:
/* Not all object RNA props have a ND_ notifier (yet) */
ED_area_tag_redraw(area);
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 35e0fdbfec3..68ebd6fed7a 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1111,7 +1111,7 @@ static void draw_marker_texts(SpaceClip *sc,
pos[1] -= fontsize;
if (track->flag & TRACK_HAS_BUNDLE) {
- BLI_snprintf(str, sizeof(str), "Average error: %.3f", track->error);
+ BLI_snprintf(str, sizeof(str), "Average error: %.2f px", track->error);
BLF_position(fontid, pos[0], pos[1], 0.0f);
BLF_draw(fontid, str, sizeof(str));
pos[1] -= fontsize;
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index a69601316ef..9da75ab7e3c 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1403,6 +1403,8 @@ static void do_sequence_proxy(void *pjv,
int build_count,
int *build_undistort_sizes,
int build_undistort_count,
+ /* Cannot be const, because it is assigned to a non-const variable.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
short *stop,
short *do_update,
float *progress)
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index c18207d7045..1ed965c30d2 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -144,7 +144,7 @@ static void solve_camera_freejob(void *scv)
else {
BKE_reportf(scj->reports,
RPT_INFO,
- "Average re-projection error: %.3f",
+ "Average re-projection error: %.2f px",
tracking->reconstruction.error);
}
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index cec7b371457..afbca48bd45 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -214,7 +214,13 @@ static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwa
return true;
}
-static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
+static void track_markers_startjob(
+ void *tmv,
+ /* Cannot be const, this function implements wm_jobs_start_callback.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ short *stop,
+ short *do_update,
+ float *progress)
{
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
int framenr = tmj->sfra;
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 81cc858c69f..b6f9ca9589f 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -731,7 +731,9 @@ void CLIP_OT_select_lasso(wmOperatorType *ot)
/********************** circle select operator *********************/
-static int point_inside_ellipse(float point[2], float offset[2], float ellipse[2])
+static int point_inside_ellipse(const float point[2],
+ const float offset[2],
+ const float ellipse[2])
{
/* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
float x, y;
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index cb785495ad5..3ce80c11160 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2660,9 +2660,9 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
if (filelist->dir[0] == 0) {
/* make directories */
# ifdef WITH_FREESTYLE
- filelist->filelist.nbr_entries = 27;
+ filelist->filelist.nbr_entries = 27;
# else
- filelist->filelist.nbr_entries = 26;
+ filelist->filelist.nbr_entries = 26;
# endif
filelist_resize(filelist, filelist->filelist.nbr_entries);
@@ -2693,11 +2693,11 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action");
filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree");
filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker");
- filelist->filelist.entries[23].entry->relpath = BLI_strdup("Hair");
- filelist->filelist.entries[24].entry->relpath = BLI_strdup("Point Cloud");
- filelist->filelist.entries[25].entry->relpath = BLI_strdup("Volume");
+ filelist->filelist.entries[23].entry->relpath = BLI_strdup("Hair");
+ filelist->filelist.entries[24].entry->relpath = BLI_strdup("Point Cloud");
+ filelist->filelist.entries[25].entry->relpath = BLI_strdup("Volume");
# ifdef WITH_FREESTYLE
- filelist->filelist.entries[26].entry->relpath = BLI_strdup("FreestyleLineStyle");
+ filelist->filelist.entries[26].entry->relpath = BLI_strdup("FreestyleLineStyle");
# endif
}
else {
@@ -2809,7 +2809,7 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
static void filelist_readjob_do(const bool do_lib,
FileList *filelist,
const char *main_name,
- short *stop,
+ const short *stop,
short *do_update,
float *progress,
ThreadMutex *lock)
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e6c40dce9c8..88c8c6b2939 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -374,7 +374,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
* pass its size here so we can store that in the preferences. Otherwise NULL.
*/
void ED_fileselect_params_to_userdef(SpaceFile *sfile,
- int temp_win_size[2],
+ const int temp_win_size[2],
const bool is_maximized)
{
UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index bff81201d60..4b329ab4524 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -754,8 +754,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
fsmenu, FS_CATEGORY_OTHER, &FOLDERID_SkyDrive, NULL, ICON_URL, FS_INSERT_LAST);
}
}
-#else
-# ifdef __APPLE__
+#elif defined(__APPLE__)
{
/* We store some known macOS system paths and corresponding icons
* and names in the FS_CATEGORY_OTHER (not displayed directly) category. */
@@ -774,9 +773,9 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
const char *home = BLI_getenv("HOME");
-# define FS_MACOS_PATH(path, name, icon) \
- BLI_snprintf(line, sizeof(line), path, home); \
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_OTHER, line, name, icon, FS_INSERT_LAST);
+# define FS_MACOS_PATH(path, name, icon) \
+ BLI_snprintf(line, sizeof(line), path, home); \
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_OTHER, line, name, icon, FS_INSERT_LAST);
FS_MACOS_PATH("%s/", NULL, ICON_HOME)
FS_MACOS_PATH("%s/Desktop/", IFACE_("Desktop"), ICON_DESKTOP)
@@ -787,7 +786,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
FS_MACOS_PATH("%s/Pictures/", IFACE_("Pictures"), ICON_FILE_IMAGE)
FS_MACOS_PATH("%s/Library/Fonts/", IFACE_("Fonts"), ICON_FILE_FONT)
-# undef FS_MACOS_PATH
+# undef FS_MACOS_PATH
/* Get mounted volumes better method OSX 10.6 and higher, see:
* https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html
@@ -849,8 +848,8 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15.
* Will have to find a new method to sync the Finder Favorites with File Browser. */
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* Finally get user favorite places */
if (read_bookmarks) {
UInt32 seed;
@@ -894,9 +893,9 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(pathesArray);
CFRelease(list);
}
-# pragma GCC diagnostic pop
+# pragma GCC diagnostic pop
}
-# else
+#else
/* unix */
{
const char *home = BLI_getenv("HOME");
@@ -932,7 +931,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
{
int found = 0;
-# ifdef __linux__
+# ifdef __linux__
/* loop over mount points */
struct mntent *mnt;
FILE *fp;
@@ -994,7 +993,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
}
BLI_filelist_free(dir, dir_len);
}
-# endif
+# endif
/* fallback */
if (!found) {
@@ -1003,7 +1002,6 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
}
}
}
-# endif
#endif
#if defined(WIN32) || defined(__APPLE__)
@@ -1131,10 +1129,13 @@ int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory categor
* before being defined as unreachable by the OS, we need to validate the bookmarks in an async
* job...
*/
-static void fsmenu_bookmark_validate_job_startjob(void *fsmenuv,
- short *stop,
- short *do_update,
- float *UNUSED(progress))
+static void fsmenu_bookmark_validate_job_startjob(
+ void *fsmenuv,
+ /* Cannot be const, this function implements wm_jobs_start_callback.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ short *stop,
+ short *do_update,
+ float *UNUSED(progress))
{
FSMenu *fsmenu = fsmenuv;
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 179d73a38ba..0158e12c79c 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -1420,7 +1420,7 @@ void graph_buttons_register(ARegionType *art)
pt->poll = graph_panel_drivers_poll;
BLI_addtail(&art->paneltypes, pt);
- pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers pover");
+ pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers popover");
strcpy(pt->idname, "GRAPH_PT_drivers_popover");
strcpy(pt->label, N_("Add/Edit Driver"));
strcpy(pt->category, "Drivers");
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 24ec2393b69..1f8dd7cfe44 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -572,8 +572,12 @@ static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v))
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
-static void uiblock_layer_pass_buttons(
- uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
+static void uiblock_layer_pass_buttons(uiLayout *layout,
+ Image *image,
+ RenderResult *rr,
+ ImageUser *iuser,
+ int w,
+ const short *render_slot)
{
struct ImageUI_Data rnd_pt_local, *rnd_pt = NULL;
uiBlock *block = uiLayoutGetBlock(layout);
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 9040ca5e79c..a7fa7709c51 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -150,8 +150,8 @@ void ED_image_draw_info(Scene *scene,
const uchar cp[4],
const float fp[4],
const float linearcol[4],
- int *zp,
- float *zpf)
+ const int *zp,
+ const float *zpf)
{
rcti color_rect;
char str[256];
@@ -463,7 +463,7 @@ void ED_image_draw_info(Scene *scene,
/* image drawing */
static void sima_draw_zbuf_pixels(
- float x1, float y1, int rectx, int recty, int *rect, float zoomx, float zoomy)
+ float x1, float y1, int rectx, int recty, const int *rect, float zoomx, float zoomy)
{
float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
@@ -489,7 +489,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene,
float y1,
int rectx,
int recty,
- float *rect_float,
+ const float *rect_float,
float zoomx,
float zoomy)
{
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index d0d9f2f57bb..130167f1bd0 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -392,7 +392,7 @@ static void nla_panel_properties(const bContext *C, Panel *panel)
uiItemR(column, &strip_ptr, "blend_type", 0, NULL, ICON_NONE);
/* Blend in/out + auto-blending:
- * - blend in/out can only be set when autoblending is off
+ * - blend in/out can only be set when auto-blending is off.
*/
uiItemS(layout);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index a56b7f8422e..96599fd92a7 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -645,8 +645,9 @@ static void nla_draw_strip_text(AnimData *adt,
UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
}
-/* add frame extents to cache of text-strings to draw in pixelspace
- * for now, only used when transforming strips
+/**
+ * Add frame extents to cache of text-strings to draw in pixel-space
+ * for now, only used when transforming strips.
*/
static void nla_draw_strip_frames_text(
NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float UNUSED(yminc), float ymaxc)
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index f3207f2dc1e..780c3d6a217 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -860,11 +860,13 @@ static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), Poin
if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) {
uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, NULL, 0);
+ uiLayout *col;
if (RNA_boolean_get(ptr, "sun_disc")) {
- uiItemR(layout, ptr, "sun_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "sun_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sun_intensity", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiLayout *col;
col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "sun_elevation", DEFAULT_FLAGS, NULL, ICON_NONE);
uiItemR(col, ptr, "sun_rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 11d87148713..7af64e75656 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -238,7 +238,12 @@ static void compo_progressjob(void *cjv, float progress)
}
/* only this runs inside thread */
-static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
+static void compo_startjob(void *cjv,
+ /* Cannot be const, this function implements wm_jobs_start_callback.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ short *stop,
+ short *do_update,
+ float *progress)
{
CompoJob *cj = cjv;
bNodeTree *ntree = cj->localtree;
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index b1dbe3bc506..b376c6b29cf 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -419,7 +419,7 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
* And here we've got recursion in the comments tips...
*/
bool ED_space_node_color_sample(
- Main *bmain, SpaceNode *snode, ARegion *region, int mval[2], float r_col[3])
+ Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float r_col[3])
{
void *lock;
Image *ima;
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index a77b5424eb6..f0287984268 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -54,6 +54,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
@@ -739,22 +740,63 @@ static void id_local_cb(bContext *C,
}
}
+typedef struct OutlinerLibOverrideData {
+ bool do_hierarchy;
+} OutlinerLibOverrideData;
+
static void id_override_library_cb(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
- TreeElement *UNUSED(te),
+ TreeElement *te,
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
- void *UNUSED(user_data))
+ void *user_data)
{
- if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id)) {
+ BLI_assert(TSE_IS_REAL_ID(tselem));
+ ID *id_root = tselem->id;
+
+ if (ID_IS_LINKED(id_root) &&
+ (BKE_idtype_get_info_from_id(id_root)->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0) {
Main *bmain = CTX_data_main(C);
+ OutlinerLibOverrideData *data = user_data;
+ const bool do_hierarchy = data->do_hierarchy;
+
+ id_root->tag |= LIB_TAG_DOIT;
+
+ printf("%s: Tagging root id %s\n", __func__, id_root->name);
+
/* For now, remapp all local usages of linked ID to local override one here. */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
- ID *override_id = BKE_lib_override_library_create_from_id(bmain, tselem->id, true);
- if (override_id != NULL) {
- BKE_main_id_clear_newpoins(bmain);
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ if (ID_IS_LINKED(id_iter)) {
+ id_iter->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ id_iter->tag |= LIB_TAG_DOIT;
+ }
}
+ FOREACH_MAIN_ID_END;
+
+ if (do_hierarchy) {
+ /* Tag all linked parents in tree hierarchy to be also overridden. */
+ while ((te = te->parent) != NULL) {
+ if (!TSE_IS_REAL_ID(te->store_elem)) {
+ continue;
+ }
+ if (!ID_IS_LINKED(te->store_elem->id)) {
+ break;
+ }
+ te->store_elem->id->tag |= LIB_TAG_DOIT;
+ printf("%s: Tagging parent id %s\n", __func__, te->store_elem->id->name);
+ }
+ BKE_lib_override_library_dependencies_tag(bmain, id_root, LIB_TAG_DOIT, true);
+ BKE_lib_override_library_create_from_tag(bmain);
+ }
+ else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
+ BKE_lib_override_library_create_from_id(bmain, id_root, true);
+ }
+
+ BKE_main_id_clear_newpoins(bmain);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
}
@@ -1127,6 +1169,7 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
{
bContext *C = (bContext *)Carg;
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
ModifierData *md = (ModifierData *)te->directdata;
Object *ob = (Object *)outliner_search_back(te, ID_OB);
@@ -1141,7 +1184,7 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (event == OL_MODIFIER_OP_DELETE) {
- ED_object_modifier_remove(NULL, bmain, ob, md);
+ ED_object_modifier_remove(NULL, bmain, scene, ob, md);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
te->store_elem->flag &= ~TSE_SELECTED;
}
@@ -1325,8 +1368,8 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth trick
- * does not work here). */
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
}
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
@@ -1507,6 +1550,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_OVERRIDE_LIBRARY,
+ OUTLINER_IDOP_OVERRIDE_LIBRARY_HIERARCHY,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
OUTLINER_IDOP_REMAP,
@@ -1530,6 +1574,11 @@ static const EnumPropertyItem prop_id_op_types[] = {
0,
"Add Library Override",
"Add a local override of this linked data-block"},
+ {OUTLINER_IDOP_OVERRIDE_LIBRARY_HIERARCHY,
+ "OVERRIDE_LIBRARY_HIERARCHY",
+ 0,
+ "Add Library Override Hierarchy",
+ "Add a local override of this linked data-block, and its hierarchy of dependencies"},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
{OUTLINER_IDOP_REMAP,
@@ -1562,7 +1611,7 @@ static bool outliner_id_operation_item_poll(bContext *C,
switch (enum_value) {
case OUTLINER_IDOP_OVERRIDE_LIBRARY:
- return BKE_lib_override_library_is_enabled();
+ return true;
case OUTLINER_IDOP_SINGLE:
if (!soops || ELEM(soops->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
return true;
@@ -1676,12 +1725,27 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY: {
- if (BKE_lib_override_library_is_enabled()) {
- /* make local */
- outliner_do_libdata_operation(
- C, op->reports, scene, soops, &soops->tree, id_override_library_cb, NULL);
- ED_undo_push(C, "Overridden Data");
- }
+ /* make local */
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ soops,
+ &soops->tree,
+ id_override_library_cb,
+ &(OutlinerLibOverrideData){.do_hierarchy = false});
+ ED_undo_push(C, "Overridden Data");
+ break;
+ }
+ case OUTLINER_IDOP_OVERRIDE_LIBRARY_HIERARCHY: {
+ /* make local */
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ soops,
+ &soops->tree,
+ id_override_library_cb,
+ &(OutlinerLibOverrideData){.do_hierarchy = true});
+ ED_undo_push(C, "Overridden Data");
break;
}
case OUTLINER_IDOP_SINGLE: {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 7178f32f182..0d8e0a87694 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -2607,6 +2607,8 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
MetaStack *ms;
bool nothing_selected = true;
+ BKE_sequencer_prefetch_stop(scene);
+
seq = BKE_sequencer_active_get(scene);
if (seq && seq->flag & SELECT) { /* Avoid a loop since this is likely to be selected. */
nothing_selected = false;
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index a20d9a2942c..80b1c7a5194 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -50,14 +50,14 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
yuv[2] += 0.5f;
}
-static void scope_put_pixel(uchar *table, uchar *pos)
+static void scope_put_pixel(const uchar *table, uchar *pos)
{
uchar newval = table[*pos];
pos[0] = pos[1] = pos[2] = newval;
pos[3] = 255;
}
-static void scope_put_pixel_single(uchar *table, uchar *pos, int col)
+static void scope_put_pixel_single(const uchar *table, uchar *pos, int col)
{
char newval = table[pos[col]];
pos[col] = newval;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index ed81d87f053..c88303daa16 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -825,6 +825,7 @@ static void view3d_main_region_listener(
case ND_POSE:
case ND_DRAW:
case ND_MODIFIER:
+ case ND_SHADERFX:
case ND_CONSTRAINT:
case ND_KEYS:
case ND_PARTICLE:
@@ -1381,6 +1382,7 @@ static void view3d_buttons_region_listener(wmWindow *UNUSED(win),
case ND_DRAW:
case ND_KEYS:
case ND_MODIFIER:
+ case ND_SHADERFX:
ED_region_tag_redraw(region);
break;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 33625a8b775..fab98857c99 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -509,8 +509,8 @@ static void viewops_data_create(bContext *C,
negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */
- /* Set the dist value to be the distance from this 3d point this means youll
- * always be able to zoom into it and panning wont go bad when dist was zero */
+ /* Set the dist value to be the distance from this 3d point this means you'll
+ * always be able to zoom into it and panning wont go bad when dist was zero. */
/* remove dist value */
upvec[0] = upvec[1] = 0;
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index c13990a4391..cc19ecf35a8 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -200,7 +200,7 @@ typedef struct FlyInfo {
float grid;
/* compare between last state */
- /** Used to accelerate when using the mousewheel a lot. */
+ /** Used to accelerate when using the mouse-wheel a lot. */
double time_lastwheel;
/** Time between draws. */
double time_lastdraw;
@@ -614,8 +614,8 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event)
fly->axis = -1;
}
else {
- /* flip speed rather than stopping, game like motion,
- * else increase like mousewheel if we're already moving in that direction */
+ /* Flip speed rather than stopping, game like motion,
+ * else increase like mouse-wheel if we're already moving in that direction. */
if (fly->speed < 0.0f) {
fly->speed = -fly->speed;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index b7d857fb172..fc763d91e3d 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1572,7 +1572,7 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
static Base *object_mouse_select_menu(bContext *C,
ViewContext *vc,
- uint *buffer,
+ const uint *buffer,
int hits,
const int mval[2],
bool extend,
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index d3e509fe96b..0d121b23c71 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -1028,8 +1028,11 @@ void ED_view3d_autodist_init(Depsgraph *depsgraph, ARegion *region, View3D *v3d,
}
/* no 4x4 sampling, run #ED_view3d_autodist_init first */
-bool ED_view3d_autodist_simple(
- ARegion *region, const int mval[2], float mouse_worldloc[3], int margin, float *force_depth)
+bool ED_view3d_autodist_simple(ARegion *region,
+ const int mval[2],
+ float mouse_worldloc[3],
+ int margin,
+ const float *force_depth)
{
float depth;
@@ -1458,7 +1461,7 @@ bool ED_view3d_lock(RegionView3D *rv3d)
* \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
* \param dist: The view distance from ofs, normally from RegionView3D.dist.
*/
-void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist)
+void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
{
float nmat[3][3];
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index d68489759fe..70004d27dfc 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_kdtree.h"
+#include "BLI_linklist_stack.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -409,59 +410,66 @@ void transform_autoik_update(TransInfo *t, short mode)
/** \name Curve Surface
* \{ */
-void calc_distanceCurveVerts(TransData *head, TransData *tail)
+void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic)
{
- TransData *td, *td_near = NULL;
+ TransData *td;
+ BLI_LINKSTACK_DECLARE(queue, TransData *);
+ BLI_LINKSTACK_INIT(queue);
for (td = head; td <= tail; td++) {
if (td->flag & TD_SELECTED) {
- td_near = td;
td->dist = 0.0f;
+ BLI_LINKSTACK_PUSH(queue, td);
}
- else if (td_near) {
- float dist;
- float vec[3];
+ else {
+ td->dist = FLT_MAX;
+ }
+ }
+
+ while ((td = BLI_LINKSTACK_POP(queue))) {
+ float dist;
+ float vec[3];
+
+ TransData *next_td = NULL;
- sub_v3_v3v3(vec, td_near->center, td->center);
+ if (td + 1 <= tail) {
+ next_td = td + 1;
+ }
+ else if (cyclic) {
+ next_td = head;
+ }
+
+ if (next_td != NULL && !(next_td->flag & TD_NOTCONNECTED)) {
+ sub_v3_v3v3(vec, next_td->center, td->center);
mul_m3_v3(head->mtx, vec);
- dist = len_v3(vec);
+ dist = len_v3(vec) + td->dist;
- if (dist < (td - 1)->dist) {
- td->dist = (td - 1)->dist;
- }
- else {
- td->dist = dist;
+ if (dist < next_td->dist) {
+ next_td->dist = dist;
+ BLI_LINKSTACK_PUSH(queue, next_td);
}
}
- else {
- td->dist = FLT_MAX;
- td->flag |= TD_NOTCONNECTED;
+
+ next_td = NULL;
+
+ if (td - 1 >= head) {
+ next_td = td - 1;
}
- }
- td_near = NULL;
- for (td = tail; td >= head; td--) {
- if (td->flag & TD_SELECTED) {
- td_near = td;
- td->dist = 0.0f;
+ else if (cyclic) {
+ next_td = tail;
}
- else if (td_near) {
- float dist;
- float vec[3];
- sub_v3_v3v3(vec, td_near->center, td->center);
+ if (next_td != NULL && !(next_td->flag & TD_NOTCONNECTED)) {
+ sub_v3_v3v3(vec, next_td->center, td->center);
mul_m3_v3(head->mtx, vec);
- dist = len_v3(vec);
+ dist = len_v3(vec) + td->dist;
- if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td + 1)->dist < td->dist) {
- td->flag &= ~TD_NOTCONNECTED;
- if (dist < (td + 1)->dist) {
- td->dist = (td + 1)->dist;
- }
- else {
- td->dist = dist;
- }
+ if (dist < next_td->dist) {
+ next_td->dist = dist;
+ BLI_LINKSTACK_PUSH(queue, next_td);
}
}
}
+ BLI_LINKSTACK_FREE(queue);
}
/* Utility function for getting the handle data from bezier's */
@@ -1270,6 +1278,9 @@ void createTransData(bContext *C, TransInfo *t)
set_prop_dist(t, false);
}
}
+ else if (convert_type == TC_MESH_UV && t->flag & T_PROP_CONNECTED) {
+ /* Already calculated by uv_set_connectivity_distance. */
+ }
else if (convert_type == TC_CURVE_VERTS && t->obedit_type == OB_CURVE) {
set_prop_dist(t, false);
}
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index f7eea286983..ee478ad8567 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -87,7 +87,7 @@ void transform_around_single_fallback_ex(TransInfo *t, int data_len_all);
void transform_around_single_fallback(TransInfo *t);
void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle);
bool constraints_list_needinv(TransInfo *t, ListBase *list);
-void calc_distanceCurveVerts(TransData *head, TransData *tail);
+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);
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 37e37072ed7..65b2c9f9382 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -350,12 +350,14 @@ void createTransCurveVerts(TransInfo *t)
(void)hdata; /* quiet warning */
}
else if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- head = tail;
+ tail->flag |= TD_NOTCONNECTED;
+ td++;
+ tail++;
}
}
if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
+ bool cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0;
+ calc_distanceCurveVerts(head, tail - 1, cyclic);
}
/* TODO - in the case of tilt and radius we can also avoid allocating the
@@ -425,12 +427,14 @@ void createTransCurveVerts(TransInfo *t)
}
}
else if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- head = tail;
+ tail->flag |= TD_NOTCONNECTED;
+ td++;
+ tail++;
}
}
if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
+ bool cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0;
+ calc_distanceCurveVerts(head, tail - 1, cyclic);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 22261b9bbd8..0eb12aeabed 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -354,7 +354,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
/* March over these points, and calculate the proportional editing distances */
if (is_prop_edit && (head != tail)) {
- calc_distanceCurveVerts(head, tail - 1);
+ calc_distanceCurveVerts(head, tail - 1, false);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 90e45253afa..f067dd60c19 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1067,7 +1067,7 @@ static void create_trans_vert_customdata_layer(BMVert *v,
BLI_ghash_insert(tcld->origverts, v, r_tcld_vert);
}
-static void trans_mesh_customdata_correction_init_container(TransInfo *t, TransDataContainer *tc)
+static void trans_mesh_customdata_correction_init_container(TransDataContainer *tc)
{
if (tc->custom.type.data) {
/* Custom data correction has initiated before. */
@@ -1075,23 +1075,6 @@ static void trans_mesh_customdata_correction_init_container(TransInfo *t, TransD
return;
}
- if (!ELEM(t->mode,
- TFM_TRANSLATION,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TOSPHERE,
- TFM_SHEAR,
- TFM_BEND,
- TFM_SHRINKFATTEN,
- TFM_TRACKBALL,
- TFM_PUSHPULL,
- TFM_ALIGN,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
- /* Currently only modes that change the position of vertices are supported. */
- return;
- }
-
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
@@ -1173,13 +1156,63 @@ static void trans_mesh_customdata_correction_init_container(TransInfo *t, TransD
void trans_mesh_customdata_correction_init(TransInfo *t)
{
+ if (!ELEM(t->mode,
+ TFM_TRANSLATION,
+ TFM_ROTATION,
+ TFM_RESIZE,
+ TFM_TOSPHERE,
+ TFM_SHEAR,
+ TFM_BEND,
+ TFM_SHRINKFATTEN,
+ TFM_TRACKBALL,
+ TFM_PUSHPULL,
+ TFM_ALIGN,
+ TFM_EDGE_SLIDE,
+ TFM_VERT_SLIDE)) {
+ /* Currently only modes that change the position of vertices are supported. */
+ return;
+ }
+
const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ?
UVCALC_TRANSFORM_CORRECT_SLIDE :
UVCALC_TRANSFORM_CORRECT;
if (t->settings->uvcalc_flag & uvcalc_correct_flag) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- trans_mesh_customdata_correction_init_container(t, tc);
+ trans_mesh_customdata_correction_init_container(tc);
+ }
+ }
+}
+
+static void trans_mesh_customdata_correction_restore(struct TransDataContainer *tc)
+{
+ struct TransCustomDataLayer *tcld = tc->custom.type.data;
+ if (!tcld) {
+ return;
+ }
+
+ BMesh *bm = tcld->bm;
+ struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0];
+ for (int i = tcld->data_len; i--; tcld_vert_iter++) {
+ BMLoop *l;
+ BMIter liter;
+ BMVert *v = tcld_vert_iter->v;
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ /* Pop the key to not restore the face again. */
+ BMFace *f_copy = BLI_ghash_popkey(tcld->origfaces, l->f, NULL);
+ if (f_copy) {
+ BMLoop *l_iter_a, *l_first_a;
+ BMLoop *l_iter_b, *l_first_b;
+ l_iter_a = l_first_a = BM_FACE_FIRST_LOOP(f_copy);
+ l_iter_b = l_first_b = BM_FACE_FIRST_LOOP(l->f);
+ do {
+ BM_elem_attrs_copy(tcld->bm_origfaces, bm, l_iter_a, l_iter_b);
+ } while (((l_iter_a = l_iter_a->next) != l_first_a) &&
+ ((l_iter_b = l_iter_b->next) != l_first_b));
+
+ BM_elem_attrs_copy_ex(
+ tcld->bm_origfaces, bm, f_copy, l->f, BM_ELEM_SELECT, CD_MASK_NORMAL);
+ }
}
}
}
@@ -1195,7 +1228,7 @@ static const float *trans_vert_orig_co_get(struct TransCustomDataLayer *tcld, BM
static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLayer *tcld,
struct TransCustomDataLayerVert *tcld_vert,
- bool is_final)
+ bool do_loop_mdisps)
{
BMesh *bm = tcld->bm;
BMVert *v = tcld_vert->v;
@@ -1295,8 +1328,8 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa
* Interpolate from every other loop (not ideal)
* However values will only be taken from loops which overlap other mdisps.
* */
- const bool do_loop_mdisps = is_moved && is_final && (tcld->cd_loop_mdisp_offset != -1);
- if (do_loop_mdisps) {
+ const bool update_loop_mdisps = is_moved && do_loop_mdisps && (tcld->cd_loop_mdisp_offset != -1);
+ if (update_loop_mdisps) {
float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
BMLoop *l;
@@ -1332,12 +1365,12 @@ static void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc
return;
}
- const bool has_mdisps = (tcld->cd_loop_mdisp_offset != -1);
+ const bool do_loop_mdisps = is_final && (tcld->cd_loop_mdisp_offset != -1);
struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0];
for (int i = tcld->data_len; i--; tcld_vert_iter++) {
- if (tcld_vert_iter->cd_loop_groups || has_mdisps) {
- trans_mesh_customdata_correction_apply_vert(tcld, tcld_vert_iter, is_final);
+ if (tcld_vert_iter->cd_loop_groups || do_loop_mdisps) {
+ trans_mesh_customdata_correction_apply_vert(tcld, tcld_vert_iter, do_loop_mdisps);
}
}
}
@@ -1388,8 +1421,9 @@ static void transform_apply_to_mirror(TransInfo *t)
void recalcData_mesh(TransInfo *t)
{
+ bool is_cancelling = t->state == TRANS_CANCEL;
/* mirror modifier clipping? */
- if (t->state != TRANS_CANCEL) {
+ if (!is_cancelling) {
/* apply clipping after so we never project past the clip plane [#25423] */
applyProject(t);
clipMirrorModifier(t);
@@ -1400,7 +1434,12 @@ void recalcData_mesh(TransInfo *t)
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- trans_mesh_customdata_correction_apply(tc, false);
+ if (is_cancelling) {
+ trans_mesh_customdata_correction_restore(tc);
+ }
+ else {
+ trans_mesh_customdata_correction_apply(tc, false);
+ }
DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1416,15 +1455,15 @@ void recalcData_mesh(TransInfo *t)
void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
- const bool canceled = (t->state == TRANS_CANCEL);
- const bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
+ const bool is_cancelling = (t->state == TRANS_CANCEL);
+ const bool use_automerge = !is_cancelling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
- if (TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.type.data != NULL) {
+ if (!is_cancelling && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.type.data != NULL) {
/* Handle multires re-projection, done
* on transform completion since it's
* really slow -joeedh. */
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- trans_mesh_customdata_correction_apply(tc, !canceled);
+ trans_mesh_customdata_correction_apply(tc, true);
}
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 41c09cd8ea2..56fa2d90fb2 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
+#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -51,12 +52,13 @@ static void UVsToTransData(const float aspect[2],
TransData2D *td2d,
float *uv,
const float *center,
+ float calc_dist,
bool selected)
{
- /* uv coords are scaled by aspects. this is needed for rotations and
- * proportional editing to be consistent with the stretched uv coords
- * that are displayed. this also means that for display and numinput,
- * and when the uv coords are flushed, these are converted each time */
+ /* UV coords are scaled by aspects. this is needed for rotations and
+ * proportional editing to be consistent with the stretched UV coords
+ * that are displayed. this also means that for display and number-input,
+ * and when the UV coords are flushed, these are converted each time. */
td2d->loc[0] = uv[0] * aspect[0];
td2d->loc[1] = uv[1] * aspect[1];
td2d->loc[2] = 0.0f;
@@ -79,12 +81,182 @@ static void UVsToTransData(const float aspect[2],
td->dist = 0.0;
}
else {
- td->dist = FLT_MAX;
+ td->dist = calc_dist;
}
unit_m3(td->mtx);
unit_m3(td->smtx);
}
+/**
+ * \param dists: Store the closest connected distance to selected vertices.
+ */
+static void uv_set_connectivity_distance(BMesh *bm, float *dists, const float aspect[2])
+{
+ /* Mostly copied from editmesh_set_connectivity_distance. */
+ BLI_LINKSTACK_DECLARE(queue, BMLoop *);
+
+ /* Any BM_ELEM_TAG'd loop is added to 'queue_next', this makes sure that we don't add things
+ * twice. */
+ BLI_LINKSTACK_DECLARE(queue_next, BMLoop *);
+
+ BLI_LINKSTACK_INIT(queue);
+ BLI_LINKSTACK_INIT(queue_next);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ BMIter fiter, liter;
+ BMVert *f;
+ BMLoop *l;
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ /* Visable faces was tagged in createTransUVs. */
+ if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ float dist;
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ bool uv_vert_sel = luv->flag & MLOOPUV_VERTSEL;
+
+ if (uv_vert_sel) {
+ BLI_LINKSTACK_PUSH(queue, l);
+ dist = 0.0f;
+ }
+ else {
+ dist = FLT_MAX;
+ }
+
+ /* Make sure all loops are in a clean tag state. */
+ BLI_assert(BM_elem_flag_test(l, BM_ELEM_TAG) == 0);
+
+ int loop_idx = BM_elem_index_get(l);
+
+ dists[loop_idx] = dist;
+ }
+ }
+
+ /* Need to be very careful of feedback loops here, store previous dist's to avoid feedback. */
+ float *dists_prev = MEM_dupallocN(dists);
+
+ do {
+ while ((l = BLI_LINKSTACK_POP(queue))) {
+ BLI_assert(dists[BM_elem_index_get(l)] != FLT_MAX);
+
+ BMLoop *l_other, *l_connected;
+ BMIter l_connected_iter;
+
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float l_uv[2];
+
+ copy_v2_v2(l_uv, luv->uv);
+ mul_v2_v2(l_uv, aspect);
+
+ BM_ITER_ELEM (l_other, &liter, l->f, BM_LOOPS_OF_FACE) {
+ if (l_other == l) {
+ continue;
+ }
+ float other_uv[2], edge_vec[2];
+ MLoopUV *luv_other = BM_ELEM_CD_GET_VOID_P(l_other, cd_loop_uv_offset);
+
+ copy_v2_v2(other_uv, luv_other->uv);
+ mul_v2_v2(other_uv, aspect);
+
+ sub_v2_v2v2(edge_vec, l_uv, other_uv);
+
+ const int i = BM_elem_index_get(l);
+ const int i_other = BM_elem_index_get(l_other);
+ float dist = len_v2(edge_vec) + dists_prev[i];
+
+ if (dist < dists[i_other]) {
+ dists[i_other] = dist;
+ }
+ else {
+ /* The face loop already has a shorter path to it. */
+ continue;
+ }
+
+ float connected_uv[2];
+ float uvdiff[2];
+
+ bool other_vert_sel, connected_vert_sel;
+
+ other_vert_sel = luv_other->flag & MLOOPUV_VERTSEL;
+
+ BM_ITER_ELEM (l_connected, &l_connected_iter, l_other->v, BM_LOOPS_OF_VERT) {
+ if (l_connected == l_other) {
+ continue;
+ }
+ /* Visable faces was tagged in createTransUVs. */
+ if (!BM_elem_flag_test(l_connected->f, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ MLoopUV *luv_connected = BM_ELEM_CD_GET_VOID_P(l_connected, cd_loop_uv_offset);
+ connected_vert_sel = luv_connected->flag & MLOOPUV_VERTSEL;
+ copy_v2_v2(connected_uv, luv_connected->uv);
+ mul_v2_v2(connected_uv, aspect);
+
+ sub_v2_v2v2(uvdiff, connected_uv, other_uv);
+ /* Check if this loop is connected in UV space.
+ * If the uv loops share the same selection state (if not, they are not connected as
+ * they have been ripped or other edit commands have separated them). */
+ bool connected = other_vert_sel == connected_vert_sel &&
+ fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT &&
+ fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT;
+ if (!connected) {
+ continue;
+ }
+
+ /* The loop vert is occupying the same space, so it has the same distance. */
+ const int i_connected = BM_elem_index_get(l_connected);
+ dists[i_connected] = dist;
+
+ if (BM_elem_flag_test(l_connected, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(l_connected, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, l_connected);
+ }
+ }
+ }
+ }
+
+ /* Clear elem flags for the next loop. */
+ for (LinkNode *lnk = queue_next; lnk; lnk = lnk->next) {
+ BMLoop *l_link = lnk->link;
+ const int i = BM_elem_index_get(l_link);
+
+ BM_elem_flag_disable(l_link, BM_ELEM_TAG);
+
+ /* Store all new dist values. */
+ dists_prev[i] = dists[i];
+ }
+
+ BLI_LINKSTACK_SWAP(queue, queue_next);
+
+ } while (BLI_LINKSTACK_SIZE(queue));
+
+#ifndef NDEBUG
+ /* Check that we didn't leave any loops tagged */
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ /* Visable faces was tagged in createTransUVs. */
+ if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BLI_assert(BM_elem_flag_test(l, BM_ELEM_TAG) == 0);
+ }
+ }
+#endif
+
+ BLI_LINKSTACK_FREE(queue);
+ BLI_LINKSTACK_FREE(queue_next);
+
+ MEM_freeN(dists_prev);
+}
+
void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -103,12 +275,11 @@ void createTransUVs(bContext *C, TransInfo *t)
BMFace *efa;
BMIter iter, liter;
UvElementMap *elementmap = NULL;
- BLI_bitmap *island_enabled = NULL;
struct {
float co[2];
int co_num;
} *island_center = NULL;
- int count = 0, countsel = 0, count_rejected = 0;
+ int count = 0, countsel = 0;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
@@ -116,22 +287,15 @@ void createTransUVs(bContext *C, TransInfo *t)
}
/* count */
- if (is_prop_connected || is_island_center) {
+ if (is_island_center) {
/* create element map with island information */
const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- const bool use_uvsel = !is_prop_connected;
- elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, use_uvsel, false, true);
+ elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true);
if (elementmap == NULL) {
continue;
}
- if (is_prop_connected) {
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
- }
-
- if (is_island_center) {
- island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
- }
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
@@ -147,20 +311,14 @@ void createTransUVs(bContext *C, TransInfo *t)
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
countsel++;
- if (is_prop_connected || island_center) {
+ if (island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- if (is_prop_connected) {
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
-
- if (is_island_center) {
- if (element->flag == false) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(island_center[element->island].co, luv->uv);
- island_center[element->island].co_num++;
- element->flag = true;
- }
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
}
}
}
@@ -198,6 +356,14 @@ void createTransUVs(bContext *C, TransInfo *t)
td = tc->data;
td2d = tc->data_2d;
+ float *prop_dists = NULL;
+
+ if (is_prop_connected) {
+ prop_dists = MEM_callocN(em->bm->totloop * sizeof(float), "TransObPropDists(UV Editing)");
+
+ uv_set_connectivity_distance(em->bm, prop_dists, t->aspect);
+ }
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l;
@@ -209,52 +375,41 @@ void createTransUVs(bContext *C, TransInfo *t)
const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
MLoopUV *luv;
const float *center = NULL;
+ float prop_distance = FLT_MAX;
if (!is_prop_edit && !selected) {
continue;
}
- if (is_prop_connected || is_island_center) {
+ if (is_prop_connected) {
+ const int idx = BM_elem_index_get(l);
+ prop_distance = prop_dists[idx];
+ }
+
+ if (is_island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
if (element) {
- if (is_prop_connected) {
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
- }
- }
-
- if (is_island_center) {
- center = island_center[element->island].co;
- }
+ center = island_center[element->island].co;
}
}
- BM_elem_flag_enable(l, BM_ELEM_TAG);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, prop_distance, selected);
}
}
- if (is_prop_connected) {
- tc->data_len -= count_rejected;
- }
-
if (sima->flag & SI_LIVE_UNWRAP) {
ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
}
finally:
- if (is_prop_connected || is_island_center) {
+ if (is_prop_connected) {
+ MEM_freeN(prop_dists);
+ }
+ if (is_island_center) {
BM_uv_element_map_free(elementmap);
- if (is_prop_connected) {
- MEM_freeN(island_enabled);
- }
-
- if (island_center) {
- MEM_freeN(island_center);
- }
+ MEM_freeN(island_center);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index 3fa722d14cf..fbe9c07ebe9 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -183,7 +183,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t)
tail++;
}
if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
+ calc_distanceCurveVerts(head, tail - 1, false);
}
}
}
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index aee05197f10..cde06a9eaac 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -67,15 +67,27 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
dist = len_v3(t->num.val);
}
else {
+ int i = 0;
float dvec[3];
-
- copy_v3_v3(dvec, vec);
- applyAspectRatio(t, dvec);
+ if (!(t->flag & T_2D_EDIT) && t->con.mode & CON_APPLY) {
+ zero_v3(dvec);
+ if (t->con.mode & CON_AXIS0) {
+ dvec[i++] = vec[0];
+ }
+ if (t->con.mode & CON_AXIS1) {
+ dvec[i++] = vec[1];
+ }
+ if (t->con.mode & CON_AXIS2) {
+ dvec[i++] = vec[2];
+ }
+ }
+ else {
+ copy_v3_v3(dvec, vec);
+ applyAspectRatio(t, dvec);
+ }
dist = len_v3(vec);
if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
- int i;
-
for (i = 0; i < 3; i++) {
bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i],
NUM_STR_REP_LEN,
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index 9e810b9c629..4bcc4cc6383 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -500,6 +500,10 @@ static void doVertSlide(TransInfo *t, float perc)
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
VertSlideData *sld = tc->custom.mode.data;
+ if (sld == NULL) {
+ continue;
+ }
+
TransDataVertSlideVert *svlist = sld->sv, *sv;
int i;
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 3af176f5aef..6dbf80ed4b9 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1106,11 +1106,13 @@ static bool raycastObjects(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
/* read/write args */
- float *ray_depth,
+ /* Parameters below cannot be const, because they are assigned to a
+ * non-const variable (readability-non-const-parameter). */
+ float *ray_depth /* NOLINT */,
/* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index,
+ float r_loc[3] /* NOLINT */,
+ float r_no[3] /* NOLINT */,
+ int *r_index /* NOLINT */,
Object **r_ob,
float r_obmat[4][4],
ListBase *r_hit_list)
@@ -2789,11 +2791,13 @@ static short snapObjectsRay(SnapObjectContext *sctx,
SnapData *snapdata,
const struct SnapObjectParams *params,
/* read/write args */
- float *dist_px,
+ /* Parameters below cannot be const, because they are assigned to a
+ * non-const variable (readability-non-const-parameter). */
+ float *dist_px /* NOLINT */,
/* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index,
+ float r_loc[3] /* NOLINT */,
+ float r_no[3] /* NOLINT */,
+ int *r_index /* NOLINT */,
Object **r_ob,
float r_obmat[4][4])
{
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index b40b82c50fb..a39234561c2 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -40,6 +40,8 @@ set(SRC
uvedit_draw.c
uvedit_ops.c
uvedit_parametrizer.c
+ uvedit_path.c
+ uvedit_rip.c
uvedit_select.c
uvedit_smart_stitch.c
uvedit_unwrap_ops.c
@@ -49,6 +51,7 @@ set(SRC
)
set(LIB
+ bf_bmesh
)
if(WITH_INTERNATIONAL)
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index c6b8b0cd02d..9f716739b1c 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -413,7 +413,7 @@ static void draw_uvs(SpaceImage *sima,
UI_GetThemeColor3fv(TH_EDGE_SELECT, col2);
col2[3] = overlay_alpha;
- float dash_width = (sima->dt_uv & SI_UVDT_DASH) ? (4.0f * UI_DPI_FAC) : 9999.0f;
+ const float dash_width = (sima->dt_uv == SI_UVDT_DASH) ? (4.0f * UI_DPI_FAC) : 9999.0f;
eGPUBuiltinShader shader = (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH :
GPU_SHADER_2D_UV_EDGES;
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 31384d6df17..6a5f5162dff 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -106,8 +106,13 @@ void UV_OT_pack_islands(struct wmOperatorType *ot);
void UV_OT_reset(struct wmOperatorType *ot);
void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
+void UV_OT_rip(struct wmOperatorType *ot);
void UV_OT_stitch(struct wmOperatorType *ot);
+/* uvedit_path.c */
+void UV_OT_shortest_path_pick(struct wmOperatorType *ot);
+void UV_OT_shortest_path_select(struct wmOperatorType *ot);
+
/* uvedit_select.c */
bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 8d85de3b141..6003d4d5d95 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -2087,7 +2087,10 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_align);
+ WM_operatortype_append(UV_OT_rip);
WM_operatortype_append(UV_OT_stitch);
+ WM_operatortype_append(UV_OT_shortest_path_pick);
+ WM_operatortype_append(UV_OT_shortest_path_select);
WM_operatortype_append(UV_OT_seams_from_islands);
WM_operatortype_append(UV_OT_mark_seam);
@@ -2111,6 +2114,21 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_cursor_set);
}
+void ED_operatormacros_uvedit(void)
+{
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("UV_OT_rip_move",
+ "UV Rip Move",
+ "unstitch UV's and move the result",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "UV_OT_rip");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+}
+
void ED_keymap_uvedit(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 921b96f6023..a4ee9a294fe 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -487,7 +487,7 @@ static void p_chart_uv_scale_xy(PChart *chart, float x, float y)
}
}
-static void p_chart_uv_translate(PChart *chart, float trans[2])
+static void p_chart_uv_translate(PChart *chart, const float trans[2])
{
PVert *v;
@@ -805,7 +805,7 @@ static PVert *p_vert_copy(PChart *chart, PVert *v)
return nv;
}
-static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys)
+static PEdge *p_edge_lookup(PHandle *handle, const PHashKey *vkeys)
{
PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
@@ -1146,14 +1146,14 @@ static PFace *p_face_add(PHandle *handle)
static PFace *p_face_add_construct(PHandle *handle,
ParamKey key,
- ParamKey *vkeys,
+ const ParamKey *vkeys,
float *co[4],
float *uv[4],
int i1,
int i2,
int i3,
- ParamBool *pin,
- ParamBool *select)
+ const ParamBool *pin,
+ const ParamBool *select)
{
PFace *f = p_face_add(handle);
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
diff --git a/source/blender/editors/uvedit/uvedit_path.c b/source/blender/editors/uvedit/uvedit_path.c
new file mode 100644
index 00000000000..e9615b62523
--- /dev/null
+++ b/source/blender/editors/uvedit/uvedit_path.c
@@ -0,0 +1,771 @@
+/*
+ * 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 eduv
+ *
+ * \note The logic in this file closely follows editmesh_path.c
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_linklist.h"
+#include "DNA_windowmanager_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "BLI_ghash.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_math.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_uvedit.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
+
+#include "intern/bmesh_marking.h"
+#include "uvedit_intern.h"
+
+#include "bmesh_tools.h"
+
+/* TODO(campbell): region filling, matching mesh selection. */
+// #define USE_FILL
+
+/* -------------------------------------------------------------------- */
+/** \name Local Utilities
+ * \{ */
+
+/**
+ * Support edge-path using vert-path calculation code.
+ *
+ * Cheat! Pick 2 closest loops and do vertex path,
+ * in practices only obscure/contrived cases will make give noticeably worse behavior.
+ *
+ * While the code below is a bit awkward, it's significantly less overhead than
+ * adding full edge selection which is nearly the same as vertex path in the case of UV's.
+ */
+static void bm_loop_calc_vert_pair_from_edge_pair(const int cd_loop_uv_offset,
+ const float aspect_y,
+ BMElem **ele_src_p,
+ BMElem **ele_dst_p,
+ BMElem **r_ele_dst_final)
+{
+ BMLoop *l_src = (BMLoop *)*ele_src_p;
+ BMLoop *l_dst = (BMLoop *)*ele_dst_p;
+
+ const MLoopUV *luv_src_v1 = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
+ const MLoopUV *luv_src_v2 = BM_ELEM_CD_GET_VOID_P(l_src->next, cd_loop_uv_offset);
+ const MLoopUV *luv_dst_v1 = BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_uv_offset);
+ const MLoopUV *luv_dst_v2 = BM_ELEM_CD_GET_VOID_P(l_dst->next, cd_loop_uv_offset);
+
+ const float uv_src_v1[2] = {luv_src_v1->uv[0], luv_src_v1->uv[1] / aspect_y};
+ const float uv_src_v2[2] = {luv_src_v2->uv[0], luv_src_v2->uv[1] / aspect_y};
+ const float uv_dst_v1[2] = {luv_dst_v1->uv[0], luv_dst_v1->uv[1] / aspect_y};
+ const float uv_dst_v2[2] = {luv_dst_v2->uv[0], luv_dst_v2->uv[1] / aspect_y};
+
+ struct {
+ int src_index;
+ int dst_index;
+ float len_sq;
+ } tests[4] = {
+ {0, 0, len_squared_v2v2(uv_src_v1, uv_dst_v1)},
+ {0, 1, len_squared_v2v2(uv_src_v1, uv_dst_v2)},
+ {1, 0, len_squared_v2v2(uv_src_v2, uv_dst_v1)},
+ {1, 1, len_squared_v2v2(uv_src_v2, uv_dst_v2)},
+ };
+ int i_best = 0;
+ for (int i = 1; i < ARRAY_SIZE(tests); i++) {
+ if (tests[i].len_sq < tests[i_best].len_sq) {
+ i_best = i;
+ }
+ }
+
+ *ele_src_p = (BMElem *)(tests[i_best].src_index ? l_src->next : l_src);
+ *ele_dst_p = (BMElem *)(tests[i_best].dst_index ? l_dst->next : l_dst);
+
+ /* Ensure the edge is selected, not just the vertices up until we hit it. */
+ *r_ele_dst_final = (BMElem *)(tests[i_best].dst_index ? l_dst : l_dst->next);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Path Select Struct & Properties
+ * \{ */
+
+struct PathSelectParams {
+ /** ensure the active element is the last selected item (handy for picking) */
+ bool track_active;
+ bool use_topology_distance;
+ bool use_face_step;
+#ifdef USE_FILL
+ bool use_fill;
+#endif
+ struct CheckerIntervalParams interval_params;
+};
+
+struct UserData_UV {
+ Scene *scene;
+ uint cd_loop_uv_offset;
+};
+
+static void path_select_properties(wmOperatorType *ot)
+{
+ RNA_def_boolean(ot->srna,
+ "use_face_step",
+ false,
+ "Face Stepping",
+ "Traverse connected faces (includes diagonals and edge-rings)");
+ RNA_def_boolean(ot->srna,
+ "use_topology_distance",
+ false,
+ "Topology Distance",
+ "Find the minimum number of steps, ignoring spatial distance");
+#ifdef USE_FILL
+ RNA_def_boolean(ot->srna,
+ "use_fill",
+ false,
+ "Fill Region",
+ "Select all paths between the source/destination elements");
+#endif
+
+ WM_operator_properties_checker_interval(ot, true);
+}
+
+static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params)
+{
+ op_params->track_active = false;
+ op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
+#ifdef USE_FILL
+ op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
+#endif
+ op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
+ WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Vert Path
+ * \{ */
+
+/* callbacks */
+static bool looptag_filter_cb(BMLoop *l, void *user_data_v)
+{
+ struct UserData_UV *user_data = user_data_v;
+ return uvedit_face_visible_test(user_data->scene, l->f);
+}
+static bool looptag_test_cb(BMLoop *l, void *user_data_v)
+{
+ /* All connected loops are selected or we return false. */
+ struct UserData_UV *user_data = user_data_v;
+ const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BMIter iter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &iter, l->v, BM_LOOPS_OF_VERT) {
+ if (looptag_filter_cb(l_iter, user_data)) {
+ const MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ if (equals_v2v2(luv->uv, luv_iter->uv)) {
+ if ((luv_iter->flag & MLOOPUV_VERTSEL) == 0) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+static void looptag_set_cb(BMLoop *l, bool val, void *user_data_v)
+{
+ struct UserData_UV *user_data = user_data_v;
+ const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BMIter iter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &iter, l->v, BM_LOOPS_OF_VERT) {
+ if (looptag_filter_cb(l_iter, user_data)) {
+ MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ if (equals_v2v2(luv->uv, luv_iter->uv)) {
+ SET_FLAG_FROM_TEST(luv_iter->flag, val, MLOOPUV_VERTSEL);
+ }
+ }
+ }
+}
+
+static void mouse_mesh_uv_shortest_path_vert(Scene *scene,
+ Object *obedit,
+ const struct PathSelectParams *op_params,
+ BMLoop *l_src,
+ BMLoop *l_dst,
+ BMLoop *l_dst_add_to_path,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ const bool use_fake_edge_select = (ts->uv_selectmode & UV_SELECT_EDGE);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ struct UserData_UV user_data = {
+ .scene = scene,
+ .cd_loop_uv_offset = cd_loop_uv_offset,
+ };
+
+ const struct BMCalcPathUVParams params = {
+ .use_topology_distance = op_params->use_topology_distance,
+ .use_step_face = op_params->use_face_step,
+ .aspect_y = aspect_y,
+ .cd_loop_uv_offset = cd_loop_uv_offset,
+ };
+ LinkNode *path = BM_mesh_calc_path_uv_vert(
+ bm, l_src, l_dst, &params, looptag_filter_cb, &user_data);
+ /* TODO: false when we support region selection. */
+ bool is_path_ordered = true;
+
+ BMLoop *l_dst_last = l_dst;
+
+ if (path) {
+ if ((l_dst_add_to_path != NULL) && (BLI_linklist_index(path, l_dst_add_to_path) == -1)) {
+ /* Append, this isn't optimal compared to #BLI_linklist_append, it's a one-off lookup. */
+ LinkNode *path_last = BLI_linklist_find_last(path);
+ BLI_linklist_insert_after(&path_last, l_dst_add_to_path);
+ BLI_assert(BLI_linklist_find_last(path)->link == l_dst_add_to_path);
+ }
+
+ /* toggle the flag */
+ bool all_set = true;
+ LinkNode *node = path;
+ do {
+ if (!looptag_test_cb((BMLoop *)node->link, &user_data)) {
+ all_set = false;
+ break;
+ }
+ } while ((node = node->next));
+
+ int depth = -1;
+ node = path;
+ do {
+ if ((is_path_ordered == false) ||
+ WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
+ looptag_set_cb((BMLoop *)node->link, !all_set, &user_data);
+ if (is_path_ordered) {
+ l_dst_last = node->link;
+ }
+ }
+ } while ((void)depth++, (node = node->next));
+
+ BLI_linklist_free(path, NULL);
+ }
+ else {
+ const bool is_act = !looptag_test_cb(l_dst, &user_data);
+ looptag_set_cb(l_dst, is_act, &user_data); /* switch the face option */
+ }
+
+ if (op_params->track_active) {
+ /* Fake edge selection. */
+ if (use_fake_edge_select) {
+ ED_uvedit_active_edge_loop_set(bm, l_dst_last);
+ }
+ else {
+ ED_uvedit_active_vert_loop_set(bm, l_dst_last);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Face Path
+ * \{ */
+
+/* callbacks */
+static bool facetag_filter_cb(BMFace *f, void *user_data_v)
+{
+ struct UserData_UV *user_data = user_data_v;
+ return uvedit_face_visible_test(user_data->scene, f);
+}
+static bool facetag_test_cb(BMFace *f, void *user_data_v)
+{
+ /* All connected loops are selected or we return false. */
+ struct UserData_UV *user_data = user_data_v;
+ const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ BMIter iter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) {
+ const MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ if ((luv_iter->flag & MLOOPUV_VERTSEL) == 0) {
+ return false;
+ }
+ }
+ return true;
+}
+static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
+{
+ struct UserData_UV *user_data = user_data_v;
+ const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ BMIter iter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv_iter->flag, val, MLOOPUV_VERTSEL);
+ }
+}
+
+static void mouse_mesh_uv_shortest_path_face(Scene *scene,
+ Object *obedit,
+ const struct PathSelectParams *op_params,
+ BMFace *f_src,
+ BMFace *f_dst,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ struct UserData_UV user_data = {
+ .scene = scene,
+ .cd_loop_uv_offset = cd_loop_uv_offset,
+ };
+
+ const struct BMCalcPathUVParams params = {
+ .use_topology_distance = op_params->use_topology_distance,
+ .use_step_face = op_params->use_face_step,
+ .aspect_y = aspect_y,
+ .cd_loop_uv_offset = cd_loop_uv_offset,
+ };
+ LinkNode *path = BM_mesh_calc_path_uv_face(
+ bm, f_src, f_dst, &params, facetag_filter_cb, &user_data);
+ /* TODO: false when we support region selection. */
+ bool is_path_ordered = true;
+
+ BMFace *f_dst_last = f_dst;
+
+ if (path) {
+ /* toggle the flag */
+ bool all_set = true;
+ LinkNode *node = path;
+ do {
+ if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
+ all_set = false;
+ break;
+ }
+ } while ((node = node->next));
+
+ int depth = -1;
+ node = path;
+ do {
+ if ((is_path_ordered == false) ||
+ WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
+ facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
+ if (is_path_ordered) {
+ f_dst_last = node->link;
+ }
+ }
+ } while ((void)depth++, (node = node->next));
+
+ BLI_linklist_free(path, NULL);
+ }
+ else {
+ const bool is_act = !facetag_test_cb(f_dst, &user_data);
+ facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
+ }
+
+ if (op_params->track_active) {
+ /* Unlike other types, we can track active without it being selected. */
+ BM_mesh_active_face_set(bm, f_dst_last);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Operator for vert/edge/face tag
+ * \{ */
+
+static int uv_shortest_path_pick_exec(bContext *C, wmOperator *op);
+
+static bool uv_shortest_path_pick_ex(Scene *scene,
+ Depsgraph *depsgraph,
+ Object *obedit,
+ const struct PathSelectParams *op_params,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ bool ok = false;
+
+ if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
+ /* pass */
+ }
+ else if (ele_src->head.htype == BM_FACE) {
+ mouse_mesh_uv_shortest_path_face(scene,
+ obedit,
+ op_params,
+ (BMFace *)ele_src,
+ (BMFace *)ele_dst,
+ aspect_y,
+ cd_loop_uv_offset);
+ ok = true;
+ }
+ else if (ele_src->head.htype == BM_LOOP) {
+ const ToolSettings *ts = scene->toolsettings;
+ BMElem *ele_dst_final = NULL;
+ if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ bm_loop_calc_vert_pair_from_edge_pair(
+ cd_loop_uv_offset, aspect_y, &ele_src, &ele_dst, &ele_dst_final);
+ }
+ mouse_mesh_uv_shortest_path_vert(scene,
+ obedit,
+ op_params,
+ (BMLoop *)ele_src,
+ (BMLoop *)ele_dst,
+ (BMLoop *)ele_dst_final,
+ aspect_y,
+ cd_loop_uv_offset);
+ ok = true;
+ }
+
+ if (ok) {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ /* Only for region redraw. */
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ return ok;
+}
+
+static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+
+ /* We could support this, it needs further testing. */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BKE_report(op->reports, RPT_ERROR, "Sync selection doesn't support path select");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (RNA_struct_property_is_set(op->ptr, "index")) {
+ return uv_shortest_path_pick_exec(C, op);
+ }
+
+ struct PathSelectParams op_params;
+ path_select_params_from_op(op, &op_params);
+
+ /* Set false if we support edge tagging. */
+ op_params.track_active = true;
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+
+ float co[2];
+
+ const ARegion *region = CTX_wm_region(C);
+
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float aspect_y;
+ {
+ float aspx, aspy;
+ ED_uvedit_get_aspect(obedit, &aspx, &aspy);
+ aspect_y = aspx / aspy;
+ }
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+
+ BMElem *ele_src = NULL, *ele_dst = NULL;
+
+ if (ts->uv_selectmode & UV_SELECT_FACE) {
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ if (!uv_find_nearest_face(scene, obedit, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMFace *f_src = BM_mesh_active_face_get(bm, false, false);
+ /* Check selection? */
+
+ ele_src = (BMElem *)f_src;
+ ele_dst = (BMElem *)hit.efa;
+ }
+ else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ if (!uv_find_nearest_edge(scene, obedit, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMLoop *l_src = ED_uvedit_active_edge_loop_get(bm);
+ const MLoopUV *luv_src_v1 = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
+ const MLoopUV *luv_src_v2 = BM_ELEM_CD_GET_VOID_P(l_src->next, cd_loop_uv_offset);
+ if ((luv_src_v1->flag & MLOOPUV_VERTSEL) == 0 && (luv_src_v2->flag & MLOOPUV_VERTSEL) == 0) {
+ l_src = NULL;
+ }
+
+ ele_src = (BMElem *)l_src;
+ ele_dst = (BMElem *)hit.l;
+ }
+ else {
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ if (!uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMLoop *l_src = ED_uvedit_active_vert_loop_get(bm);
+ const MLoopUV *luv_src = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
+ if ((luv_src->flag & MLOOPUV_VERTSEL) == 0) {
+ l_src = NULL;
+ }
+
+ ele_src = (BMElem *)l_src;
+ ele_dst = (BMElem *)hit.l;
+ }
+
+ if (ele_src == NULL || ele_dst == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ uv_shortest_path_pick_ex(
+ scene, depsgraph, obedit, &op_params, ele_src, ele_dst, aspect_y, cd_loop_uv_offset);
+
+ /* To support redo. */
+ int index;
+ if (ts->uv_selectmode & UV_SELECT_FACE) {
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ index = BM_elem_index_get(ele_dst);
+ }
+ else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+ index = BM_elem_index_get(ele_dst);
+ }
+ else {
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+ index = BM_elem_index_get(ele_dst);
+ }
+ RNA_int_set(op->ptr, "index", index);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_shortest_path_pick_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float aspect_y;
+ {
+ float aspx, aspy;
+ ED_uvedit_get_aspect(obedit, &aspx, &aspy);
+ aspect_y = aspx / aspy;
+ }
+
+ const int index = RNA_int_get(op->ptr, "index");
+
+ BMElem *ele_src, *ele_dst;
+
+ if (ts->uv_selectmode & UV_SELECT_FACE) {
+ if (index < 0 || index >= bm->totface) {
+ return OPERATOR_CANCELLED;
+ }
+ if (!(ele_src = (BMElem *)BM_mesh_active_face_get(bm, false, false)) ||
+ !(ele_dst = (BMElem *)BM_face_at_index_find_or_table(bm, index))) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ if (index < 0 || index >= bm->totloop) {
+ return OPERATOR_CANCELLED;
+ }
+ if (!(ele_src = (BMElem *)ED_uvedit_active_edge_loop_get(bm)) ||
+ !(ele_dst = (BMElem *)BM_loop_at_index_find(bm, index))) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ if (index < 0 || index >= bm->totloop) {
+ return OPERATOR_CANCELLED;
+ }
+ if (!(ele_src = (BMElem *)ED_uvedit_active_vert_loop_get(bm)) ||
+ !(ele_dst = (BMElem *)BM_loop_at_index_find(bm, index))) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ struct PathSelectParams op_params;
+ path_select_params_from_op(op, &op_params);
+ op_params.track_active = true;
+
+ if (!uv_shortest_path_pick_ex(
+ scene, depsgraph, obedit, &op_params, ele_src, ele_dst, aspect_y, cd_loop_uv_offset)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_shortest_path_pick(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Pick Shortest Path";
+ ot->idname = "UV_OT_shortest_path_pick";
+ ot->description = "Select shortest path between two selections";
+
+ /* api callbacks */
+ ot->invoke = uv_shortest_path_pick_invoke;
+ ot->exec = uv_shortest_path_pick_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ path_select_properties(ot);
+
+ /* use for redo */
+ prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Path Between Existing Selection
+ * \{ */
+
+static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ bool found_valid_elements = false;
+
+ float aspect_y;
+ {
+ Object *obedit = CTX_data_edit_object(C);
+ float aspx, aspy;
+ ED_uvedit_get_aspect(obedit, &aspx, &aspy);
+ aspect_y = aspx / aspy;
+ }
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ BMElem *ele_src = NULL, *ele_dst = NULL;
+
+ /* Find 2x elements. */
+ {
+ BMElem **ele_array = NULL;
+ int ele_array_len = 0;
+ if (ts->uv_selectmode & UV_SELECT_FACE) {
+ ele_array = (BMElem **)ED_uvedit_selected_faces(scene, bm, 3, &ele_array_len);
+ }
+ else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ ele_array = (BMElem **)ED_uvedit_selected_edges(scene, bm, 3, &ele_array_len);
+ }
+ else {
+ ele_array = (BMElem **)ED_uvedit_selected_verts(scene, bm, 3, &ele_array_len);
+ }
+
+ if (ele_array_len == 2) {
+ ele_src = ele_array[0];
+ ele_dst = ele_array[1];
+ }
+ MEM_freeN(ele_array);
+ }
+
+ if (ele_src && ele_dst) {
+ struct PathSelectParams op_params;
+ path_select_params_from_op(op, &op_params);
+
+ uv_shortest_path_pick_ex(
+ scene, depsgraph, obedit, &op_params, ele_src, ele_dst, aspect_y, cd_loop_uv_offset);
+
+ found_valid_elements = true;
+ }
+ }
+ MEM_freeN(objects);
+
+ if (!found_valid_elements) {
+ BKE_report(
+ op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_shortest_path_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Shortest Path";
+ ot->idname = "UV_OT_shortest_path_select";
+ ot->description = "Selected shortest path between two vertices/edges/faces";
+
+ /* api callbacks */
+ ot->exec = uv_shortest_path_select_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ path_select_properties(ot);
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c
new file mode 100644
index 00000000000..562f0ce84c1
--- /dev/null
+++ b/source/blender/editors/uvedit/uvedit_rip.c
@@ -0,0 +1,981 @@
+/*
+ * 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 eduv
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_ghash.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_math.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_uvedit.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
+
+#include "uvedit_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name UV Loop Rip Data Struct
+ * \{ */
+
+/** Unordered loop data, stored in #BMLoop.head.index. */
+typedef struct ULData {
+ /** When this UV is selected as well as the next UV. */
+ uint is_select_edge : 1;
+ /**
+ * When only this UV is selected and none of the other UV's
+ * around the connected fan are attached to an edge.
+ *
+ * In this case there is no need to detect contiguous loops,
+ * each isolated case is handled on it's own, no need to walk over selected edges.
+ *
+ * \note This flag isn't flushed to other loops which could also have this enabled.
+ * Currently it's not necessary since we can start off on any one of these loops,
+ * then walk onto the other loops around the uv-fan, without having the flag to be
+ * set on all loops.
+ */
+ uint is_select_vert_single : 1;
+ /** This could be a face-tag. */
+ uint is_select_all : 1;
+ /** Use when building the rip-pairs stack. */
+ uint in_stack : 1;
+ /** Set once this has been added into a #UVRipPairs. */
+ uint in_rip_pairs : 1;
+ /** The side this loop is part of. */
+ uint side : 1;
+ /**
+ * Paranoid check to ensure we don't enter eternal loop swapping sides,
+ * this could happen with float precision error, making a swap to measure as slightly better
+ * depending on the order of addition.
+ */
+ uint side_was_swapped : 1;
+} ULData;
+
+/** Ensure this fits in an int (loop index). */
+BLI_STATIC_ASSERT(sizeof(ULData) <= sizeof(int), "");
+
+BLI_INLINE ULData *UL(BMLoop *l)
+{
+ return (ULData *)&l->head.index;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Utilities
+ * \{ */
+
+static BMLoop *bm_loop_find_other_radial_loop_with_visible_face(BMLoop *l_src,
+ const int cd_loop_uv_offset)
+{
+ BMLoop *l_other = NULL;
+ BMLoop *l_iter = l_src->radial_next;
+ if (l_iter != l_src) {
+ do {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) && UL(l_iter)->is_select_edge &&
+ BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) {
+ /* Check UV's are contiguous. */
+ if (l_other == NULL) {
+ l_other = l_iter;
+ }
+ else {
+ /* Only use when there is a single alternative. */
+ l_other = NULL;
+ break;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_src);
+ }
+ return l_other;
+}
+
+static BMLoop *bm_loop_find_other_fan_loop_with_visible_face(BMLoop *l_src,
+ BMVert *v_src,
+ const int cd_loop_uv_offset)
+{
+ BLI_assert(BM_vert_in_edge(l_src->e, v_src));
+ BMLoop *l_other = NULL;
+ BMLoop *l_iter = l_src->radial_next;
+ if (l_iter != l_src) {
+ do {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) &&
+ BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) {
+ /* Check UV's are contiguous. */
+ if (l_other == NULL) {
+ l_other = l_iter;
+ }
+ else {
+ /* Only use when there is a single alternative. */
+ l_other = NULL;
+ break;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_src);
+ }
+ if (l_other != NULL) {
+ if (l_other->v == v_src) {
+ /* do nothing. */
+ }
+ else if (l_other->next->v == v_src) {
+ l_other = l_other->next;
+ }
+ else if (l_other->prev->v == v_src) {
+ l_other = l_other->prev;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ return l_other;
+}
+
+/**
+ * A version of #BM_vert_step_fan_loop that checks UV's.
+ */
+static BMLoop *bm_vert_step_fan_loop_uv(BMLoop *l, BMEdge **e_step, const int cd_loop_uv_offset)
+{
+ BMEdge *e_prev = *e_step;
+ BMLoop *l_next;
+ if (l->e == e_prev) {
+ l_next = l->prev;
+ }
+ else if (l->prev->e == e_prev) {
+ l_next = l;
+ }
+ else {
+ BLI_assert(0);
+ return NULL;
+ }
+
+ *e_step = l_next->e;
+
+ return bm_loop_find_other_fan_loop_with_visible_face(l_next, l->v, cd_loop_uv_offset);
+}
+
+static void bm_loop_uv_select_single_vert_validate(BMLoop *l_init, const int cd_loop_uv_offset)
+{
+ const MLoopUV *luv_init = BM_ELEM_CD_GET_VOID_P(l_init, cd_loop_uv_offset);
+ BMIter liter;
+ BMLoop *l;
+ bool is_single_vert = true;
+ BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (equals_v2v2(luv_init->uv, luv->uv)) {
+ if (UL(l->prev)->is_select_edge || UL(l)->is_select_edge) {
+ is_single_vert = false;
+ break;
+ }
+ }
+ }
+ if (is_single_vert == false) {
+ BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
+ if (UL(l)->is_select_vert_single) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (equals_v2v2(luv_init->uv, luv->uv)) {
+ UL(l)->is_select_vert_single = false;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * The corner return values calculate the angle between both loops,
+ * the edge values pick the closest to the either edge (ignoring the center).
+ *
+ * \param dir: Direction to calculate the angle to (normalized and aspect corrected).
+ */
+static void bm_loop_calc_uv_angle_from_dir(BMLoop *l,
+ const float dir[2],
+ const float aspect_y,
+ const int cd_loop_uv_offset,
+ float *r_corner_angle,
+ float *r_edge_angle,
+ int *r_edge_index)
+{
+ /* Calculate 3 directions, return the shortest angle. */
+ float dir_test[3][2];
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ sub_v2_v2v2(dir_test[0], luv->uv, luv_prev->uv);
+ sub_v2_v2v2(dir_test[2], luv->uv, luv_next->uv);
+ dir_test[0][1] /= aspect_y;
+ dir_test[2][1] /= aspect_y;
+
+ normalize_v2(dir_test[0]);
+ normalize_v2(dir_test[2]);
+
+ /* Calculate the orthogonal line (same as negating one, then adding). */
+ sub_v2_v2v2(dir_test[1], dir_test[0], dir_test[2]);
+ normalize_v2(dir_test[1]);
+
+ /* Rotate 90 degrees. */
+ SWAP(float, dir_test[1][0], dir_test[1][1]);
+ dir_test[1][1] *= -1.0f;
+
+ if (BM_face_uv_calc_cross(l->f, cd_loop_uv_offset) > 0.0f) {
+ negate_v2(dir_test[1]);
+ }
+
+ const float angles[3] = {
+ angle_v2v2(dir, dir_test[0]),
+ angle_v2v2(dir, dir_test[1]),
+ angle_v2v2(dir, dir_test[2]),
+ };
+
+ /* Set the corner values. */
+ *r_corner_angle = angles[1];
+
+ /* Set the edge values. */
+ if (angles[0] < angles[2]) {
+ *r_edge_angle = angles[0];
+ *r_edge_index = -1;
+ }
+ else {
+ *r_edge_angle = angles[2];
+ *r_edge_index = 1;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Rip Single
+ * \{ */
+
+typedef struct UVRipSingle {
+ /** Walk around the selected UV point, store #BMLoop. */
+ GSet *loops;
+} UVRipSingle;
+
+/**
+ * Handle single loop, the following cases:
+ *
+ * - An isolated fan, without a shared UV edge to other fans which share the same coordinate,
+ * in this case we just need to pick the closest fan to \a co.
+ *
+ * - In the case of contiguous loops (part of the same fan).
+ * Rip away the loops connected to the closest edge.
+ *
+ * - In the case of 2 contiguous loops.
+ * Rip the closest loop away.
+ *
+ * \note This matches the behavior of edit-mesh rip tool.
+ */
+static UVRipSingle *uv_rip_single_from_loop(BMLoop *l_init_orig,
+ const float co[2],
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ UVRipSingle *rip = MEM_callocN(sizeof(*rip), __func__);
+ const float *co_center =
+ (((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_init_orig, cd_loop_uv_offset))->uv);
+ rip->loops = BLI_gset_ptr_new(__func__);
+
+ /* Track the closest loop, start walking from this so in the event we have multiple
+ * disconnected fans, we can rip away loops connected to this one. */
+ BMLoop *l_init = NULL;
+ BMLoop *l_init_edge = NULL;
+ float corner_angle_best = FLT_MAX;
+ float edge_angle_best = FLT_MAX;
+ int edge_index_best = 0; /* -1 or +1 (never center). */
+
+ /* Calculate the direction from the cursor with aspect correction. */
+ float dir_co[2];
+ sub_v2_v2v2(dir_co, co_center, co);
+ dir_co[1] /= aspect_y;
+ if (UNLIKELY(normalize_v2(dir_co) == 0.0)) {
+ dir_co[1] = 1.0f;
+ }
+
+ int uv_fan_count_all = 0;
+ {
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, l_init_orig->v, BM_LOOPS_OF_VERT) {
+ if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (equals_v2v2(co_center, luv->uv)) {
+ uv_fan_count_all += 1;
+ /* Clear at the same time. */
+ UL(l)->is_select_vert_single = true;
+ UL(l)->side = 0;
+ BLI_gset_add(rip->loops, l);
+
+ /* Update `l_init_close` */
+ float corner_angle_test;
+ float edge_angle_test;
+ int edge_index_test;
+ bm_loop_calc_uv_angle_from_dir(l,
+ dir_co,
+ aspect_y,
+ cd_loop_uv_offset,
+ &corner_angle_test,
+ &edge_angle_test,
+ &edge_index_test);
+ if ((corner_angle_best == FLT_MAX) || (corner_angle_test < corner_angle_best)) {
+ corner_angle_best = corner_angle_test;
+ l_init = l;
+ }
+
+ /* Trick so we don't consider concave corners further away than they should be. */
+ edge_angle_test = min_ff(corner_angle_test, edge_angle_test);
+
+ if ((edge_angle_best == FLT_MAX) || (edge_angle_test < edge_angle_best)) {
+ edge_angle_best = edge_angle_test;
+ edge_index_best = edge_index_test;
+ l_init_edge = l;
+ }
+ }
+ }
+ }
+ }
+
+ /* Walk around the `l_init` in both directions of the UV fan. */
+ int uv_fan_count_contiguous = 1;
+ UL(l_init)->side = 1;
+ for (int i = 0; i < 2; i += 1) {
+ BMEdge *e_prev = i ? l_init->e : l_init->prev->e;
+ BMLoop *l_iter = l_init;
+ while (((l_iter = bm_vert_step_fan_loop_uv(l_iter, &e_prev, cd_loop_uv_offset)) != l_init) &&
+ (l_iter != NULL) && (UL(l_iter)->side == 0)) {
+ uv_fan_count_contiguous += 1;
+ /* Keep. */
+ UL(l_iter)->side = 1;
+ }
+ /* May be useful to know if the fan is closed, currently it's not needed. */
+#if 0
+ if (l_iter == l_init) {
+ is_closed = true;
+ }
+#endif
+ }
+
+ if (uv_fan_count_contiguous != uv_fan_count_all) {
+ /* Simply rip off the current fan, all tagging is done. */
+ }
+ else {
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, rip->loops) {
+ BMLoop *l = BLI_gsetIterator_getKey(&gs_iter);
+ UL(l)->side = 0;
+ }
+
+ if (uv_fan_count_contiguous <= 2) {
+ /* Simple case, rip away the closest loop. */
+ UL(l_init)->side = 1;
+ }
+ else {
+ /* Rip away from the closest edge. */
+ BMLoop *l_radial_init = (edge_index_best == -1) ? l_init_edge->prev : l_init_edge;
+ BMLoop *l_radial_iter = l_radial_init;
+ do {
+ if (BM_loop_uv_share_edge_check(l_radial_init, l_radial_iter, cd_loop_uv_offset)) {
+ BMLoop *l = (l_radial_iter->v == l_init->v) ? l_radial_iter : l_radial_iter->next;
+ BLI_assert(l->v == l_init->v);
+ /* Keep. */
+ UL(l)->side = 1;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_init);
+ }
+ }
+
+ return rip;
+}
+
+static void uv_rip_single_free(UVRipSingle *rip)
+{
+ BLI_gset_free(rip->loops, NULL);
+ MEM_freeN(rip);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Rip Loop Pairs
+ * \{ */
+
+typedef struct UVRipPairs {
+ /** Walk along the UV selection, store #BMLoop. */
+ GSet *loops;
+} UVRipPairs;
+
+static void uv_rip_pairs_add(UVRipPairs *rip, BMLoop *l)
+{
+ ULData *ul = UL(l);
+ BLI_assert(!BLI_gset_haskey(rip->loops, l));
+ BLI_assert(ul->in_rip_pairs == false);
+ ul->in_rip_pairs = true;
+ BLI_gset_add(rip->loops, l);
+}
+
+static void uv_rip_pairs_remove(UVRipPairs *rip, BMLoop *l)
+{
+ ULData *ul = UL(l);
+ BLI_assert(BLI_gset_haskey(rip->loops, l));
+ BLI_assert(ul->in_rip_pairs == true);
+ ul->in_rip_pairs = false;
+ BLI_gset_remove(rip->loops, l, NULL);
+}
+
+/**
+ * \note While this isn't especially efficient,
+ * this is only needed for rip-pairs end-points (only two per contiguous selection loop).
+ */
+static float uv_rip_pairs_calc_uv_angle(BMLoop *l_init,
+ uint side,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ const MLoopUV *luv_init = BM_ELEM_CD_GET_VOID_P(l_init, cd_loop_uv_offset);
+ float angle_of_side = 0.0f;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
+ if (UL(l)->in_rip_pairs) {
+ if (UL(l)->side == side) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (equals_v2v2(luv_init->uv, luv->uv)) {
+ const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float dir_prev[2], dir_next[2];
+ sub_v2_v2v2(dir_prev, luv_prev->uv, luv->uv);
+ sub_v2_v2v2(dir_next, luv_next->uv, luv->uv);
+ dir_prev[1] /= aspect_y;
+ dir_next[1] /= aspect_y;
+ const float luv_angle = angle_v2v2(dir_prev, dir_next);
+ if (LIKELY(isfinite(luv_angle))) {
+ angle_of_side += luv_angle;
+ }
+ }
+ }
+ }
+ }
+ return angle_of_side;
+}
+
+static int uv_rip_pairs_loop_count_on_side(BMLoop *l_init, uint side, const int cd_loop_uv_offset)
+{
+ const MLoopUV *luv_init = BM_ELEM_CD_GET_VOID_P(l_init, cd_loop_uv_offset);
+ int count = 0;
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, l_init->v, BM_LOOPS_OF_VERT) {
+ if (UL(l)->in_rip_pairs) {
+ if (UL(l)->side == side) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (equals_v2v2(luv_init->uv, luv->uv)) {
+ count += 1;
+ }
+ }
+ }
+ }
+ return count;
+}
+
+static bool uv_rip_pairs_loop_change_sides_test(BMLoop *l_switch,
+ BMLoop *l_target,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ const int side_a = UL(l_switch)->side;
+ const int side_b = UL(l_target)->side;
+
+ BLI_assert(UL(l_switch)->side != UL(l_target)->side);
+
+ /* First, check if this is a simple grid topology,
+ * in that case always choose the adjacent edge. */
+ const int count_a = uv_rip_pairs_loop_count_on_side(l_switch, side_a, cd_loop_uv_offset);
+ const int count_b = uv_rip_pairs_loop_count_on_side(l_target, side_b, cd_loop_uv_offset);
+ if (count_a + count_b == 4) {
+ return count_a > count_b;
+ }
+ else {
+ const float angle_a_before = uv_rip_pairs_calc_uv_angle(
+ l_switch, side_a, aspect_y, cd_loop_uv_offset);
+ const float angle_b_before = uv_rip_pairs_calc_uv_angle(
+ l_target, side_b, aspect_y, cd_loop_uv_offset);
+
+ UL(l_switch)->side = side_b;
+
+ const float angle_a_after = uv_rip_pairs_calc_uv_angle(
+ l_switch, side_a, aspect_y, cd_loop_uv_offset);
+ const float angle_b_after = uv_rip_pairs_calc_uv_angle(
+ l_target, side_b, aspect_y, cd_loop_uv_offset);
+
+ UL(l_switch)->side = side_a;
+
+ return fabsf(angle_a_before - angle_b_before) > fabsf(angle_a_after - angle_b_after);
+ }
+}
+
+/**
+ * Create 2x sides of a UV rip-pairs, the result is unordered, supporting non-contiguous rails.
+ *
+ * \param l_init: A loop on a boundary which can be used to initialize flood-filling.
+ * This will always be added to the first side. Other loops will be added to the second side.
+ *
+ * \note We could have more than two sides, however in practice this almost never happens.
+ */
+static UVRipPairs *uv_rip_pairs_from_loop(BMLoop *l_init,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ UVRipPairs *rip = MEM_callocN(sizeof(*rip), __func__);
+ rip->loops = BLI_gset_ptr_new(__func__);
+
+ /* We can rely on this stack being small, as we're walking down two sides of an edge loop,
+ * so the stack wont be much larger than the total number of fans at any one vertex. */
+ BLI_SMALLSTACK_DECLARE(stack, BMLoop *);
+
+ /* Needed for cases when we walk onto loops which already have a side assigned,
+ * in this case we need to pick a better side (see #uv_rip_pairs_loop_change_sides_test)
+ * and put the loop back in the stack,
+ * which is needed in the case adjacent loops should also switch sides. */
+#define UV_SET_SIDE_AND_REMOVE_FROM_RAIL(loop, side_value) \
+ { \
+ BLI_assert(UL(loop)->side_was_swapped == false); \
+ BLI_assert(UL(loop)->side != side_value); \
+ if (!UL(loop)->in_stack) { \
+ BLI_SMALLSTACK_PUSH(stack, loop); \
+ UL(loop)->in_stack = true; \
+ } \
+ if (UL(loop)->in_rip_pairs) { \
+ uv_rip_pairs_remove(rip, loop); \
+ } \
+ UL(loop)->side = side_value; \
+ UL(loop)->side_was_swapped = true; \
+ }
+
+ /* Initialize the stack. */
+ BLI_SMALLSTACK_PUSH(stack, l_init);
+ UL(l_init)->in_stack = true;
+
+ BMLoop *l_step;
+ while ((l_step = BLI_SMALLSTACK_POP(stack))) {
+ int side = UL(l_step)->side;
+ UL(l_step)->in_stack = false;
+
+ /* Note that we could add all loops into the rip-pairs when adding into the stack,
+ * however this complicates removal, so add into the rip-pairs when popping from the stack. */
+ uv_rip_pairs_add(rip, l_step);
+
+ /* Add to the other side if it exists. */
+ if (UL(l_step)->is_select_edge) {
+ BMLoop *l_other = bm_loop_find_other_radial_loop_with_visible_face(l_step,
+ cd_loop_uv_offset);
+ if (l_other != NULL) {
+ if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
+ BLI_SMALLSTACK_PUSH(stack, l_other);
+ UL(l_other)->in_stack = true;
+ UL(l_other)->side = !side;
+ }
+ else {
+ if (UL(l_other)->side == side) {
+ if (UL(l_other)->side_was_swapped == false) {
+ UV_SET_SIDE_AND_REMOVE_FROM_RAIL(l_other, !side);
+ }
+ }
+ }
+ }
+
+ /* Add the next loop along the edge on the same side. */
+ l_other = l_step->next;
+ if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
+ BLI_SMALLSTACK_PUSH(stack, l_other);
+ UL(l_other)->in_stack = true;
+ UL(l_other)->side = side;
+ }
+ else {
+ if (UL(l_other)->side != side) {
+ if ((UL(l_other)->side_was_swapped == false) &&
+ uv_rip_pairs_loop_change_sides_test(l_other, l_step, aspect_y, cd_loop_uv_offset)) {
+ UV_SET_SIDE_AND_REMOVE_FROM_RAIL(l_other, side);
+ }
+ }
+ }
+ }
+
+ /* Walk over the fan of loops, starting from `l_step` in both directions. */
+ for (int i = 0; i < 2; i++) {
+ BMLoop *l_radial_first = i ? l_step : l_step->prev;
+ if (l_radial_first != l_radial_first->radial_next) {
+ BMEdge *e_radial = l_radial_first->e;
+ BMLoop *l_radial_iter = l_radial_first->radial_next;
+ do {
+ /* Not a boundary and visible. */
+ if (!UL(l_radial_iter)->is_select_edge &&
+ BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
+ BMLoop *l_other = (l_radial_iter->v == l_step->v) ? l_radial_iter :
+ l_radial_iter->next;
+ BLI_assert(l_other->v == l_step->v);
+ if (BM_edge_uv_share_vert_check(e_radial, l_other, l_step, cd_loop_uv_offset)) {
+ if (!UL(l_other)->in_rip_pairs && !UL(l_other)->in_stack) {
+ BLI_SMALLSTACK_PUSH(stack, l_other);
+ UL(l_other)->in_stack = true;
+ UL(l_other)->side = side;
+ }
+ else {
+ if (UL(l_other)->side != side) {
+ if ((UL(l_other)->side_was_swapped == false) &&
+ uv_rip_pairs_loop_change_sides_test(
+ l_other, l_step, aspect_y, cd_loop_uv_offset)) {
+ UV_SET_SIDE_AND_REMOVE_FROM_RAIL(l_other, side);
+ }
+ }
+ }
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ }
+ }
+
+#undef UV_SET_SIDE_AND_REMOVE_FROM_RAIL
+
+ return rip;
+}
+
+static void uv_rip_pairs_free(UVRipPairs *rip)
+{
+ BLI_gset_free(rip->loops, NULL);
+ MEM_freeN(rip);
+}
+
+/**
+ * This is an approximation, it's easily good enough for our purpose.
+ */
+static bool uv_rip_pairs_calc_center_and_direction(UVRipPairs *rip,
+ const int cd_loop_uv_offset,
+ float r_center[2],
+ float r_dir_side[2][2])
+{
+ zero_v2(r_center);
+ int center_total = 0;
+ int side_total[2] = {0, 0};
+
+ for (int i = 0; i < 2; i++) {
+ zero_v2(r_dir_side[i]);
+ }
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, rip->loops) {
+ BMLoop *l = BLI_gsetIterator_getKey(&gs_iter);
+ int side = UL(l)->side;
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(r_center, luv->uv);
+
+ float dir[2];
+ if (!UL(l)->is_select_edge) {
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ sub_v2_v2v2(dir, luv_next->uv, luv->uv);
+ add_v2_v2(r_dir_side[side], dir);
+ }
+ if (!UL(l->prev)->is_select_edge) {
+ const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
+ sub_v2_v2v2(dir, luv_prev->uv, luv->uv);
+ add_v2_v2(r_dir_side[side], dir);
+ }
+ side_total[side] += 1;
+ }
+ center_total += BLI_gset_len(rip->loops);
+
+ for (int i = 0; i < 2; i++) {
+ normalize_v2(r_dir_side[i]);
+ }
+ mul_v2_fl(r_center, 1.0f / center_total);
+
+ /* If only a single side is selected, don't handle this rip-pairs. */
+ return side_total[0] && side_total[1];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Rip Main Function
+ * \{ */
+
+/**
+ * \return true when a change was made.
+ */
+static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const float aspect_y)
+{
+ Mesh *me = (Mesh *)obedit->data;
+ BMEditMesh *em = me->edit_mesh;
+ BMesh *bm = em->bm;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BMFace *efa;
+ BMIter iter, liter;
+ BMLoop *l;
+
+ const ULData ul_clear = {0};
+
+ bool changed = false;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(efa, BM_ELEM_TAG, uvedit_face_visible_test(scene, efa));
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ ULData *ul = UL(l);
+ *ul = ul_clear;
+ }
+ }
+ bm->elem_index_dirty |= BM_LOOP;
+
+ bool is_select_all_any = false;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ bool is_all = true;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ if (luv_next->flag & MLOOPUV_VERTSEL) {
+ UL(l)->is_select_edge = true;
+ }
+ else {
+ if ((luv_prev->flag & MLOOPUV_VERTSEL) == 0) {
+ /* #bm_loop_uv_select_single_vert_validate validates below. */
+ UL(l)->is_select_vert_single = true;
+ }
+ }
+ }
+ else {
+ is_all = false;
+ }
+ }
+ if (is_all) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ UL(l)->is_select_all = true;
+ }
+ is_select_all_any = true;
+ }
+ }
+ }
+
+ /* Remove #ULData.is_select_vert_single when connected to selected edges. */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (UL(l)->is_select_vert_single) {
+ bm_loop_uv_select_single_vert_validate(l, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+
+ /* Special case: if we have selected faces, isolated them.
+ * This isn't a rip, however it's useful for users as a quick way
+ * to detach the selection.
+ *
+ * We could also extract an edge loop from the boundary
+ * however in practice it's not that useful, see T78751. */
+ if (is_select_all_any) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (!UL(l)->is_select_all) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
+ }
+
+ /* Extract loop pairs or single loops. */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (UL(l)->is_select_edge) {
+ if (!UL(l)->in_rip_pairs) {
+ UVRipPairs *rip = uv_rip_pairs_from_loop(l, aspect_y, cd_loop_uv_offset);
+ float center[2];
+ float dir_cursor[2];
+ float dir_side[2][2];
+ int side_from_cursor = -1;
+ if (uv_rip_pairs_calc_center_and_direction(rip, cd_loop_uv_offset, center, dir_side)) {
+ for (int i = 0; i < 2; i++) {
+ sub_v2_v2v2(dir_cursor, center, co);
+ normalize_v2(dir_cursor);
+ }
+ side_from_cursor = (dot_v2v2(dir_side[0], dir_cursor) -
+ dot_v2v2(dir_side[1], dir_cursor)) < 0.0f;
+ }
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, rip->loops) {
+ BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter);
+ ULData *ul = UL(l_iter);
+ if (ul->side == side_from_cursor) {
+ uvedit_uv_select_disable(em, scene, l_iter, cd_loop_uv_offset);
+ changed = true;
+ }
+ /* Ensure we don't operate on these again. */
+ *ul = ul_clear;
+ }
+ uv_rip_pairs_free(rip);
+ }
+ }
+ else if (UL(l)->is_select_vert_single) {
+ UVRipSingle *rip = uv_rip_single_from_loop(l, co, aspect_y, cd_loop_uv_offset);
+ /* We only ever use one side. */
+ const int side_from_cursor = 0;
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, rip->loops) {
+ BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter);
+ ULData *ul = UL(l_iter);
+ if (ul->side == side_from_cursor) {
+ uvedit_uv_select_disable(em, scene, l_iter, cd_loop_uv_offset);
+ changed = true;
+ }
+ /* Ensure we don't operate on these again. */
+ *ul = ul_clear;
+ }
+ uv_rip_single_free(rip);
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Rip Operator
+ * \{ */
+
+static int uv_rip_exec(bContext *C, wmOperator *op)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ bool changed_multi = false;
+
+ float co[2];
+ RNA_float_get_array(op->ptr, "location", co);
+
+ float aspx, aspy;
+ {
+ /* Note that we only want to run this on the */
+ Object *obedit = CTX_data_edit_object(C);
+ ED_uvedit_get_aspect(obedit, &aspx, &aspy);
+ }
+ const float aspect_y = aspx / aspy;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ if (uv_rip_object(scene, obedit, co, aspect_y)) {
+ changed_multi = true;
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ if (!changed_multi) {
+ BKE_report(op->reports, RPT_ERROR, "Rip failed");
+ return OPERATOR_CANCELLED;
+ }
+ return OPERATOR_FINISHED;
+}
+
+static int uv_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_rip_exec(C, op);
+}
+
+void UV_OT_rip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "UV Rip";
+ ot->description = "Rip selected vertices or a selected region";
+ ot->idname = "UV_OT_rip";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_rip_exec;
+ ot->invoke = uv_rip_invoke;
+ ot->poll = ED_operator_uvedit;
+
+ /* translation data */
+ Transform_Properties(ot, P_MIRROR_DUMMY);
+
+ /* properties */
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index b701e94cd77..ddb276a663a 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -88,6 +88,59 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
Object *obedit);
/* -------------------------------------------------------------------- */
+/** \name Active Selection Tracking
+ *
+ * Currently we don't store loops in the selection history,
+ * store face/edge/vert combinations (needed for UV path selection).
+ * \{ */
+
+void ED_uvedit_active_vert_loop_set(BMesh *bm, BMLoop *l)
+{
+ BM_select_history_clear(bm);
+ BM_select_history_remove(bm, (BMElem *)l->f);
+ BM_select_history_remove(bm, (BMElem *)l->v);
+ BM_select_history_store_notest(bm, (BMElem *)l->f);
+ BM_select_history_store_notest(bm, (BMElem *)l->v);
+}
+
+BMLoop *ED_uvedit_active_vert_loop_get(BMesh *bm)
+{
+ BMEditSelection *ese = bm->selected.last;
+ if (ese && ese->prev) {
+ BMEditSelection *ese_prev = ese->prev;
+ if ((ese->htype == BM_VERT) && (ese_prev->htype == BM_FACE)) {
+ /* May be NULL. */
+ return BM_face_vert_share_loop((BMFace *)ese_prev->ele, (BMVert *)ese->ele);
+ }
+ }
+ return NULL;
+}
+
+void ED_uvedit_active_edge_loop_set(BMesh *bm, BMLoop *l)
+{
+ BM_select_history_clear(bm);
+ BM_select_history_remove(bm, (BMElem *)l->f);
+ BM_select_history_remove(bm, (BMElem *)l->e);
+ BM_select_history_store_notest(bm, (BMElem *)l->f);
+ BM_select_history_store_notest(bm, (BMElem *)l->e);
+}
+
+BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm)
+{
+ BMEditSelection *ese = bm->selected.last;
+ if (ese && ese->prev) {
+ BMEditSelection *ese_prev = ese->prev;
+ if ((ese->htype == BM_EDGE) && (ese_prev->htype == BM_FACE)) {
+ /* May be NULL. */
+ return BM_face_edge_share_loop((BMFace *)ese_prev->ele, (BMEdge *)ese->ele);
+ }
+ }
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Visibility and Selection Utilities
* \{ */
@@ -1424,7 +1477,7 @@ void UV_OT_select_all(wmOperatorType *ot)
* \{ */
static bool uv_sticky_select(
- float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
+ const float *limit, const int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
{
int i;
@@ -1531,6 +1584,11 @@ static int uv_mouse_select_multi(bContext *C,
hituv[hit.lindex] = hit.luv->uv;
hitlen = hit.efa->len;
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
+ BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
+ ED_uvedit_active_vert_loop_set(bm, hit.l);
+ }
}
}
else if (selectmode == UV_SELECT_EDGE) {
@@ -1550,6 +1608,11 @@ static int uv_mouse_select_multi(bContext *C,
hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
hitlen = hit.efa->len;
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
+ BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
+ ED_uvedit_active_edge_loop_set(bm, hit.l);
+ }
}
}
else if (selectmode == UV_SELECT_FACE) {
@@ -2061,6 +2124,7 @@ void UV_OT_select_linked_pick(wmOperatorType *ot)
*/
static int uv_select_split_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const ToolSettings *ts = scene->toolsettings;
@@ -2127,6 +2191,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
if (changed) {
changed_multi = true;
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
}
MEM_freeN(objects);
@@ -3354,3 +3419,154 @@ void UV_OT_select_overlap(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
+ *
+ * These functions return single elements per connected vertex/edge.
+ * So an edge that has two connected edge loops only assigns one loop in the array.
+ * \{ */
+
+BMFace **ED_uvedit_selected_faces(Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
+{
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ CLAMP_MAX(len_max, bm->totface);
+ int faces_len = 0;
+ BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__);
+
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, f)) {
+ if (uvedit_face_select_test(scene, f, cd_loop_uv_offset)) {
+ faces[faces_len++] = f;
+ if (faces_len == len_max) {
+ goto finally;
+ }
+ }
+ }
+ }
+
+finally:
+ *r_faces_len = faces_len;
+ if (faces_len != len_max) {
+ faces = MEM_reallocN(faces, sizeof(*faces) * faces_len);
+ }
+ return faces;
+}
+
+BMLoop **ED_uvedit_selected_edges(Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
+{
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ CLAMP_MAX(len_max, bm->totloop);
+ int edges_len = 0;
+ BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__);
+
+ BMIter iter;
+ BMFace *f;
+
+ /* Clear tag. */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMIter liter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
+ }
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, f)) {
+ BMIter liter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
+ if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
+ const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset);
+ if ((luv_curr->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) {
+ BM_elem_flag_enable(l_iter, BM_ELEM_TAG);
+
+ edges[edges_len++] = l_iter;
+ if (edges_len == len_max) {
+ goto finally;
+ }
+
+ /* Tag other connected loops so we don't consider them separate edges. */
+ if (l_iter != l_iter->radial_next) {
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ do {
+ if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, cd_loop_uv_offset)) {
+ BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG);
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+ }
+ }
+ }
+ }
+ }
+ }
+
+finally:
+ *r_edges_len = edges_len;
+ if (edges_len != len_max) {
+ edges = MEM_reallocN(edges, sizeof(*edges) * edges_len);
+ }
+ return edges;
+}
+
+BMLoop **ED_uvedit_selected_verts(Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
+{
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ CLAMP_MAX(len_max, bm->totloop);
+ int verts_len = 0;
+ BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__);
+
+ BMIter iter;
+ BMFace *f;
+
+ /* Clear tag. */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMIter liter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
+ }
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, f)) {
+ BMIter liter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
+ if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ if ((luv->flag & MLOOPUV_VERTSEL)) {
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+
+ verts[verts_len++] = l_iter;
+ if (verts_len == len_max) {
+ goto finally;
+ }
+
+ /* Tag other connected loops so we don't consider them separate vertices. */
+ BMIter liter_disk;
+ BMLoop *l_disk_iter;
+ BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) {
+ if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, cd_loop_uv_offset)) {
+ BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+finally:
+ *r_verts_len = verts_len;
+ if (verts_len != len_max) {
+ verts = MEM_reallocN(verts, sizeof(*verts) * verts_len);
+ }
+ return verts;
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 38bd928e7b1..29e10f03e3c 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -534,7 +534,7 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge,
StitchStateContainer *ssc,
StitchState *state,
UVVertAverage *uv_average,
- uint *uvfinal_map,
+ const uint *uvfinal_map,
IslandStitchData *island_stitch_data)
{
BMesh *bm = state->em->bm;
@@ -1935,7 +1935,7 @@ static StitchState *stitch_init(bContext *C,
return NULL;
}
- ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(obedit, &aspx, &aspy);
state->aspect = aspx / aspy;
/* Count 'unique' uvs */
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index aff73308fb5..6fcfb0e0bfc 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -210,15 +210,16 @@ static bool uvedit_have_selection_multi(const Scene *scene,
return have_select;
}
-void ED_uvedit_get_aspect(
- const Scene *UNUSED(scene), Object *ob, BMesh *bm, float *r_aspx, float *r_aspy)
+void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
{
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BLI_assert(em != NULL);
bool sloppy = true;
bool selected = false;
BMFace *efa;
Image *ima;
- efa = BM_mesh_active_face_get(bm, sloppy, selected);
+ efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
if (efa) {
ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
@@ -285,7 +286,7 @@ static ParamHandle *construct_param_handle(const Scene *scene,
if (options->correct_aspect) {
float aspx, aspy;
- ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(ob, &aspx, &aspy);
if (aspx != aspy) {
param_aspect_ratio(handle, aspx, aspy);
@@ -354,11 +355,9 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
if (options->correct_aspect) {
Object *ob = objects[0];
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMesh *bm = em->bm;
float aspx, aspy;
- ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(ob, &aspx, &aspy);
if (aspx != aspy) {
param_aspect_ratio(handle, aspx, aspy);
}
@@ -500,7 +499,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
if (options->correct_aspect) {
float aspx, aspy;
- ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(ob, &aspx, &aspy);
if (aspx != aspy) {
param_aspect_ratio(handle, aspx, aspy);
@@ -1413,7 +1412,7 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
-static void correct_uv_aspect(const Scene *scene, Object *ob, BMEditMesh *em)
+static void correct_uv_aspect(Object *ob, BMEditMesh *em)
{
BMLoop *l;
BMIter iter, liter;
@@ -1423,7 +1422,7 @@ static void correct_uv_aspect(const Scene *scene, Object *ob, BMEditMesh *em)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(ob, &aspx, &aspy);
if (aspx == aspy) {
return;
@@ -1491,10 +1490,7 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
"Scale UV coordinates to bounds after unwrapping");
}
-static void uv_map_clip_correct_multi(const Scene *scene,
- Object **objects,
- uint objects_len,
- wmOperator *op)
+static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
{
BMFace *efa;
BMLoop *l;
@@ -1515,7 +1511,7 @@ static void uv_map_clip_correct_multi(const Scene *scene,
/* correct for image aspect ratio */
if (correct_aspect) {
- correct_uv_aspect(scene, ob, em);
+ correct_uv_aspect(ob, em);
}
if (scale_to_bounds) {
@@ -1580,9 +1576,9 @@ static void uv_map_clip_correct_multi(const Scene *scene,
}
}
-static void uv_map_clip_correct(const Scene *scene, Object *ob, wmOperator *op)
+static void uv_map_clip_correct(Object *ob, wmOperator *op)
{
- uv_map_clip_correct_multi(scene, &ob, 1, op);
+ uv_map_clip_correct_multi(&ob, 1, op);
}
/** \} */
@@ -1973,7 +1969,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if (changed_multi) {
- uv_map_clip_correct_multi(scene, objects, objects_len, op);
+ uv_map_clip_correct_multi(objects, objects_len, op);
}
MEM_freeN(objects);
@@ -2174,7 +2170,7 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
uv_map_mirror(em, efa);
}
- uv_map_clip_correct(scene, obedit, op);
+ uv_map_clip_correct(obedit, op);
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -2272,7 +2268,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
uv_map_mirror(em, efa);
}
- uv_map_clip_correct(scene, obedit, op);
+ uv_map_clip_correct(obedit, op);
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -2395,7 +2391,7 @@ static int cube_project_exec(bContext *C, wmOperator *op)
uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
- uv_map_clip_correct(scene, obedit, op);
+ uv_map_clip_correct(obedit, op);
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp
index b97843e045d..b26c9a58f70 100644
--- a/source/blender/freestyle/intern/application/AppConfig.cpp
+++ b/source/blender/freestyle/intern/application/AppConfig.cpp
@@ -48,15 +48,13 @@ void Path::setRootDir(const string &iRootDir)
{
_ProjectDir = iRootDir + string(DIR_SEP) + "freestyle";
_ModelsPath = "";
- _PatternsPath = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) +
- "textures" + string(DIR_SEP) + "variation_patterns" +
- string(DIR_SEP);
- _BrushesPath = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) +
- "textures" + string(DIR_SEP) + "brushes" + string(DIR_SEP);
- _EnvMapDir = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) +
- "env_map" + string(DIR_SEP);
- _MapsDir = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "maps" +
- string(DIR_SEP);
+ _PatternsPath = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "textures" +
+ string(DIR_SEP) + "variation_patterns" + string(DIR_SEP);
+ _BrushesPath = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "textures" +
+ string(DIR_SEP) + "brushes" + string(DIR_SEP);
+ _EnvMapDir = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "env_map" +
+ string(DIR_SEP);
+ _MapsDir = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "maps" + string(DIR_SEP);
}
void Path::setHomeDir(const string &iHomeDir)
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 0af57e5d728..e1763514e08 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -222,7 +222,7 @@ void BlenderFileLoader::clipTriangle(int numTris,
bool em1,
bool em2,
bool em3,
- int clip[3])
+ const int clip[3])
{
float *v[3], *n[3];
bool em[3];
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index ad6379d5f52..d9387b221f8 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -128,7 +128,7 @@ class BlenderFileLoader {
bool em1,
bool em2,
bool em3,
- int clip[3]);
+ const int clip[3]);
void addTriangle(struct LoaderState *ls,
float v1[3],
float v2[3],
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
index b5d954664e4..e5f029d28b7 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
@@ -65,7 +65,7 @@ void SceneHash::visitIndexedFaceSet(IndexedFaceSet &ifs)
static const int MOD_ADLER = 65521;
-void SceneHash::adler32(unsigned char *data, int size)
+void SceneHash::adler32(const unsigned char *data, int size)
{
uint32_t sum1 = _sum & 0xffff;
uint32_t sum2 = (_sum >> 16) & 0xffff;
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.h b/source/blender/freestyle/intern/scene_graph/SceneHash.h
index 53d1381da60..05c0880f806 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneHash.h
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.h
@@ -67,7 +67,7 @@ class SceneHash : public SceneVisitor {
}
private:
- void adler32(unsigned char *data, int size);
+ void adler32(const unsigned char *data, int size);
uint32_t _sum;
uint32_t _prevSum;
diff --git a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp
index 2df5ecd0867..cb3a297076a 100644
--- a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp
+++ b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp
@@ -94,7 +94,7 @@ static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
return GeomUtils::intersect2dSeg2dArea(min, max, A, B);
}
-static inline bool insideProscenium(real proscenium[4], const Vec3r &point)
+static inline bool insideProscenium(const real proscenium[4], const Vec3r &point)
{
return !(point[0] < proscenium[0] || point[0] > proscenium[1] || point[1] < proscenium[2] ||
point[1] > proscenium[3]);
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index b7de3a5b319..8ac272e92b5 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -1084,7 +1084,7 @@ static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
return GeomUtils::intersect2dSeg2dArea(min, max, A, B);
}
-static inline bool insideProscenium(real proscenium[4], const Vec3r &point)
+static inline bool insideProscenium(const real proscenium[4], const Vec3r &point)
{
return !(point[0] < proscenium[0] || point[0] > proscenium[1] || point[1] < proscenium[2] ||
point[1] > proscenium[3]);
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 703d3c393e8..fefd86f6c86 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -30,8 +30,10 @@ set(SRC
intern/attributes_ref.cc
intern/cpp_types.cc
intern/multi_function.cc
+ intern/multi_function_builder.cc
intern/multi_function_network.cc
intern/multi_function_network_evaluation.cc
+ intern/multi_function_network_optimization.cc
FN_array_spans.hh
FN_attributes_ref.hh
@@ -43,6 +45,7 @@ set(SRC
FN_multi_function_data_type.hh
FN_multi_function_network.hh
FN_multi_function_network_evaluation.hh
+ FN_multi_function_network_optimization.hh
FN_multi_function_param_type.hh
FN_multi_function_params.hh
FN_multi_function_signature.hh
diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh
index 3c31665e0b5..cf5ef2af8a6 100644
--- a/source/blender/functions/FN_attributes_ref.hh
+++ b/source/blender/functions/FN_attributes_ref.hh
@@ -161,6 +161,8 @@ class MutableAttributesRef {
Span<void *> buffers_;
IndexRange range_;
+ friend class AttributesRef;
+
public:
MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, uint size)
: MutableAttributesRef(info, buffers, IndexRange(size))
@@ -241,6 +243,97 @@ class MutableAttributesRef {
}
};
+class AttributesRef {
+ private:
+ const AttributesInfo *info_;
+ Span<const void *> buffers_;
+ IndexRange range_;
+
+ public:
+ AttributesRef(const AttributesInfo &info, Span<const void *> buffers, uint size)
+ : AttributesRef(info, buffers, IndexRange(size))
+ {
+ }
+
+ AttributesRef(const AttributesInfo &info, Span<const void *> buffers, IndexRange range)
+ : info_(&info), buffers_(buffers), range_(range)
+ {
+ }
+
+ AttributesRef(MutableAttributesRef attributes)
+ : info_(attributes.info_), buffers_(attributes.buffers_), range_(attributes.range_)
+ {
+ }
+
+ uint size() const
+ {
+ return range_.size();
+ }
+
+ const AttributesInfo &info() const
+ {
+ return *info_;
+ }
+
+ GSpan get(uint index) const
+ {
+ const CPPType &type = info_->type_of(index);
+ const void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start());
+ return GSpan(type, ptr, range_.size());
+ }
+
+ GSpan get(StringRef name) const
+ {
+ return this->get(info_->index_of(name));
+ }
+
+ template<typename T> Span<T> get(uint index) const
+ {
+ BLI_assert(info_->type_of(index).is<T>());
+ return Span<T>((T *)buffers_[index] + range_.start(), range_.size());
+ }
+
+ template<typename T> Span<T> get(StringRef name) const
+ {
+ return this->get<T>(info_->index_of(name));
+ }
+
+ std::optional<GSpan> try_get(StringRef name, const CPPType &type) const
+ {
+ int index = info_->try_index_of(name, type);
+ if (index == -1) {
+ return {};
+ }
+ else {
+ return this->get((uint)index);
+ }
+ }
+
+ template<typename T> std::optional<Span<T>> try_get(StringRef name) const
+ {
+ int index = info_->try_index_of(name);
+ if (index == -1) {
+ return {};
+ }
+ else if (info_->type_of((uint)index).is<T>()) {
+ return this->get<T>((uint)index);
+ }
+ else {
+ return {};
+ }
+ }
+
+ AttributesRef slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
+
+ AttributesRef slice(uint start, uint size) const
+ {
+ return AttributesRef(*info_, buffers_, range_.slice(start, size));
+ }
+};
+
} // namespace blender::fn
#endif /* __FN_ATTRIBUTES_REF_HH__ */
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 1681ff9fe8c..7ec60809194 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -18,12 +18,12 @@
#define __FN_CPP_TYPE_HH__
/** \file
- * \ingroup functions
+ * \ingroup fn
*
- * The CPPType class is the core of the runtime-type-system used by the functions system. An
- * instance of this class can represent any C++ type, that is default-constructible, destructible,
- * movable and copyable. Therefore it also works for all C types. This restrictions might need to
- * be removed in the future, but for now every required type has these properties.
+ * The CPPType class is the core of the runtime-type-system used by the functions system. It can
+ * represent C++ types that are default-constructible, destructible, movable, copyable,
+ * equality comparable and hashable. In the future we might want to make some of these properties
+ * optional.
*
* Every type has a size and an alignment. Every function dealing with C++ types in a generic way,
* has to make sure that alignment rules are followed. The methods provided by a CPPType instance
@@ -40,9 +40,9 @@
* Constructs a single instance of that type at the given pointer.
* - construct_default_n(void *ptr, uint n):
* Constructs n instances of that type in an array that starts at the given pointer.
- * - construct_default_indices(void *ptr, IndexMask index_mask):
+ * - construct_default_indices(void *ptr, IndexMask mask):
* Constructs multiple instances of that type in an array that starts at the given pointer.
- * Only the indices referenced by `index_mask` will by constructed.
+ * Only the indices referenced by `mask` will by constructed.
*
* In some cases default-construction does nothing (e.g. for trivial types like int). The
* `default_value` method provides some default value anyway that can be copied instead. What the
@@ -66,44 +66,94 @@
* pointers to virtual member functions.
*/
+#include "BLI_hash.hh"
#include "BLI_index_mask.hh"
#include "BLI_math_base.h"
#include "BLI_string_ref.hh"
+#include "BLI_utility_mixins.hh"
namespace blender::fn {
-class CPPType {
+class CPPType : NonCopyable, NonMovable {
public:
using ConstructDefaultF = void (*)(void *ptr);
using ConstructDefaultNF = void (*)(void *ptr, uint n);
- using ConstructDefaultIndicesF = void (*)(void *ptr, IndexMask index_mask);
+ using ConstructDefaultIndicesF = void (*)(void *ptr, IndexMask mask);
using DestructF = void (*)(void *ptr);
using DestructNF = void (*)(void *ptr, uint n);
- using DestructIndicesF = void (*)(void *ptr, IndexMask index_mask);
+ using DestructIndicesF = void (*)(void *ptr, IndexMask mask);
using CopyToInitializedF = void (*)(const void *src, void *dst);
using CopyToInitializedNF = void (*)(const void *src, void *dst, uint n);
- using CopyToInitializedIndicesF = void (*)(const void *src, void *dst, IndexMask index_mask);
+ using CopyToInitializedIndicesF = void (*)(const void *src, void *dst, IndexMask mask);
using CopyToUninitializedF = void (*)(const void *src, void *dst);
using CopyToUninitializedNF = void (*)(const void *src, void *dst, uint n);
- using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask index_mask);
+ using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask mask);
using RelocateToInitializedF = void (*)(void *src, void *dst);
using RelocateToInitializedNF = void (*)(void *src, void *dst, uint n);
- using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask index_mask);
+ using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
using RelocateToUninitializedF = void (*)(void *src, void *dst);
using RelocateToUninitializedNF = void (*)(void *src, void *dst, uint n);
- using RelocateToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask index_mask);
+ using RelocateToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
using FillInitializedF = void (*)(const void *value, void *dst, uint n);
- using FillInitializedIndicesF = void (*)(const void *value, void *dst, IndexMask index_mask);
+ using FillInitializedIndicesF = void (*)(const void *value, void *dst, IndexMask mask);
using FillUninitializedF = void (*)(const void *value, void *dst, uint n);
- using FillUninitializedIndicesF = void (*)(const void *value, void *dst, IndexMask index_mask);
+ using FillUninitializedIndicesF = void (*)(const void *value, void *dst, IndexMask mask);
+ using DebugPrintF = void (*)(const void *value, std::stringstream &ss);
+ using IsEqualF = bool (*)(const void *a, const void *b);
+ using HashF = uint32_t (*)(const void *value);
+
+ private:
+ uint size_;
+ uint alignment_;
+ uintptr_t alignment_mask_;
+ bool is_trivially_destructible_;
+
+ ConstructDefaultF construct_default_;
+ ConstructDefaultNF construct_default_n_;
+ ConstructDefaultIndicesF construct_default_indices_;
+
+ DestructF destruct_;
+ DestructNF destruct_n_;
+ DestructIndicesF destruct_indices_;
+
+ CopyToInitializedF copy_to_initialized_;
+ CopyToInitializedNF copy_to_initialized_n_;
+ CopyToInitializedIndicesF copy_to_initialized_indices_;
+
+ CopyToUninitializedF copy_to_uninitialized_;
+ CopyToUninitializedNF copy_to_uninitialized_n_;
+ CopyToUninitializedIndicesF copy_to_uninitialized_indices_;
+
+ RelocateToInitializedF relocate_to_initialized_;
+ RelocateToInitializedNF relocate_to_initialized_n_;
+ RelocateToInitializedIndicesF relocate_to_initialized_indices_;
+
+ RelocateToUninitializedF relocate_to_uninitialized_;
+ RelocateToUninitializedNF relocate_to_uninitialized_n_;
+ RelocateToUninitializedIndicesF relocate_to_uninitialized_indices_;
+
+ FillInitializedF fill_initialized_;
+ FillInitializedIndicesF fill_initialized_indices_;
+
+ FillUninitializedF fill_uninitialized_;
+ FillUninitializedIndicesF fill_uninitialized_indices_;
+
+ DebugPrintF debug_print_;
+ IsEqualF is_equal_;
+ HashF hash_;
+
+ const void *default_value_;
+ std::string name_;
+
+ public:
CPPType(std::string name,
uint size,
uint alignment,
@@ -130,6 +180,9 @@ class CPPType {
FillInitializedIndicesF fill_initialized_indices,
FillUninitializedF fill_uninitialized,
FillUninitializedIndicesF fill_uninitialized_indices,
+ DebugPrintF debug_print,
+ IsEqualF is_equal,
+ HashF hash,
const void *default_value)
: size_(size),
alignment_(alignment),
@@ -156,6 +209,9 @@ class CPPType {
fill_initialized_indices_(fill_initialized_indices),
fill_uninitialized_(fill_uninitialized),
fill_uninitialized_indices_(fill_uninitialized_indices),
+ debug_print_(debug_print),
+ is_equal_(is_equal),
+ hash_(hash),
default_value_(default_value),
name_(name)
{
@@ -164,6 +220,22 @@ class CPPType {
}
/**
+ * Two types only compare equal when their pointer is equal. No two instances of CPPType for the
+ * same C++ type should be created.
+ */
+ friend bool operator==(const CPPType &a, const CPPType &b)
+ {
+ return &a == &b;
+ }
+
+ friend bool operator!=(const CPPType &a, const CPPType &b)
+ {
+ return !(&a == &b);
+ }
+
+ template<typename T> static const CPPType &get();
+
+ /**
* Returns the name of the type for debugging purposes. This name should not be used as
* identifier.
*/
@@ -199,7 +271,7 @@ class CPPType {
* for optimization purposes.
*
* C++ equivalent:
- * std::is_trivially_destructible<T>::value;
+ * std::is_trivially_destructible_v<T>;
*/
bool is_trivially_destructible() const
{
@@ -236,16 +308,16 @@ class CPPType {
void construct_default_n(void *ptr, uint n) const
{
- BLI_assert(this->pointer_has_valid_alignment(ptr));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(ptr));
construct_default_n_(ptr, n);
}
- void construct_default_indices(void *ptr, IndexMask index_mask) const
+ void construct_default_indices(void *ptr, IndexMask mask) const
{
- BLI_assert(this->pointer_has_valid_alignment(ptr));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr));
- construct_default_indices_(ptr, index_mask);
+ construct_default_indices_(ptr, mask);
}
/**
@@ -265,16 +337,21 @@ class CPPType {
void destruct_n(void *ptr, uint n) const
{
- BLI_assert(this->pointer_has_valid_alignment(ptr));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(ptr));
destruct_n_(ptr, n);
}
- void destruct_indices(void *ptr, IndexMask index_mask) const
+ void destruct_indices(void *ptr, IndexMask mask) const
{
- BLI_assert(this->pointer_has_valid_alignment(ptr));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(ptr));
- destruct_indices_(ptr, index_mask);
+ destruct_indices_(ptr, mask);
+ }
+
+ DestructF destruct_cb() const
+ {
+ return destruct_;
}
/**
@@ -295,19 +372,19 @@ class CPPType {
void copy_to_initialized_n(const void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
copy_to_initialized_n_(src, dst, n);
}
- void copy_to_initialized_indices(const void *src, void *dst, IndexMask index_mask) const
+ void copy_to_initialized_indices(const void *src, void *dst, IndexMask mask) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
- copy_to_initialized_indices_(src, dst, index_mask);
+ copy_to_initialized_indices_(src, dst, mask);
}
/**
@@ -330,19 +407,19 @@ class CPPType {
void copy_to_uninitialized_n(const void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
copy_to_uninitialized_n_(src, dst, n);
}
- void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask index_mask) const
+ void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask mask) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
- copy_to_uninitialized_indices_(src, dst, index_mask);
+ copy_to_uninitialized_indices_(src, dst, mask);
}
/**
@@ -365,19 +442,19 @@ class CPPType {
void relocate_to_initialized_n(void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
relocate_to_initialized_n_(src, dst, n);
}
- void relocate_to_initialized_indices(void *src, void *dst, IndexMask index_mask) const
+ void relocate_to_initialized_indices(void *src, void *dst, IndexMask mask) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
- relocate_to_initialized_indices_(src, dst, index_mask);
+ relocate_to_initialized_indices_(src, dst, mask);
}
/**
@@ -400,19 +477,19 @@ class CPPType {
void relocate_to_uninitialized_n(void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
relocate_to_uninitialized_n_(src, dst, n);
}
- void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask index_mask) const
+ void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask mask) const
{
BLI_assert(src != dst);
- BLI_assert(this->pointer_has_valid_alignment(src));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
- relocate_to_uninitialized_indices_(src, dst, index_mask);
+ relocate_to_uninitialized_indices_(src, dst, mask);
}
/**
@@ -422,18 +499,18 @@ class CPPType {
*/
void fill_initialized(const void *value, void *dst, uint n) const
{
- BLI_assert(this->pointer_can_point_to_instance(value));
- BLI_assert(this->pointer_can_point_to_instance(dst));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(value));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
fill_initialized_(value, dst, n);
}
- void fill_initialized_indices(const void *value, void *dst, IndexMask index_mask) const
+ void fill_initialized_indices(const void *value, void *dst, IndexMask mask) const
{
- BLI_assert(this->pointer_has_valid_alignment(value));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
- fill_initialized_indices_(value, dst, index_mask);
+ fill_initialized_indices_(value, dst, mask);
}
/**
@@ -443,18 +520,37 @@ class CPPType {
*/
void fill_uninitialized(const void *value, void *dst, uint n) const
{
- BLI_assert(this->pointer_can_point_to_instance(value));
- BLI_assert(this->pointer_can_point_to_instance(dst));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(value));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
fill_uninitialized_(value, dst, n);
}
- void fill_uninitialized_indices(const void *value, void *dst, IndexMask index_mask) const
+ void fill_uninitialized_indices(const void *value, void *dst, IndexMask mask) const
{
- BLI_assert(this->pointer_has_valid_alignment(value));
- BLI_assert(this->pointer_has_valid_alignment(dst));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(value));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
+
+ fill_uninitialized_indices_(value, dst, mask);
+ }
- fill_uninitialized_indices_(value, dst, index_mask);
+ void debug_print(const void *value, std::stringstream &ss) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(value));
+ debug_print_(value, ss);
+ }
+
+ bool is_equal(const void *a, const void *b) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(a));
+ BLI_assert(this->pointer_can_point_to_instance(b));
+ return is_equal_(a, b);
+ }
+
+ uint32_t hash(const void *value) const
+ {
+ BLI_assert(this->pointer_can_point_to_instance(value));
+ return hash_(value);
}
/**
@@ -466,72 +562,22 @@ class CPPType {
return default_value_;
}
- /**
- * Two types only compare equal when their pointer is equal. No two instances of CPPType for the
- * same C++ type should be created.
- */
- friend bool operator==(const CPPType &a, const CPPType &b)
- {
- return &a == &b;
- }
-
- friend bool operator!=(const CPPType &a, const CPPType &b)
+ uint32_t hash() const
{
- return !(&a == &b);
+ return DefaultHash<const CPPType *>{}(this);
}
- template<typename T> static const CPPType &get();
-
template<typename T> bool is() const
{
return this == &CPPType::get<T>();
}
-
- private:
- uint size_;
- uint alignment_;
- uintptr_t alignment_mask_;
- bool is_trivially_destructible_;
-
- ConstructDefaultF construct_default_;
- ConstructDefaultNF construct_default_n_;
- ConstructDefaultIndicesF construct_default_indices_;
-
- DestructF destruct_;
- DestructNF destruct_n_;
- DestructIndicesF destruct_indices_;
-
- CopyToInitializedF copy_to_initialized_;
- CopyToInitializedNF copy_to_initialized_n_;
- CopyToInitializedIndicesF copy_to_initialized_indices_;
-
- CopyToUninitializedF copy_to_uninitialized_;
- CopyToUninitializedNF copy_to_uninitialized_n_;
- CopyToUninitializedIndicesF copy_to_uninitialized_indices_;
-
- RelocateToInitializedF relocate_to_initialized_;
- RelocateToInitializedNF relocate_to_initialized_n_;
- RelocateToInitializedIndicesF relocate_to_initialized_indices_;
-
- RelocateToUninitializedF relocate_to_uninitialized_;
- RelocateToUninitializedNF relocate_to_uninitialized_n_;
- RelocateToUninitializedIndicesF relocate_to_uninitialized_indices_;
-
- FillInitializedF fill_initialized_;
- FillInitializedIndicesF fill_initialized_indices_;
-
- FillUninitializedF fill_uninitialized_;
- FillUninitializedIndicesF fill_uninitialized_indices_;
-
- const void *default_value_;
- std::string name_;
};
/* --------------------------------------------------------------------
* Utility for creating CPPType instances for C++ types.
*/
-namespace CPPTypeUtil {
+namespace cpp_type_util {
template<typename T> void construct_default_cb(void *ptr)
{
@@ -541,9 +587,9 @@ template<typename T> void construct_default_n_cb(void *ptr, uint n)
{
blender::default_construct_n((T *)ptr, n);
}
-template<typename T> void construct_default_indices_cb(void *ptr, IndexMask index_mask)
+template<typename T> void construct_default_indices_cb(void *ptr, IndexMask mask)
{
- index_mask.foreach_index([&](uint i) { new ((T *)ptr + i) T; });
+ mask.foreach_index([&](uint i) { new ((T *)ptr + i) T; });
}
template<typename T> void destruct_cb(void *ptr)
@@ -554,10 +600,10 @@ template<typename T> void destruct_n_cb(void *ptr, uint n)
{
blender::destruct_n((T *)ptr, n);
}
-template<typename T> void destruct_indices_cb(void *ptr, IndexMask index_mask)
+template<typename T> void destruct_indices_cb(void *ptr, IndexMask mask)
{
T *ptr_ = (T *)ptr;
- index_mask.foreach_index([&](uint i) { ptr_[i].~T(); });
+ mask.foreach_index([&](uint i) { ptr_[i].~T(); });
}
template<typename T> void copy_to_initialized_cb(const void *src, void *dst)
@@ -574,12 +620,12 @@ template<typename T> void copy_to_initialized_n_cb(const void *src, void *dst, u
}
}
template<typename T>
-void copy_to_initialized_indices_cb(const void *src, void *dst, IndexMask index_mask)
+void copy_to_initialized_indices_cb(const void *src, void *dst, IndexMask mask)
{
const T *src_ = (const T *)src;
T *dst_ = (T *)dst;
- index_mask.foreach_index([&](uint i) { dst_[i] = src_[i]; });
+ mask.foreach_index([&](uint i) { dst_[i] = src_[i]; });
}
template<typename T> void copy_to_uninitialized_cb(const void *src, void *dst)
@@ -591,12 +637,12 @@ template<typename T> void copy_to_uninitialized_n_cb(const void *src, void *dst,
blender::uninitialized_copy_n((T *)src, n, (T *)dst);
}
template<typename T>
-void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask index_mask)
+void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask mask)
{
const T *src_ = (const T *)src;
T *dst_ = (T *)dst;
- index_mask.foreach_index([&](uint i) { new (dst_ + i) T(src_[i]); });
+ mask.foreach_index([&](uint i) { new (dst_ + i) T(src_[i]); });
}
template<typename T> void relocate_to_initialized_cb(void *src, void *dst)
@@ -611,13 +657,12 @@ template<typename T> void relocate_to_initialized_n_cb(void *src, void *dst, uin
{
blender::initialized_relocate_n((T *)src, n, (T *)dst);
}
-template<typename T>
-void relocate_to_initialized_indices_cb(void *src, void *dst, IndexMask index_mask)
+template<typename T> void relocate_to_initialized_indices_cb(void *src, void *dst, IndexMask mask)
{
T *src_ = (T *)src;
T *dst_ = (T *)dst;
- index_mask.foreach_index([&](uint i) {
+ mask.foreach_index([&](uint i) {
dst_[i] = std::move(src_[i]);
src_[i].~T();
});
@@ -636,12 +681,12 @@ template<typename T> void relocate_to_uninitialized_n_cb(void *src, void *dst, u
blender::uninitialized_relocate_n((T *)src, n, (T *)dst);
}
template<typename T>
-void relocate_to_uninitialized_indices_cb(void *src, void *dst, IndexMask index_mask)
+void relocate_to_uninitialized_indices_cb(void *src, void *dst, IndexMask mask)
{
T *src_ = (T *)src;
T *dst_ = (T *)dst;
- index_mask.foreach_index([&](uint i) {
+ mask.foreach_index([&](uint i) {
new (dst_ + i) T(std::move(src_[i]));
src_[i].~T();
});
@@ -656,13 +701,12 @@ template<typename T> void fill_initialized_cb(const void *value, void *dst, uint
dst_[i] = value_;
}
}
-template<typename T>
-void fill_initialized_indices_cb(const void *value, void *dst, IndexMask index_mask)
+template<typename T> void fill_initialized_indices_cb(const void *value, void *dst, IndexMask mask)
{
const T &value_ = *(const T *)value;
T *dst_ = (T *)dst;
- index_mask.foreach_index([&](uint i) { dst_[i] = value_; });
+ mask.foreach_index([&](uint i) { dst_[i] = value_; });
}
template<typename T> void fill_uninitialized_cb(const void *value, void *dst, uint n)
@@ -675,24 +719,43 @@ template<typename T> void fill_uninitialized_cb(const void *value, void *dst, ui
}
}
template<typename T>
-void fill_uninitialized_indices_cb(const void *value, void *dst, IndexMask index_mask)
+void fill_uninitialized_indices_cb(const void *value, void *dst, IndexMask mask)
{
const T &value_ = *(const T *)value;
T *dst_ = (T *)dst;
- index_mask.foreach_index([&](uint i) { new (dst_ + i) T(value_); });
+ mask.foreach_index([&](uint i) { new (dst_ + i) T(value_); });
+}
+
+template<typename T> void debug_print_cb(const void *value, std::stringstream &ss)
+{
+ const T &value_ = *(const T *)value;
+ ss << value_;
+}
+
+template<typename T> bool is_equal_cb(const void *a, const void *b)
+{
+ const T &a_ = *(T *)a;
+ const T &b_ = *(T *)b;
+ return a_ == b_;
+}
+
+template<typename T> uint32_t hash_cb(const void *value)
+{
+ const T &value_ = *(const T *)value;
+ return DefaultHash<T>{}(value_);
}
-} // namespace CPPTypeUtil
+} // namespace cpp_type_util
template<typename T>
-static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &default_value)
+inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &default_value)
{
- using namespace CPPTypeUtil;
+ using namespace cpp_type_util;
const CPPType *type = new CPPType(name,
sizeof(T),
alignof(T),
- std::is_trivially_destructible<T>::value,
+ std::is_trivially_destructible_v<T>,
construct_default_cb<T>,
construct_default_n_cb<T>,
construct_default_indices_cb<T>,
@@ -715,6 +778,9 @@ static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
fill_initialized_indices_cb<T>,
fill_uninitialized_cb<T>,
fill_uninitialized_indices_cb<T>,
+ debug_print_cb<T>,
+ is_equal_cb<T>,
+ hash_cb<T>,
(const void *)&default_value);
return std::unique_ptr<const CPPType>(type);
}
diff --git a/source/blender/functions/FN_cpp_types.hh b/source/blender/functions/FN_cpp_types.hh
index 704a1363935..63f6b49885f 100644
--- a/source/blender/functions/FN_cpp_types.hh
+++ b/source/blender/functions/FN_cpp_types.hh
@@ -18,7 +18,7 @@
#define __FN_CPP_TYPES_HH__
/** \file
- * \ingroup functions
+ * \ingroup fn
*
* This header provides convenient access to CPPType instances for some core types like integer
* types.
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh
index f28e94b34ee..2672484c184 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/functions/FN_generic_vector_array.hh
@@ -78,7 +78,7 @@ class GVectorArray : NonCopyable, NonMovable {
operator GVArraySpan() const
{
- return GVArraySpan(type_, starts_.as_span(), lengths_);
+ return GVArraySpan(type_, starts_, lengths_);
}
bool is_empty() const
@@ -98,7 +98,7 @@ class GVectorArray : NonCopyable, NonMovable {
Span<const void *> starts() const
{
- return starts_.as_span();
+ return starts_;
}
Span<uint> lengths() const
diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh
index 452fd5472ce..35f144368ac 100644
--- a/source/blender/functions/FN_multi_function.hh
+++ b/source/blender/functions/FN_multi_function.hh
@@ -45,6 +45,8 @@
* 3. Override the `call` function.
*/
+#include "BLI_hash.hh"
+
#include "FN_multi_function_context.hh"
#include "FN_multi_function_params.hh"
@@ -61,6 +63,21 @@ class MultiFunction {
virtual void call(IndexMask mask, MFParams params, MFContext context) const = 0;
+ virtual uint32_t hash() const
+ {
+ return DefaultHash<const MultiFunction *>{}(this);
+ }
+
+ virtual bool equals(const MultiFunction &UNUSED(other)) const
+ {
+ return false;
+ }
+
+ uint param_amount() const
+ {
+ return signature_.param_types.size();
+ }
+
IndexRange param_indices() const
{
return signature_.param_types.index_range();
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index abc1e5d0723..6e7efb21850 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -203,6 +203,61 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
};
/**
+ * Generates a multi-function that converts between two types.
+ */
+template<typename From, typename To> class CustomMF_Convert : public MultiFunction {
+ public:
+ CustomMF_Convert()
+ {
+ std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
+ MFSignatureBuilder signature = this->get_builder(std::move(name));
+ signature.single_input<From>("Input");
+ signature.single_output<To>("Output");
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ VSpan<From> inputs = params.readonly_single_input<From>(0);
+ MutableSpan<To> outputs = params.uninitialized_single_output<To>(1);
+
+ for (uint i : mask) {
+ new ((void *)&outputs[i]) To(inputs[i]);
+ }
+ }
+};
+
+/**
+ * A multi-function that outputs the same value every time. The value is not owned by an instance
+ * of this function. The caller is responsible for destructing and freeing the value.
+ */
+class CustomMF_GenericConstant : public MultiFunction {
+ private:
+ const CPPType &type_;
+ const void *value_;
+
+ template<typename T> friend class CustomMF_Constant;
+
+ public:
+ CustomMF_GenericConstant(const CPPType &type, const void *value);
+ void call(IndexMask mask, MFParams params, MFContext context) const override;
+ uint32_t hash() const override;
+ bool equals(const MultiFunction &other) const override;
+};
+
+/**
+ * A multi-function that outputs the same array every time. The array is not owned by in instance
+ * of this function. The caller is responsible for destructing and freeing the values.
+ */
+class CustomMF_GenericConstantArray : public MultiFunction {
+ private:
+ GSpan array_;
+
+ public:
+ CustomMF_GenericConstantArray(GSpan array);
+ void call(IndexMask mask, MFParams params, MFContext context) const override;
+};
+
+/**
* Generates a multi-function that outputs a constant value.
*/
template<typename T> class CustomMF_Constant : public MultiFunction {
@@ -223,6 +278,28 @@ template<typename T> class CustomMF_Constant : public MultiFunction {
MutableSpan<T> output = params.uninitialized_single_output<T>(0);
mask.foreach_index([&](uint i) { new (&output[i]) T(value_); });
}
+
+ uint32_t hash() const override
+ {
+ return DefaultHash<T>{}(value_);
+ }
+
+ bool equals(const MultiFunction &other) const override
+ {
+ const CustomMF_Constant *other1 = dynamic_cast<const CustomMF_Constant *>(&other);
+ if (other1 != nullptr) {
+ return value_ == other1->value_;
+ }
+ const CustomMF_GenericConstant *other2 = dynamic_cast<const CustomMF_GenericConstant *>(
+ &other);
+ if (other2 != nullptr) {
+ const CPPType &type = CPPType::get<T>();
+ if (type == other2->type_) {
+ return type.is_equal((const void *)&value_, other2->value_);
+ }
+ }
+ return false;
+ }
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_data_type.hh b/source/blender/functions/FN_multi_function_data_type.hh
index 78f0d96fb80..57aea046006 100644
--- a/source/blender/functions/FN_multi_function_data_type.hh
+++ b/source/blender/functions/FN_multi_function_data_type.hh
@@ -108,6 +108,11 @@ class MFDataType {
BLI_assert(false);
return "";
}
+
+ uint hash() const
+ {
+ return DefaultHash<CPPType>{}(*type_) + (uint32_t)category_;
+ }
};
inline bool operator==(const MFDataType &a, const MFDataType &b)
diff --git a/source/blender/functions/FN_multi_function_network.hh b/source/blender/functions/FN_multi_function_network.hh
index a9d8508cdb8..e47c8260057 100644
--- a/source/blender/functions/FN_multi_function_network.hh
+++ b/source/blender/functions/FN_multi_function_network.hh
@@ -95,8 +95,6 @@ class MFNode : NonCopyable, NonMovable {
Span<MFOutputSocket *> outputs();
Span<const MFOutputSocket *> outputs() const;
- template<typename FuncT> void foreach_origin_socket(const FuncT &func) const;
-
bool all_inputs_have_origin() const;
private:
@@ -150,6 +148,7 @@ class MFSocket : NonCopyable, NonMovable {
StringRefNull name() const;
uint id() const;
+ uint index() const;
const MFDataType &data_type() const;
@@ -216,10 +215,25 @@ class MFNetwork : NonCopyable, NonMovable {
void relink(MFOutputSocket &old_output, MFOutputSocket &new_output);
void remove(MFNode &node);
+ void remove(Span<MFNode *> nodes);
+
+ uint socket_id_amount() const;
+ uint node_id_amount() const;
+
+ Span<MFDummyNode *> dummy_nodes();
+ Span<MFFunctionNode *> function_nodes();
+
+ MFNode *node_or_null_by_id(uint id);
+ const MFNode *node_or_null_by_id(uint id) const;
+
+ MFSocket *socket_or_null_by_id(uint id);
+ const MFSocket *socket_or_null_by_id(uint id) const;
- uint max_socket_id() const;
+ void find_dependencies(Span<const MFInputSocket *> sockets,
+ VectorSet<const MFOutputSocket *> &r_dummy_sockets,
+ VectorSet<const MFInputSocket *> &r_unlinked_inputs) const;
- std::string to_dot() const;
+ std::string to_dot(Span<const MFNode *> marked_nodes = {}) const;
};
/* --------------------------------------------------------------------
@@ -325,16 +339,6 @@ inline Span<const MFOutputSocket *> MFNode::outputs() const
return outputs_;
}
-template<typename FuncT> void MFNode::foreach_origin_socket(const FuncT &func) const
-{
- for (const MFInputSocket *socket : inputs_) {
- const MFOutputSocket *origin = socket->origin();
- if (origin != nullptr) {
- func(*origin);
- }
- }
-}
-
inline bool MFNode::all_inputs_have_origin() const
{
for (const MFInputSocket *socket : inputs_) {
@@ -402,6 +406,11 @@ inline uint MFSocket::id() const
return id_;
}
+inline uint MFSocket::index() const
+{
+ return index_;
+}
+
inline const MFDataType &MFSocket::data_type() const
{
return data_type_;
@@ -476,16 +485,51 @@ inline Span<MFInputSocket *> MFOutputSocket::targets()
inline Span<const MFInputSocket *> MFOutputSocket::targets() const
{
- return targets_.as_span();
+ return targets_;
}
/* --------------------------------------------------------------------
* MFNetwork inline methods.
*/
-inline uint MFNetwork::max_socket_id() const
+inline Span<MFDummyNode *> MFNetwork::dummy_nodes()
+{
+ return dummy_nodes_;
+}
+
+inline Span<MFFunctionNode *> MFNetwork::function_nodes()
+{
+ return function_nodes_;
+}
+
+inline MFNode *MFNetwork::node_or_null_by_id(uint id)
+{
+ return node_or_null_by_id_[id];
+}
+
+inline const MFNode *MFNetwork::node_or_null_by_id(uint id) const
+{
+ return node_or_null_by_id_[id];
+}
+
+inline MFSocket *MFNetwork::socket_or_null_by_id(uint id)
+{
+ return socket_or_null_by_id_[id];
+}
+
+inline const MFSocket *MFNetwork::socket_or_null_by_id(uint id) const
+{
+ return socket_or_null_by_id_[id];
+}
+
+inline uint MFNetwork::socket_id_amount() const
+{
+ return socket_or_null_by_id_.size();
+}
+
+inline uint MFNetwork::node_id_amount() const
{
- return socket_or_null_by_id_.size() - 1;
+ return node_or_null_by_id_.size();
}
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_network_optimization.hh b/source/blender/functions/FN_multi_function_network_optimization.hh
new file mode 100644
index 00000000000..3cbabd72c2a
--- /dev/null
+++ b/source/blender/functions/FN_multi_function_network_optimization.hh
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef __FN_MULTI_FUNCTION_NETWORK_OPTIMIZATION_HH__
+#define __FN_MULTI_FUNCTION_NETWORK_OPTIMIZATION_HH__
+
+#include "FN_multi_function_network.hh"
+
+#include "BLI_resource_collector.hh"
+
+namespace blender::fn::mf_network_optimization {
+
+void dead_node_removal(MFNetwork &network);
+void constant_folding(MFNetwork &network, ResourceCollector &resources);
+void common_subnetwork_elimination(MFNetwork &network);
+
+} // namespace blender::fn::mf_network_optimization
+
+#endif /* __FN_MULTI_FUNCTION_NETWORK_OPTIMIZATION_HH__ */
diff --git a/source/blender/functions/FN_multi_function_param_type.hh b/source/blender/functions/FN_multi_function_param_type.hh
index 0e43e355b53..7c16b8cdf10 100644
--- a/source/blender/functions/FN_multi_function_param_type.hh
+++ b/source/blender/functions/FN_multi_function_param_type.hh
@@ -144,6 +144,11 @@ class MFParamType {
return ELEM(interface_type_, Output, Mutable);
}
+ bool is_output() const
+ {
+ return interface_type_ == Output;
+ }
+
friend bool operator==(const MFParamType &a, const MFParamType &b);
friend bool operator!=(const MFParamType &a, const MFParamType &b);
};
diff --git a/source/blender/functions/FN_spans.hh b/source/blender/functions/FN_spans.hh
index b2622eab95f..c8c98d66628 100644
--- a/source/blender/functions/FN_spans.hh
+++ b/source/blender/functions/FN_spans.hh
@@ -339,6 +339,16 @@ class GVSpan : public VSpanBase<void> {
return ref;
}
+ static GVSpan FromSingleWithMaxSize(const CPPType &type, const void *value)
+ {
+ return GVSpan::FromSingle(type, value, UINT32_MAX);
+ }
+
+ static GVSpan FromDefault(const CPPType &type)
+ {
+ return GVSpan::FromSingleWithMaxSize(type, type.default_value());
+ }
+
static GVSpan FromFullPointerArray(const CPPType &type, const void *const *values, uint size)
{
GVSpan ref;
diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc
new file mode 100644
index 00000000000..889a2595aab
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_builder.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 "FN_multi_function_builder.hh"
+
+#include "BLI_hash.hh"
+
+namespace blender::fn {
+
+CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type, const void *value)
+ : type_(type), value_(value)
+{
+ MFSignatureBuilder signature = this->get_builder("Constant " + type.name());
+ std::stringstream ss;
+ type.debug_print(value, ss);
+ signature.single_output(ss.str(), type);
+}
+
+void CustomMF_GenericConstant::call(IndexMask mask,
+ MFParams params,
+ MFContext UNUSED(context)) const
+{
+ GMutableSpan output = params.uninitialized_single_output(0);
+ type_.fill_uninitialized_indices(value_, output.buffer(), mask);
+}
+
+uint CustomMF_GenericConstant::hash() const
+{
+ return type_.hash(value_);
+}
+
+bool CustomMF_GenericConstant::equals(const MultiFunction &other) const
+{
+ const CustomMF_GenericConstant *_other = dynamic_cast<const CustomMF_GenericConstant *>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ if (type_ != _other->type_) {
+ return false;
+ }
+ return type_.is_equal(value_, _other->value_);
+}
+
+static std::string gspan_to_string(GSpan array)
+{
+ std::stringstream ss;
+ ss << "[";
+ uint max_amount = 5;
+ for (uint i : IndexRange(std::min(max_amount, array.size()))) {
+ array.type().debug_print(array[i], ss);
+ ss << ", ";
+ }
+ if (max_amount < array.size()) {
+ ss << "...";
+ }
+ ss << "]";
+ return ss.str();
+}
+
+CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array)
+{
+ const CPPType &type = array.type();
+ MFSignatureBuilder signature = this->get_builder("Constant " + type.name() + " Vector");
+ signature.vector_output(gspan_to_string(array), type);
+}
+
+void CustomMF_GenericConstantArray::call(IndexMask mask,
+ MFParams params,
+ MFContext UNUSED(context)) const
+{
+ GVectorArray &vectors = params.vector_output(0);
+ for (uint i : mask) {
+ vectors.extend(i, array_);
+ }
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc
index 5df70d92a4e..11c9c065f51 100644
--- a/source/blender/functions/intern/multi_function_network.cc
+++ b/source/blender/functions/intern/multi_function_network.cc
@@ -15,6 +15,8 @@
*/
#include "BLI_dot_export.hh"
+#include "BLI_stack.hh"
+
#include "FN_multi_function_network.hh"
namespace blender::fn {
@@ -184,17 +186,18 @@ void MFNetwork::add_link(MFOutputSocket &from, MFInputSocket &to)
MFOutputSocket &MFNetwork::add_input(StringRef name, MFDataType data_type)
{
- return this->add_dummy(name, {}, {data_type}, {}, {name}).output(0);
+ return this->add_dummy(name, {}, {data_type}, {}, {"Value"}).output(0);
}
MFInputSocket &MFNetwork::add_output(StringRef name, MFDataType data_type)
{
- return this->add_dummy(name, {data_type}, {}, {name}, {}).input(0);
+ return this->add_dummy(name, {data_type}, {}, {"Value"}, {}).input(0);
}
void MFNetwork::relink(MFOutputSocket &old_output, MFOutputSocket &new_output)
{
BLI_assert(&old_output != &new_output);
+ BLI_assert(old_output.data_type_ == new_output.data_type_);
for (MFInputSocket *input : old_output.targets()) {
input->origin_ = &new_output;
}
@@ -230,7 +233,43 @@ void MFNetwork::remove(MFNode &node)
node_or_null_by_id_[node.id_] = nullptr;
}
-std::string MFNetwork::to_dot() const
+void MFNetwork::remove(Span<MFNode *> nodes)
+{
+ for (MFNode *node : nodes) {
+ this->remove(*node);
+ }
+}
+
+void MFNetwork::find_dependencies(Span<const MFInputSocket *> sockets,
+ VectorSet<const MFOutputSocket *> &r_dummy_sockets,
+ VectorSet<const MFInputSocket *> &r_unlinked_inputs) const
+{
+ Set<const MFNode *> visited_nodes;
+ Stack<const MFInputSocket *> sockets_to_check;
+ sockets_to_check.push_multiple(sockets);
+
+ while (!sockets_to_check.is_empty()) {
+ const MFInputSocket &socket = *sockets_to_check.pop();
+ const MFOutputSocket *origin_socket = socket.origin();
+ if (origin_socket == nullptr) {
+ r_unlinked_inputs.add(&socket);
+ continue;
+ }
+
+ const MFNode &origin_node = origin_socket->node();
+
+ if (origin_node.is_dummy()) {
+ r_dummy_sockets.add(origin_socket);
+ continue;
+ }
+
+ if (visited_nodes.add(&origin_node)) {
+ sockets_to_check.push_multiple(origin_node.inputs());
+ }
+ }
+}
+
+std::string MFNetwork::to_dot(Span<const MFNode *> marked_nodes) const
{
dot::DirectedGraph digraph;
digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
@@ -256,6 +295,13 @@ std::string MFNetwork::to_dot() const
dot_nodes.add_new(node, dot_node_ref);
}
+ for (const MFDummyNode *node : dummy_nodes_) {
+ dot_nodes.lookup(node).node().set_background_color("#77EE77");
+ }
+ for (const MFNode *node : marked_nodes) {
+ dot_nodes.lookup(node).node().set_background_color("#7777EE");
+ }
+
for (const MFNode *to_node : all_nodes) {
dot::NodeWithSocketsRef to_dot_node = dot_nodes.lookup(to_node);
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index 08a254dc300..b59cbc6a1a2 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -58,7 +58,7 @@ class MFNetworkEvaluationStorage {
uint min_array_size_;
public:
- MFNetworkEvaluationStorage(IndexMask mask, uint max_socket_id);
+ MFNetworkEvaluationStorage(IndexMask mask, uint socket_id_amount);
~MFNetworkEvaluationStorage();
/* Add the values that have been provided by the caller of the multi-function network. */
@@ -106,30 +106,30 @@ MFNetworkEvaluator::MFNetworkEvaluator(Vector<const MFOutputSocket *> inputs,
BLI_assert(outputs_.size() > 0);
MFSignatureBuilder signature = this->get_builder("Function Tree");
- for (auto socket : inputs_) {
+ for (const MFOutputSocket *socket : inputs_) {
BLI_assert(socket->node().is_dummy());
MFDataType type = socket->data_type();
switch (type.category()) {
case MFDataType::Single:
- signature.single_input("Input", type.single_type());
+ signature.single_input(socket->name(), type.single_type());
break;
case MFDataType::Vector:
- signature.vector_input("Input", type.vector_base_type());
+ signature.vector_input(socket->name(), type.vector_base_type());
break;
}
}
- for (auto socket : outputs_) {
+ for (const MFInputSocket *socket : outputs_) {
BLI_assert(socket->node().is_dummy());
MFDataType type = socket->data_type();
switch (type.category()) {
case MFDataType::Single:
- signature.single_output("Output", type.single_type());
+ signature.single_output(socket->name(), type.single_type());
break;
case MFDataType::Vector:
- signature.vector_output("Output", type.vector_base_type());
+ signature.vector_output(socket->name(), type.vector_base_type());
break;
}
}
@@ -142,7 +142,7 @@ void MFNetworkEvaluator::call(IndexMask mask, MFParams params, MFContext context
}
const MFNetwork &network = outputs_[0]->node().network();
- Storage storage(mask, network.max_socket_id());
+ Storage storage(mask, network.socket_id_amount());
Vector<const MFInputSocket *> outputs_to_initialize_in_the_end;
@@ -219,8 +219,6 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_network_to_compute_outputs(
sockets_to_compute.push(socket->origin());
}
- Vector<const MFOutputSocket *, 32> missing_sockets;
-
/* This is the main loop that traverses the MFNetwork. */
while (!sockets_to_compute.is_empty()) {
const MFOutputSocket &socket = *sockets_to_compute.peek();
@@ -235,17 +233,18 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_network_to_compute_outputs(
BLI_assert(node.all_inputs_have_origin());
const MFFunctionNode &function_node = node.as_function();
- missing_sockets.clear();
- function_node.foreach_origin_socket([&](const MFOutputSocket &origin) {
- if (!storage.socket_is_computed(origin)) {
- missing_sockets.append(&origin);
+ bool all_origins_are_computed = true;
+ for (const MFInputSocket *input_socket : function_node.inputs()) {
+ const MFOutputSocket *origin = input_socket->origin();
+ if (origin != nullptr) {
+ if (!storage.socket_is_computed(*origin)) {
+ sockets_to_compute.push(origin);
+ all_origins_are_computed = false;
+ }
}
- });
-
- sockets_to_compute.push_multiple(missing_sockets);
+ }
- bool all_inputs_are_computed = missing_sockets.size() == 0;
- if (all_inputs_are_computed) {
+ if (all_origins_are_computed) {
this->evaluate_function(global_context, function_node, storage);
sockets_to_compute.pop();
}
@@ -507,9 +506,9 @@ struct OwnVectorValue : public Value {
/** \name Storage methods
* \{ */
-MFNetworkEvaluationStorage::MFNetworkEvaluationStorage(IndexMask mask, uint max_socket_id)
+MFNetworkEvaluationStorage::MFNetworkEvaluationStorage(IndexMask mask, uint socket_id_amount)
: mask_(mask),
- value_per_output_id_(max_socket_id + 1, nullptr),
+ value_per_output_id_(socket_id_amount, nullptr),
min_array_size_(mask.min_array_size())
{
}
diff --git a/source/blender/functions/intern/multi_function_network_optimization.cc b/source/blender/functions/intern/multi_function_network_optimization.cc
new file mode 100644
index 00000000000..849b24a318f
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_network_optimization.cc
@@ -0,0 +1,491 @@
+/*
+ * 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 fn
+ */
+
+/* Used to check if two multi-functions have the exact same type. */
+#include <typeinfo>
+
+#include "FN_multi_function_builder.hh"
+#include "FN_multi_function_network_evaluation.hh"
+#include "FN_multi_function_network_optimization.hh"
+
+#include "BLI_disjoint_set.hh"
+#include "BLI_ghash.h"
+#include "BLI_map.hh"
+#include "BLI_rand.h"
+#include "BLI_stack.hh"
+
+namespace blender::fn::mf_network_optimization {
+
+/* -------------------------------------------------------------------- */
+/** \name Utility functions to find nodes in a network.
+ *
+ * \{ */
+
+static bool set_tag_and_check_if_modified(bool &tag, bool new_value)
+{
+ if (tag != new_value) {
+ tag = new_value;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static Array<bool> mask_nodes_to_the_left(MFNetwork &network, Span<MFNode *> nodes)
+{
+ Array<bool> is_to_the_left(network.node_id_amount(), false);
+ Stack<MFNode *> nodes_to_check;
+
+ for (MFNode *node : nodes) {
+ is_to_the_left[node->id()] = true;
+ nodes_to_check.push(node);
+ }
+
+ while (!nodes_to_check.is_empty()) {
+ MFNode &node = *nodes_to_check.pop();
+
+ for (MFInputSocket *input_socket : node.inputs()) {
+ MFOutputSocket *origin = input_socket->origin();
+ if (origin != nullptr) {
+ MFNode &origin_node = origin->node();
+ if (set_tag_and_check_if_modified(is_to_the_left[origin_node.id()], true)) {
+ nodes_to_check.push(&origin_node);
+ }
+ }
+ }
+ }
+
+ return is_to_the_left;
+}
+
+static Array<bool> mask_nodes_to_the_right(MFNetwork &network, Span<MFNode *> nodes)
+{
+ Array<bool> is_to_the_right(network.node_id_amount(), false);
+ Stack<MFNode *> nodes_to_check;
+
+ for (MFNode *node : nodes) {
+ is_to_the_right[node->id()] = true;
+ nodes_to_check.push(node);
+ }
+
+ while (!nodes_to_check.is_empty()) {
+ MFNode &node = *nodes_to_check.pop();
+
+ for (MFOutputSocket *output_socket : node.outputs()) {
+ for (MFInputSocket *target_socket : output_socket->targets()) {
+ MFNode &target_node = target_socket->node();
+ if (set_tag_and_check_if_modified(is_to_the_right[target_node.id()], true)) {
+ nodes_to_check.push(&target_node);
+ }
+ }
+ }
+ }
+
+ return is_to_the_right;
+}
+
+static Vector<MFNode *> find_nodes_based_on_mask(MFNetwork &network,
+ Span<bool> id_mask,
+ bool mask_value)
+{
+ Vector<MFNode *> nodes;
+ for (uint id : id_mask.index_range()) {
+ if (id_mask[id] == mask_value) {
+ MFNode *node = network.node_or_null_by_id(id);
+ if (node != nullptr) {
+ nodes.append(node);
+ }
+ }
+ }
+ return nodes;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dead Node Removal
+ *
+ * \{ */
+
+/**
+ * Unused nodes are all those nodes that no dummy node depends upon.
+ */
+void dead_node_removal(MFNetwork &network)
+{
+ Array<bool> node_is_used_mask = mask_nodes_to_the_left(network, network.dummy_nodes());
+ Vector<MFNode *> nodes_to_remove = find_nodes_based_on_mask(network, node_is_used_mask, false);
+ network.remove(nodes_to_remove);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constant Folding
+ *
+ * \{ */
+
+static Vector<MFNode *> find_non_constant_nodes(MFNetwork &network)
+{
+ Vector<MFNode *> non_constant_nodes;
+ non_constant_nodes.extend(network.dummy_nodes());
+
+ for (MFFunctionNode *node : network.function_nodes()) {
+ if (!node->all_inputs_have_origin()) {
+ non_constant_nodes.append(node);
+ }
+ }
+ return non_constant_nodes;
+}
+
+static bool output_has_non_constant_target_node(MFOutputSocket *output_socket,
+ Span<bool> is_not_constant_mask)
+{
+ for (MFInputSocket *target_socket : output_socket->targets()) {
+ MFNode &target_node = target_socket->node();
+ bool target_is_not_constant = is_not_constant_mask[target_node.id()];
+ if (target_is_not_constant) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static MFInputSocket *try_find_dummy_target_socket(MFOutputSocket *output_socket)
+{
+ for (MFInputSocket *target_socket : output_socket->targets()) {
+ if (target_socket->node().is_dummy()) {
+ return target_socket;
+ }
+ }
+ return nullptr;
+}
+
+static Vector<MFInputSocket *> find_constant_inputs_to_fold(
+ MFNetwork &network, Vector<MFDummyNode *> &r_temporary_nodes)
+{
+ Vector<MFNode *> non_constant_nodes = find_non_constant_nodes(network);
+ Array<bool> is_not_constant_mask = mask_nodes_to_the_right(network, non_constant_nodes);
+ Vector<MFNode *> constant_nodes = find_nodes_based_on_mask(network, is_not_constant_mask, false);
+
+ Vector<MFInputSocket *> sockets_to_compute;
+ for (MFNode *node : constant_nodes) {
+ if (node->inputs().size() == 0) {
+ continue;
+ }
+
+ for (MFOutputSocket *output_socket : node->outputs()) {
+ MFDataType data_type = output_socket->data_type();
+ if (output_has_non_constant_target_node(output_socket, is_not_constant_mask)) {
+ MFInputSocket *dummy_target = try_find_dummy_target_socket(output_socket);
+ if (dummy_target == nullptr) {
+ dummy_target = &network.add_output("Dummy", data_type);
+ network.add_link(*output_socket, *dummy_target);
+ r_temporary_nodes.append(&dummy_target->node().as_dummy());
+ }
+
+ sockets_to_compute.append(dummy_target);
+ }
+ }
+ }
+ return sockets_to_compute;
+}
+
+static void prepare_params_for_constant_folding(const MultiFunction &network_fn,
+ MFParamsBuilder &params,
+ ResourceCollector &resources)
+{
+ for (uint param_index : network_fn.param_indices()) {
+ MFParamType param_type = network_fn.param_type(param_index);
+ MFDataType data_type = param_type.data_type();
+
+ switch (data_type.category()) {
+ case MFDataType::Single: {
+ /* Allocates memory for a single constant folded value. */
+ const CPPType &cpp_type = data_type.single_type();
+ void *buffer = resources.linear_allocator().allocate(cpp_type.size(),
+ cpp_type.alignment());
+ GMutableSpan array{cpp_type, buffer, 1};
+ params.add_uninitialized_single_output(array);
+ break;
+ }
+ case MFDataType::Vector: {
+ /* Allocates memory for a constant folded vector. */
+ const CPPType &cpp_type = data_type.vector_base_type();
+ GVectorArray &vector_array = resources.construct<GVectorArray>(AT, cpp_type, 1);
+ params.add_vector_output(vector_array);
+ break;
+ }
+ }
+ }
+}
+
+static Array<MFOutputSocket *> add_constant_folded_sockets(const MultiFunction &network_fn,
+ MFParamsBuilder &params,
+ ResourceCollector &resources,
+ MFNetwork &network)
+{
+ Array<MFOutputSocket *> folded_sockets{network_fn.param_indices().size(), nullptr};
+
+ for (uint param_index : network_fn.param_indices()) {
+ MFParamType param_type = network_fn.param_type(param_index);
+ MFDataType data_type = param_type.data_type();
+
+ const MultiFunction *constant_fn = nullptr;
+
+ switch (data_type.category()) {
+ case MFDataType::Single: {
+ const CPPType &cpp_type = data_type.single_type();
+ GMutableSpan array = params.computed_array(param_index);
+ void *buffer = array.buffer();
+ resources.add(buffer, array.type().destruct_cb(), AT);
+
+ constant_fn = &resources.construct<CustomMF_GenericConstant>(AT, cpp_type, buffer);
+ break;
+ }
+ case MFDataType::Vector: {
+ GVectorArray &vector_array = params.computed_vector_array(param_index);
+ GSpan array = vector_array[0];
+ constant_fn = &resources.construct<CustomMF_GenericConstantArray>(AT, array);
+ break;
+ }
+ }
+
+ MFFunctionNode &folded_node = network.add_function(*constant_fn);
+ folded_sockets[param_index] = &folded_node.output(0);
+ }
+ return folded_sockets;
+}
+
+static Array<MFOutputSocket *> compute_constant_sockets_and_add_folded_nodes(
+ MFNetwork &network,
+ Span<const MFInputSocket *> sockets_to_compute,
+ ResourceCollector &resources)
+{
+ MFNetworkEvaluator network_fn{{}, sockets_to_compute};
+
+ MFContextBuilder context;
+ MFParamsBuilder params{network_fn, 1};
+ prepare_params_for_constant_folding(network_fn, params, resources);
+ network_fn.call({0}, params, context);
+ return add_constant_folded_sockets(network_fn, params, resources, network);
+}
+
+/**
+ * Find function nodes that always output the same value and replace those with constant nodes.
+ */
+void constant_folding(MFNetwork &network, ResourceCollector &resources)
+{
+ Vector<MFDummyNode *> temporary_nodes;
+ Vector<MFInputSocket *> inputs_to_fold = find_constant_inputs_to_fold(network, temporary_nodes);
+ if (inputs_to_fold.size() == 0) {
+ return;
+ }
+
+ Array<MFOutputSocket *> folded_sockets = compute_constant_sockets_and_add_folded_nodes(
+ network, inputs_to_fold, resources);
+
+ for (uint i : inputs_to_fold.index_range()) {
+ MFOutputSocket &original_socket = *inputs_to_fold[i]->origin();
+ network.relink(original_socket, *folded_sockets[i]);
+ }
+
+ network.remove(temporary_nodes);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common Sub-network Elimination
+ *
+ * \{ */
+
+static uint32_t compute_node_hash(MFFunctionNode &node, RNG *rng, Span<uint32_t> node_hashes)
+{
+ uint32_t combined_inputs_hash = 394659347u;
+ for (MFInputSocket *input_socket : node.inputs()) {
+ MFOutputSocket *origin_socket = input_socket->origin();
+ uint32_t input_hash;
+ if (origin_socket == nullptr) {
+ input_hash = BLI_rng_get_uint(rng);
+ }
+ else {
+ input_hash = BLI_ghashutil_combine_hash(node_hashes[origin_socket->node().id()],
+ origin_socket->index());
+ }
+ combined_inputs_hash = BLI_ghashutil_combine_hash(combined_inputs_hash, input_hash);
+ }
+
+ uint32_t function_hash = node.function().hash();
+ uint32_t node_hash = BLI_ghashutil_combine_hash(combined_inputs_hash, function_hash);
+ return node_hash;
+}
+
+/**
+ * Produces a hash for every node. Two nodes with the same hash should have a high probability of
+ * outputting the same values.
+ */
+static Array<uint32_t> compute_node_hashes(MFNetwork &network)
+{
+ RNG *rng = BLI_rng_new(0);
+ Array<uint32_t> node_hashes(network.node_id_amount());
+ Array<bool> node_is_hashed(network.node_id_amount(), false);
+
+ /* No dummy nodes are not assumed to output the same values. */
+ for (MFDummyNode *node : network.dummy_nodes()) {
+ uint32_t node_hash = BLI_rng_get_uint(rng);
+ node_hashes[node->id()] = node_hash;
+ node_is_hashed[node->id()] = true;
+ }
+
+ Stack<MFFunctionNode *> nodes_to_check;
+ nodes_to_check.push_multiple(network.function_nodes());
+
+ while (!nodes_to_check.is_empty()) {
+ MFFunctionNode &node = *nodes_to_check.peek();
+ if (node_is_hashed[node.id()]) {
+ nodes_to_check.pop();
+ continue;
+ }
+
+ /* Make sure that origin nodes are hashed first. */
+ bool all_dependencies_ready = true;
+ for (MFInputSocket *input_socket : node.inputs()) {
+ MFOutputSocket *origin_socket = input_socket->origin();
+ if (origin_socket != nullptr) {
+ MFNode &origin_node = origin_socket->node();
+ if (!node_is_hashed[origin_node.id()]) {
+ all_dependencies_ready = false;
+ nodes_to_check.push(&origin_node.as_function());
+ }
+ }
+ }
+ if (!all_dependencies_ready) {
+ continue;
+ }
+
+ uint32_t node_hash = compute_node_hash(node, rng, node_hashes);
+ node_hashes[node.id()] = node_hash;
+ node_is_hashed[node.id()] = true;
+ nodes_to_check.pop();
+ }
+
+ BLI_rng_free(rng);
+ return node_hashes;
+}
+
+static Map<uint32_t, Vector<MFNode *, 1>> group_nodes_by_hash(MFNetwork &network,
+ Span<uint32_t> node_hashes)
+{
+ Map<uint32_t, Vector<MFNode *, 1>> nodes_by_hash;
+ for (uint id : IndexRange(network.node_id_amount())) {
+ MFNode *node = network.node_or_null_by_id(id);
+ if (node != nullptr) {
+ uint32_t node_hash = node_hashes[id];
+ nodes_by_hash.lookup_or_add_default(node_hash).append(node);
+ }
+ }
+ return nodes_by_hash;
+}
+
+static bool functions_are_equal(const MultiFunction &a, const MultiFunction &b)
+{
+ if (&a == &b) {
+ return true;
+ }
+ if (typeid(a) == typeid(b)) {
+ return a.equals(b);
+ }
+ return false;
+}
+
+static bool nodes_output_same_values(DisjointSet &cache, const MFNode &a, const MFNode &b)
+{
+ if (cache.in_same_set(a.id(), b.id())) {
+ return true;
+ }
+
+ if (a.is_dummy() || b.is_dummy()) {
+ return false;
+ }
+ if (!functions_are_equal(a.as_function().function(), b.as_function().function())) {
+ return false;
+ }
+ for (uint i : a.inputs().index_range()) {
+ const MFOutputSocket *origin_a = a.input(i).origin();
+ const MFOutputSocket *origin_b = b.input(i).origin();
+ if (origin_a == nullptr || origin_b == nullptr) {
+ return false;
+ }
+ if (!nodes_output_same_values(cache, origin_a->node(), origin_b->node())) {
+ return false;
+ }
+ }
+
+ cache.join(a.id(), b.id());
+ return true;
+}
+
+static void relink_duplicate_nodes(MFNetwork &network,
+ Map<uint32_t, Vector<MFNode *, 1>> &nodes_by_hash)
+{
+ DisjointSet same_node_cache{network.node_id_amount()};
+
+ for (Span<MFNode *> nodes_with_same_hash : nodes_by_hash.values()) {
+ if (nodes_with_same_hash.size() <= 1) {
+ continue;
+ }
+
+ Vector<MFNode *, 16> nodes_to_check = nodes_with_same_hash;
+ while (nodes_to_check.size() >= 2) {
+ Vector<MFNode *, 16> remaining_nodes;
+
+ MFNode &deduplicated_node = *nodes_to_check[0];
+ for (MFNode *node : nodes_to_check.as_span().drop_front(1)) {
+ /* This is true with fairly high probability, but hash collisions can happen. So we have to
+ * check if the node actually output the same values. */
+ if (nodes_output_same_values(same_node_cache, deduplicated_node, *node)) {
+ for (uint i : deduplicated_node.outputs().index_range()) {
+ network.relink(node->output(i), deduplicated_node.output(i));
+ }
+ }
+ else {
+ remaining_nodes.append(node);
+ }
+ }
+ nodes_to_check = std::move(remaining_nodes);
+ }
+ }
+}
+
+/**
+ * Tries to detect duplicate sub-networks and eliminates them. This can help quite a lot when node
+ * groups were used to create the network.
+ */
+void common_subnetwork_elimination(MFNetwork &network)
+{
+ Array<uint32_t> node_hashes = compute_node_hashes(network);
+ Map<uint32_t, Vector<MFNode *, 1>> nodes_by_hash = group_nodes_by_hash(network, node_hashes);
+ relink_duplicate_nodes(network, nodes_by_hash);
+}
+
+/** \} */
+
+} // namespace blender::fn::mf_network_optimization
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 92aacc74190..497cb4a10a5 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -42,7 +42,6 @@ set(INC_SYS
)
set(SRC
- intern/MOD_gpencil_util.h
intern/MOD_gpencil_ui_common.c
intern/MOD_gpencil_util.c
@@ -65,8 +64,9 @@ set(SRC
intern/MOD_gpenciltime.c
intern/MOD_gpenciltint.c
- intern/MOD_gpencil_ui_common.h
MOD_gpencil_modifiertypes.h
+ intern/MOD_gpencil_ui_common.h
+ intern/MOD_gpencil_util.h
)
set(LIB
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 54ed2ffafe1..56d94611b5d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -119,7 +119,6 @@ static void gpf_clear_all_strokes(bGPDframe *gpf)
/* Reduce the number of points in the stroke
*
* Note: This won't be called if all points are present/removed
- * TODO: Allow blending of growing/shrinking tip (e.g. for more gradual transitions)
*/
static void reduce_stroke_points(bGPDstroke *gps,
const int num_points,
@@ -132,7 +131,6 @@ static void reduce_stroke_points(bGPDstroke *gps,
}
/* Which end should points be removed from */
- // TODO: free stroke weights
switch (transition) {
case GP_BUILD_TRANSITION_GROW: /* Show in forward order =
* Remove ungrown-points from end of stroke. */
@@ -279,7 +277,6 @@ static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
}
else {
/* Some proportion of stroke is visible */
- /* XXX: Will the transition settings still be valid now? */
if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) {
/* Do nothing - whole stroke is visible */
}
@@ -303,8 +300,6 @@ static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
/* --------------------------------------------- */
/* Concurrent - Show multiple strokes at once */
-// TODO: Allow random offsets to start times
-// TODO: Allow varying speeds? Scaling of progress?
static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
{
bGPDstroke *gps, *gps_next;
@@ -342,8 +337,7 @@ static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
/* Build effect occurs over when fac = 0, to fac = relative_len */
if (fac <= relative_len) {
/* Scale fac to fit relative_len */
- /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
- const float scaled_fac = fac / relative_len;
+ const float scaled_fac = fac / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
if (reverse) {
num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
@@ -371,8 +365,7 @@ static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
const float start_fac = 1.0f - relative_len;
if (fac >= start_fac) {
- /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
- const float scaled_fac = (fac - start_fac) / relative_len;
+ const float scaled_fac = (fac - start_fac) / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
if (reverse) {
num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
@@ -393,8 +386,6 @@ static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
break;
}
-
- /* TODO... */
}
/* Modify the stroke geometry */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index 812bb5628e1..0d8a5f7914e 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -327,7 +327,7 @@ static void random_panel_draw(const bContext *C, Panel *panel)
static void mask_panel_draw(const bContext *C, Panel *panel)
{
- gpencil_modifier_masking_panel_draw(C, panel, true, false);
+ gpencil_modifier_masking_panel_draw(C, panel, true, true);
}
static void panelRegister(ARegionType *region_type)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index 8d4556421eb..1e75c5926cd 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -83,7 +83,7 @@ static void deformStroke(GpencilModifierData *md,
mmd->material,
mmd->pass_index,
mmd->layer_pass,
- mmd->mode == GP_SIMPLIFY_SAMPLE ? 3 : 4,
+ mmd->mode == GP_SIMPLIFY_SAMPLE ? 2 : 4,
gpl,
gps,
mmd->flag & GP_SIMPLIFY_INVERT_LAYER,
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 41a29a4d45d..c7e74040568 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -67,7 +67,7 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
- int *grid_indices);
+ const int *grid_indices);
/* Update mesh buffers without topology changes. Threaded. */
enum {
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index eeb2d2caef2..c372bfaf218 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -169,8 +169,8 @@ void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_sss_profile_create(GPUMaterial *material,
float radii[3],
- short *falloff_type,
- float *sharpness);
+ const short *falloff_type,
+ const float *sharpness);
struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material,
int sample_len,
struct GPUTexture **tex_profile);
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 9c21f9040da..10d5a860f6a 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -38,6 +38,7 @@
#include "BLI_utildefines.h"
#include "DNA_meshdata_types.h"
+#include "DNA_userdef_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_ccg.h"
@@ -234,7 +235,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_face_sets = sculpt_face_sets &&
(update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0;
- const bool show_vcol = (vcol || vtcol) && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_vcol = (vcol || (vtcol && U.experimental.use_sculpt_vertex_colors)) &&
+ (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
bool empty_mask = true;
bool default_face_set = true;
@@ -317,7 +319,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Vertex Colors. */
if (show_vcol) {
ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- if (vtcol) {
+ if (vtcol && U.experimental.use_sculpt_vertex_colors) {
scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]);
scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]);
scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]);
@@ -450,7 +452,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers,
SubdivCCG *UNUSED(subdiv_ccg),
const int *UNUSED(face_sets),
- int *grid_indices,
+ const int *grid_indices,
uint visible_quad_len,
int totgrid,
int gridsize)
@@ -581,7 +583,7 @@ static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers,
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
- int *grid_indices)
+ const int *grid_indices)
{
const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index fbeb2edc266..d1c7aba37df 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -339,7 +339,6 @@ void gpu_extensions_init(void)
GG.depth_blitting_workaround = true;
GG.unused_fb_slot_workaround = true;
GG.texture_copy_workaround = true;
- GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
}
/* Special fix for theses specific GPUs.
@@ -347,7 +346,12 @@ void gpu_extensions_init(void)
if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
(strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) {
GG.mip_render_workaround = true;
- GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
+ }
+
+ /* Intel Ivy Bridge GPU's seems to have buggy cube-map array support. (see T75943) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
+ (strstr(renderer, "HD Graphics 4000") || strstr(renderer, "HD Graphics 2500"))) {
+ GG.glew_arb_texture_cube_map_array_is_supported = false;
}
/* df/dy calculation factors, those are dependent on driver */
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index d2384b9c065..c65c1046b8f 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -497,8 +497,8 @@ static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
void GPU_material_sss_profile_create(GPUMaterial *material,
float radii[3],
- short *falloff_type,
- float *sharpness)
+ const short *falloff_type,
+ const float *sharpness)
{
copy_v3_v3(material->sss_radii, radii);
material->sss_falloff = (falloff_type) ? *falloff_type : 0.0;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
index 7309549062c..d15f48c8f8a 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -9,25 +9,33 @@ uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE];
uniform vec4 parameters[MAX_PARAM];
#endif
-/* gl_InstanceID is 0 if not drawing instances. */
-#define recti parameters[gl_InstanceID * MAX_PARAM + 0]
-#define rect parameters[gl_InstanceID * MAX_PARAM + 1]
-#define radsi parameters[gl_InstanceID * MAX_PARAM + 2].x
-#define rads parameters[gl_InstanceID * MAX_PARAM + 2].y
-#define faci parameters[gl_InstanceID * MAX_PARAM + 2].zw
-#define roundCorners parameters[gl_InstanceID * MAX_PARAM + 3]
-#define colorInner1 parameters[gl_InstanceID * MAX_PARAM + 4]
-#define colorInner2 parameters[gl_InstanceID * MAX_PARAM + 5]
-#define colorEdge parameters[gl_InstanceID * MAX_PARAM + 6]
-#define colorEmboss parameters[gl_InstanceID * MAX_PARAM + 7]
-#define colorTria parameters[gl_InstanceID * MAX_PARAM + 8]
-#define tria1Center parameters[gl_InstanceID * MAX_PARAM + 9].xy
-#define tria2Center parameters[gl_InstanceID * MAX_PARAM + 9].zw
-#define tria1Size parameters[gl_InstanceID * MAX_PARAM + 10].x
-#define tria2Size parameters[gl_InstanceID * MAX_PARAM + 10].y
-#define shadeDir parameters[gl_InstanceID * MAX_PARAM + 10].z
-#define alphaDiscard parameters[gl_InstanceID * MAX_PARAM + 10].w
-#define triaType parameters[gl_InstanceID * MAX_PARAM + 11].x
+/* gl_InstanceID is supposed to be 0 if not drawing instances, but this seems
+ * to be violated in some drivers. For example, macOS 10.15.4 and Intel Iris
+ * causes T78307 when using gl_InstanceID outside of instance. */
+#ifdef USE_INSTANCE
+# define widgetID gl_InstanceID
+#else
+# define widgetID 0
+#endif
+
+#define recti parameters[widgetID * MAX_PARAM + 0]
+#define rect parameters[widgetID * MAX_PARAM + 1]
+#define radsi parameters[widgetID * MAX_PARAM + 2].x
+#define rads parameters[widgetID * MAX_PARAM + 2].y
+#define faci parameters[widgetID * MAX_PARAM + 2].zw
+#define roundCorners parameters[widgetID * MAX_PARAM + 3]
+#define colorInner1 parameters[widgetID * MAX_PARAM + 4]
+#define colorInner2 parameters[widgetID * MAX_PARAM + 5]
+#define colorEdge parameters[widgetID * MAX_PARAM + 6]
+#define colorEmboss parameters[widgetID * MAX_PARAM + 7]
+#define colorTria parameters[widgetID * MAX_PARAM + 8]
+#define tria1Center parameters[widgetID * MAX_PARAM + 9].xy
+#define tria2Center parameters[widgetID * MAX_PARAM + 9].zw
+#define tria1Size parameters[widgetID * MAX_PARAM + 10].x
+#define tria2Size parameters[widgetID * MAX_PARAM + 10].y
+#define shadeDir parameters[widgetID * MAX_PARAM + 10].z
+#define alphaDiscard parameters[widgetID * MAX_PARAM + 10].w
+#define triaType parameters[widgetID * MAX_PARAM + 11].x
/* We encode alpha check and discard factor together. */
#define doAlphaCheck (alphaDiscard < 0.0)
@@ -179,10 +187,4 @@ void main()
vec2 pos = (is_tria) ? do_tria() : do_widget();
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
-
-#ifdef OS_MAC
- /* Generate a dummy read to avoid the driver bug with shaders having no
- * vertex reads on macOS (T78307) */
- gl_Position.x += dummy * 0.0;
-#endif
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
index 981d17b4283..b6aad5904ff 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
@@ -1,4 +1,150 @@
-void node_tex_sky(vec3 co, out vec4 color)
+float sky_angle_between(float thetav, float phiv, float theta, float phi)
+{
+ float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta);
+
+ if (cospsi > 1.0) {
+ return 0.0;
+ }
+ if (cospsi < -1.0) {
+ return M_PI;
+ }
+
+ return acos(cospsi);
+}
+
+vec3 sky_spherical_coordinates(vec3 dir)
+{
+ return vec3(M_PI_2 - atan(dir.z, length(dir.xy)), atan(dir.x, dir.y), 0);
+}
+
+/* Preetham */
+/* lam03+lam4: 5 floats passed as vec4+float */
+float sky_perez_function(vec4 lam03, float lam4, float theta, float gamma)
+{
+ float ctheta = cos(theta);
+ float cgamma = cos(gamma);
+
+ return (1.0 + lam03[0] * exp(lam03[1] / ctheta)) *
+ (1.0 + lam03[2] * exp(lam03[3] * gamma) + lam4 * cgamma * cgamma);
+}
+
+vec3 xyY_to_xyz(float x, float y, float Y)
+{
+ float X, Z;
+
+ if (y != 0.0) {
+ X = (x / y) * Y;
+ }
+ else {
+ X = 0.0;
+ }
+
+ if (y != 0.0 && Y != 0.0) {
+ Z = ((1.0 - x - y) / y) * Y;
+ }
+ else {
+ Z = 0.0;
+ }
+
+ return vec3(X, Y, Z);
+}
+
+void node_tex_sky_preetham(vec3 co,
+ vec4 config_Y03,
+ float config_Y4,
+ vec4 config_x03,
+ float config_x4,
+ vec4 config_y03,
+ float config_y4,
+ vec2 sun_angles,
+ vec3 radiance,
+ vec3 xyz_to_r,
+ vec3 xyz_to_g,
+ vec3 xyz_to_b,
+ out vec4 color)
+{
+ /* convert vector to spherical coordinates */
+ vec3 spherical = sky_spherical_coordinates(co);
+ float theta = spherical[0];
+ float phi = spherical[1];
+
+ float suntheta = sun_angles[0];
+ float sunphi = sun_angles[1];
+
+ /* angle between sun direction and dir */
+ float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
+
+ /* clamp theta to horizon */
+ theta = min(theta, M_PI_2 - 0.001);
+
+ /* compute xyY color space values */
+ float Y = radiance[0] * sky_perez_function(config_Y03, config_Y4, theta, gamma);
+ float x = radiance[1] * sky_perez_function(config_x03, config_x4, theta, gamma);
+ float y = radiance[2] * sky_perez_function(config_y03, config_y4, theta, gamma);
+
+ /* convert to RGB */
+ vec3 xyz = xyY_to_xyz(x, y, Y);
+ color = vec4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1);
+}
+
+/* Hosek / Wilkie */
+float sky_radiance_hosekwilkie(
+ vec4 config03, vec4 config47, float config8, float theta, float gamma)
+{
+ float ctheta = cos(theta);
+ float cgamma = cos(gamma);
+
+ float expM = exp(config47[0] * gamma);
+ float rayM = cgamma * cgamma;
+ float mieM = (1.0 + rayM) / pow((1.0 + config8 * config8 - 2.0 * config8 * cgamma), 1.5);
+ float zenith = sqrt(ctheta);
+
+ return (1.0 + config03[0] * exp(config03[1] / (ctheta + 0.01))) *
+ (config03[2] + config03[3] * expM + config47[1] * rayM + config47[2] * mieM +
+ config47[3] * zenith);
+}
+
+void node_tex_sky_hosekwilkie(vec3 co,
+ vec4 config_x03,
+ vec4 config_x47,
+ vec4 config_y03,
+ vec4 config_y47,
+ vec4 config_z03,
+ vec4 config_z47,
+ vec3 config_xyz8,
+ vec2 sun_angles,
+ vec3 radiance,
+ vec3 xyz_to_r,
+ vec3 xyz_to_g,
+ vec3 xyz_to_b,
+ out vec4 color)
+{
+ /* convert vector to spherical coordinates */
+ vec3 spherical = sky_spherical_coordinates(co);
+ float theta = spherical[0];
+ float phi = spherical[1];
+
+ float suntheta = sun_angles[0];
+ float sunphi = sun_angles[1];
+
+ /* angle between sun direction and dir */
+ float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
+
+ /* clamp theta to horizon */
+ theta = min(theta, M_PI_2 - 0.001);
+
+ vec3 xyz;
+ xyz.x = sky_radiance_hosekwilkie(config_x03, config_x47, config_xyz8[0], theta, gamma) *
+ radiance.x;
+ xyz.y = sky_radiance_hosekwilkie(config_y03, config_y47, config_xyz8[1], theta, gamma) *
+ radiance.y;
+ xyz.z = sky_radiance_hosekwilkie(config_z03, config_z47, config_xyz8[2], theta, gamma) *
+ radiance.z;
+
+ color = vec4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1);
+}
+
+void node_tex_sky_nishita(vec3 co, out vec4 color)
{
color = vec4(1.0);
}
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 3158e3419b0..4530f6c9fc0 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -72,6 +72,7 @@ BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
BLI_INLINE void IMB_colormangement_xyz_to_rgb(float rgb[3], const float xyz[3]);
BLI_INLINE void IMB_colormangement_rgb_to_xyz(float xyz[3], const float rgb[3]);
+const float *IMB_colormangement_get_xyz_to_rgb(void);
/* ** Color space transformation functions ** */
void IMB_colormanagement_transform(float *buffer,
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 83ef910d0bb..fc7e03c3073 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -367,6 +367,7 @@ struct anim *IMB_open_anim(const char *name,
void IMB_suffix_anim(struct anim *anim, const char *suffix);
void IMB_close_anim(struct anim *anim);
void IMB_close_anim_proxies(struct anim *anim);
+bool IMB_anim_can_produce_frames(const struct anim *anim);
/**
*
@@ -411,7 +412,7 @@ void IMB_free_anim(struct anim *anim);
void IMB_filter(struct ImBuf *ibuf);
void IMB_mask_filter_extend(char *mask, int width, int height);
-void IMB_mask_clear(struct ImBuf *ibuf, char *mask, int val);
+void IMB_mask_clear(struct ImBuf *ibuf, const char *mask, int val);
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter);
void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter);
@@ -599,7 +600,7 @@ void bilinear_interpolation_color_wrap(
struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
-void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3]);
+void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
void IMB_sampleImageAtLocation(
struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 11b30a24cde..220801137f5 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -304,6 +304,21 @@ struct anim *IMB_open_anim(const char *name,
return (anim);
}
+bool IMB_anim_can_produce_frames(const struct anim *anim)
+{
+#ifdef WITH_AVI
+ if (anim->avi != NULL) {
+ return true;
+ }
+#endif
+#ifdef WITH_FFMPEG
+ if (anim->pCodecCtx != NULL) {
+ return true;
+ }
+#endif
+ return false;
+}
+
void IMB_suffix_anim(struct anim *anim, const char *suffix)
{
BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 3f5a0f25cc5..5c9ebbaba21 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1456,6 +1456,11 @@ bool IMB_colormanagement_space_name_is_data(const char *name)
return (colorspace && colorspace->is_data);
}
+const float *IMB_colormangement_get_xyz_to_rgb()
+{
+ return &imbuf_xyz_to_rgb[0][0];
+}
+
/*********************** Threaded display buffer transform routines *************************/
typedef struct DisplayBufferThread {
@@ -1718,7 +1723,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
static void display_buffer_apply_threaded(ImBuf *ibuf,
- float *buffer,
+ const float *buffer,
unsigned char *byte_buffer,
float *display_buffer,
unsigned char *display_buffer_byte,
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp
index 4397c1febab..9fd6d71e091 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.cpp
+++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp
@@ -241,7 +241,7 @@ void BlockDXT1::decodeBlockNV5x(ColorBlock *block) const
}
}
-void BlockDXT1::setIndices(int *idx)
+void BlockDXT1::setIndices(const int *idx)
{
indices = 0;
for (uint i = 0; i < 16; i++) {
@@ -580,7 +580,7 @@ void BlockCTX1::decodeBlock(ColorBlock *block) const
}
}
-void BlockCTX1::setIndices(int *idx)
+void BlockCTX1::setIndices(const int *idx)
{
indices = 0;
for (uint i = 0; i < 16; i++) {
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 16937bce042..57430dbaea2 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -76,7 +76,7 @@ struct BlockDXT1 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
- void setIndices(int *idx);
+ void setIndices(const int *idx);
void flip4();
void flip2();
@@ -289,7 +289,7 @@ struct BlockCTX1 {
};
void evaluatePalette(Color32 color_array[4]) const;
- void setIndices(int *idx);
+ void setIndices(const int *idx);
void decodeBlock(ColorBlock *block) const;
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index e36088f8eac..d8a5096af71 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -363,7 +363,7 @@ void IMB_mask_filter_extend(char *mask, int width, int height)
MEM_freeN(temprect);
}
-void IMB_mask_clear(ImBuf *ibuf, char *mask, int val)
+void IMB_mask_clear(ImBuf *ibuf, const char *mask, int val)
{
int x, y;
if (ibuf->rect_float) {
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 7ebbd1a7409..bf58f047773 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -456,7 +456,7 @@ void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[
}
}
-void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3])
+void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3])
{
size_t a = ((size_t)x) * y;
unsigned char *cp = rect;
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 985a8e977ca..7cc31b99077 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -894,7 +894,7 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
}
static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
- short *stop,
+ const short *stop,
short *do_update,
float *progress)
{
@@ -1090,7 +1090,7 @@ static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context,
}
static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
- short *stop,
+ const short *stop,
short *do_update,
float *progress)
{
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index bfcd1ec2cee..2516df22151 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -122,7 +122,7 @@ static int expandrow2(
static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt);
-static void lumrow(uchar *rgbptr, uchar *lumptr, int n);
+static void lumrow(const uchar *rgbptr, uchar *lumptr, int n);
/*
* byte order independent read/write of shorts and ints.
@@ -900,7 +900,7 @@ static int output_iris(uint *lptr, int xsize, int ysize, int zsize, const char *
/* static utility functions for output_iris */
-static void lumrow(uchar *rgbptr, uchar *lumptr, int n)
+static void lumrow(const uchar *rgbptr, uchar *lumptr, int n)
{
lumptr += CHANOFFSET(0);
while (n--) {
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 46d07e74ce3..6ed01c73f04 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -176,7 +176,7 @@ static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol)
}
/* float color -> rgbe */
-static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe)
+static void FLOAT2RGBE(const fCOLOR fcol, RGBE rgbe)
{
int e;
float d = (fcol[RED] > fcol[GRN]) ? fcol[RED] : fcol[GRN];
@@ -308,7 +308,8 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
}
/* ImBuf write */
-static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufscan, float *fpscan)
+static int fwritecolrs(
+ FILE *file, int width, int channels, const unsigned char *ibufscan, const float *fpscan)
{
int beg, c2, cnt = 0;
fCOLOR fcol;
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 309de25db03..715f2aaf621 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -81,14 +81,24 @@ typedef struct ImbTIFFMemFile {
* Function implementations. *
*****************************/
-static void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+static void imb_tiff_DummyUnmapProc(
+ thandle_t fd,
+ tdata_t base,
+ /* Cannot be const, because this function implements #TIFFUnmapFileProc.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ toff_t size)
{
(void)fd;
(void)base;
(void)size;
}
-static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t *pbase, toff_t *psize)
+static int imb_tiff_DummyMapProc(
+ thandle_t fd,
+ tdata_t *pbase,
+ /* Cannot be const, because this function implements #TIFFMapFileProc.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ toff_t *psize)
{
(void)fd;
(void)pbase;
@@ -100,7 +110,7 @@ static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t *pbase, toff_t *psize)
/**
* Reads data from an in-memory TIFF file.
*
- * \param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile).
+ * \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
* \param data: Buffer to contain data (treat as (void *)).
* \param n: Number of bytes to read.
*
diff --git a/source/blender/io/alembic/CMakeLists.txt b/source/blender/io/alembic/CMakeLists.txt
index da36272b850..681d6d04acd 100644
--- a/source/blender/io/alembic/CMakeLists.txt
+++ b/source/blender/io/alembic/CMakeLists.txt
@@ -63,8 +63,8 @@ set(SRC
exporter/abc_writer_camera.cc
exporter/abc_writer_curves.cc
exporter/abc_writer_hair.cc
- exporter/abc_writer_mesh.cc
exporter/abc_writer_mball.cc
+ exporter/abc_writer_mesh.cc
exporter/abc_writer_nurbs.cc
exporter/abc_writer_points.cc
exporter/abc_writer_transform.cc
@@ -89,8 +89,8 @@ set(SRC
exporter/abc_writer_camera.h
exporter/abc_writer_curves.h
exporter/abc_writer_hair.h
- exporter/abc_writer_mesh.h
exporter/abc_writer_mball.h
+ exporter/abc_writer_mesh.h
exporter/abc_writer_nurbs.h
exporter/abc_writer_points.h
exporter/abc_writer_transform.h
diff --git a/source/blender/io/alembic/exporter/abc_export_capi.cc b/source/blender/io/alembic/exporter/abc_export_capi.cc
index fbc5b2d5c02..98c551c635c 100644
--- a/source/blender/io/alembic/exporter/abc_export_capi.cc
+++ b/source/blender/io/alembic/exporter/abc_export_capi.cc
@@ -73,7 +73,12 @@ static void build_depsgraph(Depsgraph *depsgraph, Main *bmain)
DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
}
-static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
+static void export_startjob(void *customdata,
+ /* Cannot be const, this function implements wm_jobs_start_callback.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ short *stop,
+ short *do_update,
+ float *progress)
{
ExportJobData *data = static_cast<ExportJobData *>(customdata);
data->was_canceled = false;
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
index 90004c0e85b..c83eaf3eede 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
@@ -107,20 +107,23 @@ AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator::
determine_graph_index_object(const HierarchyContext *context)
{
if (params_.flatten_hierarchy) {
- return std::make_pair(nullptr, nullptr);
+ return ObjectIdentifier::for_graph_root();
}
return AbstractHierarchyIterator::determine_graph_index_object(context);
}
AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator::determine_graph_index_dupli(
- const HierarchyContext *context, const std::set<Object *> &dupli_set)
+ const HierarchyContext *context,
+ const DupliObject *dupli_object,
+ const DupliParentFinder &dupli_parent_finder)
{
if (params_.flatten_hierarchy) {
- return std::make_pair(nullptr, nullptr);
+ return ObjectIdentifier::for_graph_root();
}
- return AbstractHierarchyIterator::determine_graph_index_dupli(context, dupli_set);
+ return AbstractHierarchyIterator::determine_graph_index_dupli(
+ context, dupli_object, dupli_parent_finder);
}
Alembic::Abc::OObject ABCHierarchyIterator::get_alembic_parent(
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
index edcb31806ba..3fe2d2c43d2 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
@@ -67,7 +67,9 @@ class ABCHierarchyIterator : public AbstractHierarchyIterator {
virtual ExportGraph::key_type determine_graph_index_object(
const HierarchyContext *context) override;
virtual AbstractHierarchyIterator::ExportGraph::key_type determine_graph_index_dupli(
- const HierarchyContext *context, const std::set<Object *> &dupli_set) override;
+ const HierarchyContext *context,
+ const DupliObject *dupli_object,
+ const DupliParentFinder &dupli_parent_finder) override;
virtual AbstractHierarchyWriter *create_transform_writer(
const HierarchyContext *context) override;
diff --git a/source/blender/io/avi/intern/avi_mjpeg.c b/source/blender/io/avi/intern/avi_mjpeg.c
index 70ddca28060..75059c202e5 100644
--- a/source/blender/io/avi/intern/avi_mjpeg.c
+++ b/source/blender/io/avi/intern/avi_mjpeg.c
@@ -20,7 +20,7 @@
/** \file
* \ingroup avi
*
- * This is external code. Converts between avi and mpeg/jpeg.
+ * This is external code. Converts between AVI and MPEG/JPEG.
*/
#include <stdlib.h>
@@ -39,7 +39,9 @@
#include "avi_mjpeg.h"
static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, size_t bufsize);
-static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, size_t bufsize);
+static void jpegmemsrcmgr_build(j_decompress_ptr dinfo,
+ const unsigned char *buffer,
+ size_t bufsize);
static size_t numbytes;
@@ -381,7 +383,10 @@ static void deinterlace(int odd, unsigned char *to, unsigned char *from, int wid
}
}
-void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
+void *avi_converter_from_mjpeg(AviMovie *movie,
+ int stream,
+ unsigned char *buffer,
+ const size_t *size)
{
int deint;
unsigned char *buf;
@@ -553,7 +558,9 @@ static void jpegmemsrcmgr_term_source(j_decompress_ptr dinfo)
MEM_freeN(dinfo->src);
}
-static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, size_t bufsize)
+static void jpegmemsrcmgr_build(j_decompress_ptr dinfo,
+ const unsigned char *buffer,
+ size_t bufsize)
{
dinfo->src = MEM_mallocN(sizeof(*(dinfo->src)), "avi.jpegmemsrcmgr_build");
diff --git a/source/blender/io/avi/intern/avi_mjpeg.h b/source/blender/io/avi/intern/avi_mjpeg.h
index 30e46bf1d0c..13153fa41f0 100644
--- a/source/blender/io/avi/intern/avi_mjpeg.h
+++ b/source/blender/io/avi/intern/avi_mjpeg.h
@@ -24,7 +24,10 @@
#ifndef __AVI_MJPEG_H__
#define __AVI_MJPEG_H__
-void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
+void *avi_converter_from_mjpeg(AviMovie *movie,
+ int stream,
+ unsigned char *buffer,
+ const size_t *size);
void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
#endif /* __AVI_MJPEG_H__ */
diff --git a/source/blender/io/avi/intern/avi_rgb.c b/source/blender/io/avi/intern/avi_rgb.c
index 6f4f33d72d1..44542af96ae 100644
--- a/source/blender/io/avi/intern/avi_rgb.c
+++ b/source/blender/io/avi/intern/avi_rgb.c
@@ -37,7 +37,10 @@
/* implementation */
-void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size)
+void *avi_converter_from_avi_rgb(AviMovie *movie,
+ int stream,
+ unsigned char *buffer,
+ const size_t *size)
{
unsigned char *buf;
AviBitmapInfoHeader *bi;
diff --git a/source/blender/io/avi/intern/avi_rgb.h b/source/blender/io/avi/intern/avi_rgb.h
index 7c8ce590d27..3a37fad94e1 100644
--- a/source/blender/io/avi/intern/avi_rgb.h
+++ b/source/blender/io/avi/intern/avi_rgb.h
@@ -24,7 +24,10 @@
#ifndef __AVI_RGB_H__
#define __AVI_RGB_H__
-void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
+void *avi_converter_from_avi_rgb(AviMovie *movie,
+ int stream,
+ unsigned char *buffer,
+ const size_t *size);
void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size);
#endif /* __AVI_RGB_H__ */
diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp
index 3755b71f300..bd5bd913a18 100644
--- a/source/blender/io/collada/ArmatureImporter.cpp
+++ b/source/blender/io/collada/ArmatureImporter.cpp
@@ -969,8 +969,8 @@ void ArmatureImporter::make_shape_keys(bContext *C)
/* insert other shape keys */
for (int i = 0; i < morphTargetIds.getCount(); i++) {
- /* better to have a separate map of morph objects,
- * This'll do for now since only mesh morphing is imported */
+ /* Better to have a separate map of morph objects,
+ * This will do for now since only mesh morphing is imported. */
Mesh *me = this->mesh_importer->get_mesh_by_geom_uid(morphTargetIds[i]);
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index 495af60488b..9fbb7324f8f 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -205,7 +205,7 @@ MeshImporter::MeshImporter(
}
bool MeshImporter::set_poly_indices(
- MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
+ MPoly *mpoly, MLoop *mloop, int loop_index, const unsigned int *indices, int loop_count)
{
mpoly->loopstart = loop_index;
mpoly->totloop = loop_count;
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 2f2a18ff11a..18e56e8f9df 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -105,7 +105,7 @@ class MeshImporter : public MeshImporterBase {
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom;
bool set_poly_indices(
- MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count);
+ MPoly *mpoly, MLoop *mloop, int loop_index, const unsigned int *indices, int loop_count);
void set_face_uv(MLoopUV *mloopuv,
UVDataWrapper &uvs,
diff --git a/source/blender/io/collada/TransformWriter.cpp b/source/blender/io/collada/TransformWriter.cpp
index 0a66db72cb9..b7455837379 100644
--- a/source/blender/io/collada/TransformWriter.cpp
+++ b/source/blender/io/collada/TransformWriter.cpp
@@ -129,9 +129,9 @@ void TransformWriter::add_node_transform_identity(COLLADASW::Node &node,
}
void TransformWriter::add_transform(COLLADASW::Node &node,
- float loc[3],
- float rot[3],
- float scale[3])
+ const float loc[3],
+ const float rot[3],
+ const float scale[3])
{
node.addScale("scale", scale[0], scale[1], scale[2]);
node.addRotateZ("rotationZ", RAD2DEGF(rot[2]));
diff --git a/source/blender/io/collada/TransformWriter.h b/source/blender/io/collada/TransformWriter.h
index 3c71fc9d36e..db8ef3f5ee2 100644
--- a/source/blender/io/collada/TransformWriter.h
+++ b/source/blender/io/collada/TransformWriter.h
@@ -42,7 +42,10 @@ class TransformWriter {
void add_node_transform_identity(COLLADASW::Node &node, BCExportSettings &export_settings);
private:
- void add_transform(COLLADASW::Node &node, float loc[3], float rot[3], float scale[3]);
+ void add_transform(COLLADASW::Node &node,
+ const float loc[3],
+ const float rot[3],
+ const float scale[3]);
};
#endif
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index e74808df466..2c54a49198a 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -603,7 +603,7 @@ float BoneExtended::get_roll()
return this->roll;
}
-void BoneExtended::set_tail(float vec[])
+void BoneExtended::set_tail(const float vec[])
{
this->tail[0] = vec[0];
this->tail[1] = vec[1];
diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h
index b1ec2c8b81a..11a9376294b 100644
--- a/source/blender/io/collada/collada_utils.h
+++ b/source/blender/io/collada/collada_utils.h
@@ -343,7 +343,7 @@ class BoneExtended {
bool has_roll();
float get_roll();
- void set_tail(float vec[]);
+ void set_tail(const float vec[]);
float *get_tail();
bool has_tail();
diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index 4ed6f12762e..708f24ca0e2 100644
--- a/source/blender/io/common/CMakeLists.txt
+++ b/source/blender/io/common/CMakeLists.txt
@@ -31,8 +31,13 @@ set(INC_SYS
set(SRC
intern/abstract_hierarchy_iterator.cc
+ intern/dupli_parent_finder.cc
+ intern/dupli_persistent_id.cc
+ intern/object_identifier.cc
IO_abstract_hierarchy_iterator.h
+ IO_dupli_persistent_id.hh
+ intern/dupli_parent_finder.hh
)
set(LIB
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index 5f84fd48b71..2669f137fd4 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -36,6 +36,8 @@
#ifndef __ABSTRACT_HIERARCHY_ITERATOR_H__
#define __ABSTRACT_HIERARCHY_ITERATOR_H__
+#include "IO_dupli_persistent_id.hh"
+
#include <map>
#include <set>
#include <string>
@@ -52,6 +54,7 @@ namespace blender {
namespace io {
class AbstractHierarchyWriter;
+class DupliParentFinder;
/* HierarchyContext structs are created by the AbstractHierarchyIterator. Each HierarchyContext
* struct contains everything necessary to export a single object to a file. */
@@ -60,6 +63,7 @@ struct HierarchyContext {
Object *object; /* Evaluated object. */
Object *export_parent;
Object *duplicator;
+ PersistentID persistent_id;
float matrix_world[4][4];
std::string export_name;
@@ -161,6 +165,35 @@ class EnsuredWriter {
AbstractHierarchyWriter *operator->();
};
+/* Unique identifier for a (potentially duplicated) object.
+ *
+ * Instances of this class serve as key in the export graph of the
+ * AbstractHierarchyIterator. */
+class ObjectIdentifier {
+ public:
+ Object *object;
+ Object *duplicated_by; /* nullptr for real objects. */
+ PersistentID persistent_id;
+
+ protected:
+ ObjectIdentifier(Object *object, Object *duplicated_by, const PersistentID &persistent_id);
+
+ public:
+ ObjectIdentifier(const ObjectIdentifier &other);
+ ~ObjectIdentifier();
+
+ static ObjectIdentifier for_graph_root();
+ static ObjectIdentifier for_real_object(Object *object);
+ static ObjectIdentifier for_hierarchy_context(const HierarchyContext *context);
+ static ObjectIdentifier for_duplicated_object(const DupliObject *dupli_object,
+ Object *duplicated_by);
+
+ bool is_root() const;
+};
+
+bool operator<(const ObjectIdentifier &obj_ident_a, const ObjectIdentifier &obj_ident_b);
+bool operator==(const ObjectIdentifier &obj_ident_a, const ObjectIdentifier &obj_ident_b);
+
/* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export
* writers. These writers are then called to perform the actual writing to a USD or Alembic file.
*
@@ -172,14 +205,10 @@ class AbstractHierarchyIterator {
public:
/* Mapping from export path to writer. */
typedef std::map<std::string, AbstractHierarchyWriter *> WriterMap;
- /* Pair of a (potentially duplicated) object and its duplicator (or nullptr).
- * This is typically used to store a pair of HierarchyContext::object and
- * HierarchyContext::duplicator. */
- typedef std::pair<Object *, Object *> DupliAndDuplicator;
/* All the children of some object, as per the export hierarchy. */
typedef std::set<HierarchyContext *> ExportChildren;
/* Mapping from an object and its duplicator to the object's export-children. */
- typedef std::map<DupliAndDuplicator, ExportChildren> ExportGraph;
+ typedef std::map<ObjectIdentifier, ExportChildren> ExportGraph;
/* Mapping from ID to its export path. This is used for instancing; given an
* instanced datablock, the export path of the original can be looked up. */
typedef std::map<ID *, std::string> ExportPathMap;
@@ -237,7 +266,7 @@ class AbstractHierarchyIterator {
void visit_object(Object *object, Object *export_parent, bool weak_export);
void visit_dupli_object(DupliObject *dupli_object,
Object *duplicator,
- const std::set<Object *> &dupli_set);
+ const DupliParentFinder &dupli_parent_finder);
void context_update_for_graph_index(HierarchyContext *context,
const ExportGraph::key_type &graph_index) const;
@@ -291,8 +320,10 @@ class AbstractHierarchyIterator {
virtual bool should_visit_dupli_object(const DupliObject *dupli_object) const;
virtual ExportGraph::key_type determine_graph_index_object(const HierarchyContext *context);
- virtual ExportGraph::key_type determine_graph_index_dupli(const HierarchyContext *context,
- const std::set<Object *> &dupli_set);
+ virtual ExportGraph::key_type determine_graph_index_dupli(
+ const HierarchyContext *context,
+ const DupliObject *dupli_object,
+ const DupliParentFinder &dupli_parent_finder);
/* These functions should create an AbstractHierarchyWriter subclass instance, or return
* nullptr if the object or its data should not be exported. Returning a nullptr for
diff --git a/source/blender/io/common/IO_dupli_persistent_id.hh b/source/blender/io/common/IO_dupli_persistent_id.hh
new file mode 100644
index 00000000000..5dc54164684
--- /dev/null
+++ b/source/blender/io/common/IO_dupli_persistent_id.hh
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __IO_COMMON_DUPLI_PERSISTENT_ID_H__
+#define __IO_COMMON_DUPLI_PERSISTENT_ID_H__
+
+#include "BKE_duplilist.h"
+
+#include "DNA_object_types.h" /* For MAX_DUPLI_RECUR */
+
+#include <array>
+#include <optional>
+#include <ostream>
+
+namespace blender::io {
+
+/* Wrapper for DupliObject::persistent_id that can act as a map key. */
+class PersistentID {
+ protected:
+ constexpr static int array_length_ = MAX_DUPLI_RECUR;
+ typedef std::array<int, array_length_> PIDArray;
+ PIDArray persistent_id_;
+
+ explicit PersistentID(const PIDArray &persistent_id_values);
+
+ public:
+ PersistentID();
+ explicit PersistentID(const DupliObject *dupli_ob);
+
+ /* Return true iff the persistent IDs are the same, ignoring the first digit. */
+ bool is_from_same_instancer_as(const PersistentID &other) const;
+
+ /* Construct the persistent ID of this instance's instancer. */
+ PersistentID instancer_pid() const;
+
+ /* Construct a string representation by reversing the persistent ID.
+ * In case of a duplicator that is duplicated itself as well, this
+ * results in strings like:
+ * "3" for the duplicated duplicator, and
+ * "3-0", "3-1", etc. for its duplis. */
+ std::string as_object_name_suffix() const;
+
+ friend bool operator==(const PersistentID &persistent_id_a, const PersistentID &persistent_id_b);
+ friend bool operator<(const PersistentID &persistent_id_a, const PersistentID &persistent_id_b);
+ friend std::ostream &operator<<(std::ostream &os, const PersistentID &persistent_id);
+
+ private:
+ void copy_values_from(const PIDArray &persistent_id_values);
+};
+
+} // namespace blender::io
+
+#endif // __IO_COMMON_DUPLI_PARENT_FINDER_H__
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index dce6b8e178b..3622c1eb7cd 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -17,6 +17,7 @@
* All rights reserved.
*/
#include "IO_abstract_hierarchy_iterator.h"
+#include "dupli_parent_finder.hh"
#include <iostream>
#include <limits.h>
@@ -200,9 +201,9 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap
{
size_t total_graph_size = 0;
for (const ExportGraph::value_type &map_iter : graph) {
- const DupliAndDuplicator &parent_info = map_iter.first;
- Object *const export_parent = parent_info.first;
- Object *const duplicator = parent_info.second;
+ const ObjectIdentifier &parent_info = map_iter.first;
+ const Object *const export_parent = parent_info.object;
+ const Object *const duplicator = parent_info.duplicated_by;
if (duplicator != nullptr) {
printf(" DU %s (as dupped by %s):\n",
@@ -217,7 +218,7 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap
for (HierarchyContext *child_ctx : map_iter.second) {
if (child_ctx->duplicator == nullptr) {
printf(" - %s%s%s\n",
- child_ctx->object->id.name + 2,
+ child_ctx->export_name.c_str(),
child_ctx->weak_export ? " (weak)" : "",
child_ctx->original_export_path.empty() ?
"" :
@@ -225,7 +226,7 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap
}
else {
printf(" - %s (dup by %s%s) %s\n",
- child_ctx->object->id.name + 2,
+ child_ctx->export_name.c_str(),
child_ctx->duplicator->id.name + 2,
child_ctx->weak_export ? ", weak" : "",
child_ctx->original_export_path.empty() ?
@@ -234,7 +235,7 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap
}
}
}
- printf(" (Total graph size: %zu objects\n", total_graph_size);
+ printf(" (Total graph size: %zu objects)\n", total_graph_size);
}
void AbstractHierarchyIterator::export_graph_construct()
@@ -257,22 +258,21 @@ void AbstractHierarchyIterator::export_graph_construct()
// Export the duplicated objects instanced by this object.
ListBase *lb = object_duplilist(depsgraph_, scene, object);
if (lb) {
- // Construct the set of duplicated objects, so that later we can determine whether a parent
- // is also duplicated itself.
- std::set<Object *> dupli_set;
+ DupliParentFinder dupli_parent_finder;
+
LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
+ PersistentID persistent_id(dupli_object);
if (!should_visit_dupli_object(dupli_object)) {
continue;
}
- dupli_set.insert(dupli_object->ob);
+ dupli_parent_finder.insert(dupli_object);
}
LISTBASE_FOREACH (DupliObject *, dupli_object, lb) {
if (!should_visit_dupli_object(dupli_object)) {
continue;
}
-
- visit_dupli_object(dupli_object, object, dupli_set);
+ visit_dupli_object(dupli_object, object, dupli_parent_finder);
}
}
@@ -291,29 +291,30 @@ void AbstractHierarchyIterator::connect_loose_objects()
for (const ExportGraph::value_type &map_iter : export_graph_) {
for (const HierarchyContext *child : map_iter.second) {
// An object that is marked as a child of another object is not considered 'loose'.
- loose_objects_graph.erase(std::make_pair(child->object, child->duplicator));
+ ObjectIdentifier child_oid = ObjectIdentifier::for_hierarchy_context(child);
+ loose_objects_graph.erase(child_oid);
}
}
// The root of the hierarchy is always found, so it's never considered 'loose'.
- loose_objects_graph.erase(std::make_pair(nullptr, nullptr));
+ loose_objects_graph.erase(ObjectIdentifier::for_graph_root());
// Iterate over the loose objects and connect them to their export parent.
for (const ExportGraph::value_type &map_iter : loose_objects_graph) {
- const DupliAndDuplicator &export_info = map_iter.first;
- Object *object = export_info.first;
+ const ObjectIdentifier &graph_key = map_iter.first;
+ Object *object = graph_key.object;
while (true) {
// Loose objects will all be real objects, as duplicated objects always have
// their duplicator or other exported duplicated object as ancestor.
ExportGraph::iterator found_parent_iter = export_graph_.find(
- std::make_pair(object->parent, nullptr));
+ ObjectIdentifier::for_real_object(object->parent));
visit_object(object, object->parent, true);
if (found_parent_iter != export_graph_.end()) {
break;
}
// 'object->parent' will never be nullptr here, as the export graph contains the
- // tuple <nullptr, nullptr> as root and thus will cause a break.
+ // root as nullptr and thus will cause a break above.
BLI_assert(object->parent != nullptr);
object = object->parent;
@@ -326,10 +327,8 @@ static bool remove_weak_subtrees(const HierarchyContext *context,
const AbstractHierarchyIterator::ExportGraph &input_graph)
{
bool all_is_weak = context != nullptr && context->weak_export;
- Object *object = context != nullptr ? context->object : nullptr;
- Object *duplicator = context != nullptr ? context->duplicator : nullptr;
+ const ObjectIdentifier map_key = ObjectIdentifier::for_hierarchy_context(context);
- const AbstractHierarchyIterator::DupliAndDuplicator map_key = std::make_pair(object, duplicator);
AbstractHierarchyIterator::ExportGraph::const_iterator child_iterator;
child_iterator = input_graph.find(map_key);
@@ -399,7 +398,7 @@ void AbstractHierarchyIterator::visit_object(Object *object,
// check on whether an object is part of the export, rather than having to check all objects in
// the map. Note that it's not possible to simply search for (object->parent, nullptr), as the
// object's parent in Blender may not be the same as its export-parent.
- ExportGraph::key_type object_key = std::make_pair(object, nullptr);
+ ExportGraph::key_type object_key = ObjectIdentifier::for_real_object(object);
if (export_graph_.find(object_key) == export_graph_.end()) {
export_graph_[object_key] = ExportChildren();
}
@@ -408,16 +407,17 @@ void AbstractHierarchyIterator::visit_object(Object *object,
AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
determine_graph_index_object(const HierarchyContext *context)
{
- return std::make_pair(context->export_parent, nullptr);
+ return ObjectIdentifier::for_real_object(context->export_parent);
}
void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
Object *duplicator,
- const std::set<Object *> &dupli_set)
+ const DupliParentFinder &dupli_parent_finder)
{
HierarchyContext *context = new HierarchyContext();
context->object = dupli_object->ob;
context->duplicator = duplicator;
+ context->persistent_id = PersistentID(dupli_object);
context->weak_export = false;
context->export_path = "";
context->original_export_path = "";
@@ -427,38 +427,36 @@ void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
copy_m4_m4(context->matrix_world, dupli_object->mat);
// Construct export name for the dupli-instance.
- std::stringstream suffix_stream;
- suffix_stream << std::hex;
- for (int i = 0; i < MAX_DUPLI_RECUR && dupli_object->persistent_id[i] != INT_MAX; i++) {
- suffix_stream << "-" << dupli_object->persistent_id[i];
- }
- context->export_name = make_valid_name(get_object_name(context->object) + suffix_stream.str());
+ std::stringstream export_name_stream;
+ export_name_stream << get_object_name(context->object) << "-"
+ << context->persistent_id.as_object_name_suffix();
+ context->export_name = make_valid_name(export_name_stream.str());
- ExportGraph::key_type graph_index = determine_graph_index_dupli(context, dupli_set);
+ ExportGraph::key_type graph_index = determine_graph_index_dupli(
+ context, dupli_object, dupli_parent_finder);
context_update_for_graph_index(context, graph_index);
+
export_graph_[graph_index].insert(context);
}
AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
determine_graph_index_dupli(const HierarchyContext *context,
- const std::set<Object *> &dupli_set)
+ const DupliObject *dupli_object,
+ const DupliParentFinder &dupli_parent_finder)
{
- /* If the dupli-object's parent is also instanced by this object, use that as the
- * export parent. Otherwise use the dupli-parent as export parent. */
+ const DupliObject *dupli_parent = dupli_parent_finder.find_suitable_export_parent(dupli_object);
- Object *parent = context->object->parent;
- if (parent != nullptr && dupli_set.find(parent) != dupli_set.end()) {
- // The parent object is part of the duplicated collection.
- return std::make_pair(parent, context->duplicator);
+ if (dupli_parent != nullptr) {
+ return ObjectIdentifier::for_duplicated_object(dupli_parent, context->duplicator);
}
- return std::make_pair(context->duplicator, nullptr);
+ return ObjectIdentifier::for_real_object(context->duplicator);
}
void AbstractHierarchyIterator::context_update_for_graph_index(
HierarchyContext *context, const ExportGraph::key_type &graph_index) const
{
// Update the HierarchyContext so that it is consistent with the graph index.
- context->export_parent = graph_index.first;
+ context->export_parent = graph_index.object;
if (context->export_parent != context->object->parent) {
/* The parent object in Blender is NOT used as the export parent. This means
* that the world transform of this object can be influenced by objects that
@@ -470,11 +468,7 @@ void AbstractHierarchyIterator::context_update_for_graph_index(
AbstractHierarchyIterator::ExportChildren &AbstractHierarchyIterator::graph_children(
const HierarchyContext *context)
{
- if (context == nullptr) {
- return export_graph_[std::make_pair(nullptr, nullptr)];
- }
-
- return export_graph_[std::make_pair(context->object, context->duplicator)];
+ return export_graph_[ObjectIdentifier::for_hierarchy_context(context)];
}
void AbstractHierarchyIterator::determine_export_paths(const HierarchyContext *parent_context)
diff --git a/source/blender/io/common/intern/dupli_parent_finder.cc b/source/blender/io/common/intern/dupli_parent_finder.cc
new file mode 100644
index 00000000000..73e33eff164
--- /dev/null
+++ b/source/blender/io/common/intern/dupli_parent_finder.cc
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "dupli_parent_finder.hh"
+
+#include "BLI_utildefines.h"
+
+#include <iostream>
+
+namespace blender::io {
+
+DupliParentFinder::DupliParentFinder()
+{
+}
+
+DupliParentFinder::~DupliParentFinder()
+{
+}
+
+void DupliParentFinder::insert(const DupliObject *dupli_ob)
+{
+ dupli_set_.insert(dupli_ob->ob);
+
+ PersistentID dupli_pid(dupli_ob);
+ pid_to_dupli_[dupli_pid] = dupli_ob;
+ instancer_pid_to_duplis_[dupli_pid.instancer_pid()].insert(dupli_ob);
+}
+
+bool DupliParentFinder::is_duplicated(const Object *object) const
+{
+ return dupli_set_.find(object) != dupli_set_.end();
+}
+
+const DupliObject *DupliParentFinder::find_suitable_export_parent(
+ const DupliObject *dupli_ob) const
+{
+ if (dupli_ob->ob->parent != nullptr) {
+ const DupliObject *parent = find_duplicated_parent(dupli_ob);
+ if (parent != nullptr) {
+ return parent;
+ }
+ }
+
+ return find_instancer(dupli_ob);
+}
+
+const DupliObject *DupliParentFinder::find_duplicated_parent(const DupliObject *dupli_ob) const
+{
+ const PersistentID dupli_pid(dupli_ob);
+ PersistentID parent_pid = dupli_pid.instancer_pid();
+
+ const Object *parent_ob = dupli_ob->ob->parent;
+ BLI_assert(parent_ob != nullptr);
+
+ InstancerPIDToDuplisMap::const_iterator found = instancer_pid_to_duplis_.find(parent_pid);
+ if (found == instancer_pid_to_duplis_.end()) {
+ /* Unexpected, as there should be at least one entry here, for the dupli_ob itself. */
+ return nullptr;
+ }
+
+ for (const DupliObject *potential_parent_dupli : found->second) {
+ if (potential_parent_dupli->ob != parent_ob) {
+ continue;
+ }
+
+ PersistentID potential_parent_pid(potential_parent_dupli);
+ if (potential_parent_pid.is_from_same_instancer_as(dupli_pid)) {
+ return potential_parent_dupli;
+ }
+ }
+ return nullptr;
+}
+
+const DupliObject *DupliParentFinder::find_instancer(const DupliObject *dupli_ob) const
+{
+ PersistentID dupli_pid(dupli_ob);
+ PersistentID parent_pid = dupli_pid.instancer_pid();
+
+ PIDToDupliMap::const_iterator found = pid_to_dupli_.find(parent_pid);
+ if (found == pid_to_dupli_.end()) {
+ return nullptr;
+ }
+
+ const DupliObject *instancer_dupli = found->second;
+ return instancer_dupli;
+}
+
+} // namespace blender::io
diff --git a/source/blender/io/common/intern/dupli_parent_finder.hh b/source/blender/io/common/intern/dupli_parent_finder.hh
new file mode 100644
index 00000000000..e7e628665ee
--- /dev/null
+++ b/source/blender/io/common/intern/dupli_parent_finder.hh
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+#ifndef __IO_COMMON_DUPLI_PARENT_FINDER_H__
+#define __IO_COMMON_DUPLI_PARENT_FINDER_H__
+
+#include "IO_dupli_persistent_id.hh"
+
+#include "BKE_duplilist.h"
+
+#include <map>
+#include <set>
+
+namespace blender::io {
+
+/* Find relations between duplicated objects. This class should be instanced for a single real
+ * object, and fed its dupli-objects. */
+class DupliParentFinder final {
+ private:
+ /* To check whether an Object * is instanced by this duplicator. */
+ std::set<const Object *> dupli_set_;
+
+ /* To find the DupliObject given its Persistent ID. */
+ typedef std::map<const PersistentID, const DupliObject *> PIDToDupliMap;
+ PIDToDupliMap pid_to_dupli_;
+
+ /* Mapping from instancer PID to duplis instanced by it. */
+ typedef std::map<const PersistentID, std::set<const DupliObject *>> InstancerPIDToDuplisMap;
+ InstancerPIDToDuplisMap instancer_pid_to_duplis_;
+
+ public:
+ DupliParentFinder();
+ ~DupliParentFinder();
+
+ void insert(const DupliObject *dupli_ob);
+
+ bool is_duplicated(const Object *object) const;
+ const DupliObject *find_suitable_export_parent(const DupliObject *dupli_ob) const;
+
+ private:
+ const DupliObject *find_duplicated_parent(const DupliObject *dupli_ob) const;
+ const DupliObject *find_instancer(const DupliObject *dupli_ob) const;
+};
+
+} // namespace blender::io
+
+#endif \ No newline at end of file
diff --git a/source/blender/io/common/intern/dupli_persistent_id.cc b/source/blender/io/common/intern/dupli_persistent_id.cc
new file mode 100644
index 00000000000..b40cd83ef44
--- /dev/null
+++ b/source/blender/io/common/intern/dupli_persistent_id.cc
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "dupli_parent_finder.hh"
+
+#include <climits>
+#include <cstring>
+#include <ostream>
+#include <sstream>
+
+namespace blender::io {
+
+PersistentID::PersistentID()
+{
+ persistent_id_[0] = INT_MAX;
+}
+
+PersistentID::PersistentID(const DupliObject *dupli_ob)
+{
+ for (int index = 0; index < array_length_; ++index) {
+ persistent_id_[index] = dupli_ob->persistent_id[index];
+ }
+}
+
+PersistentID::PersistentID(const PIDArray &persistent_id_values)
+{
+ persistent_id_ = persistent_id_values;
+}
+
+bool PersistentID::is_from_same_instancer_as(const PersistentID &other) const
+{
+ if (persistent_id_[0] == INT_MAX || other.persistent_id_[0] == INT_MAX) {
+ /* Either one or the other is not instanced at all, so definitely not from the same instancer.
+ */
+ return false;
+ }
+
+ /* Start at index 1 to skip the first digit. */
+ for (int index = 1; index < array_length_; ++index) {
+ const int pid_digit_a = persistent_id_[index];
+ const int pid_digit_b = other.persistent_id_[index];
+
+ if (pid_digit_a != pid_digit_b) {
+ return false;
+ }
+
+ if (pid_digit_a == INT_MAX) {
+ /* Both persistent IDs were identical so far, and this marks the end of the useful data. */
+ break;
+ }
+ }
+ return true;
+}
+
+PersistentID PersistentID::instancer_pid() const
+{
+ if (persistent_id_[0] == INT_MAX) {
+ return PersistentID();
+ }
+
+ /* Left-shift the entire PID by 1. */
+ PIDArray new_pid_values;
+ int index;
+ for (index = 0; index < array_length_ - 1; ++index) {
+ new_pid_values[index] = persistent_id_[index + 1];
+ }
+ new_pid_values[index] = INT_MAX;
+
+ return PersistentID(new_pid_values);
+}
+
+std::string PersistentID::as_object_name_suffix() const
+{
+ std::stringstream stream;
+
+ /* Find one past the last index. */
+ int index;
+ for (index = 0; index < array_length_ && persistent_id_[index] < INT_MAX; ++index) {
+ ;
+ }
+
+ /* Iterate backward to construct the string. */
+ --index;
+ for (; index >= 0; --index) {
+ stream << persistent_id_[index];
+ if (index > 0) {
+ stream << "-";
+ }
+ }
+
+ return stream.str();
+}
+
+bool operator<(const PersistentID &persistent_id_a, const PersistentID &persistent_id_b)
+{
+ const PersistentID::PIDArray &pid_a = persistent_id_a.persistent_id_;
+ const PersistentID::PIDArray &pid_b = persistent_id_b.persistent_id_;
+
+ for (int index = 0; index < PersistentID::array_length_; ++index) {
+ const int pid_digit_a = pid_a[index];
+ const int pid_digit_b = pid_b[index];
+
+ if (pid_digit_a != pid_digit_b) {
+ return pid_digit_a < pid_digit_b;
+ }
+
+ if (pid_a[index] == INT_MAX) {
+ break;
+ }
+ }
+ /* Both Persistent IDs were equal, so not less-than. */
+ return false;
+}
+
+bool operator==(const PersistentID &persistent_id_a, const PersistentID &persistent_id_b)
+{
+ const PersistentID::PIDArray &pid_a = persistent_id_a.persistent_id_;
+ const PersistentID::PIDArray &pid_b = persistent_id_b.persistent_id_;
+
+ for (int index = 0; index < PersistentID::array_length_; ++index) {
+ const int pid_digit_a = pid_a[index];
+ const int pid_digit_b = pid_b[index];
+
+ if (pid_digit_a != pid_digit_b) {
+ return false;
+ }
+
+ if (pid_a[index] == INT_MAX) {
+ break;
+ }
+ }
+ return true;
+}
+
+std::ostream &operator<<(std::ostream &os, const PersistentID &persistent_id)
+{
+ if (persistent_id.persistent_id_[0] == INT_MAX) {
+ return os;
+ }
+
+ const PersistentID::PIDArray &pid_array = persistent_id.persistent_id_;
+ for (int index = 0; index < PersistentID::array_length_ && pid_array[index] < INT_MAX; ++index) {
+ if (index > 0) {
+ os << "-";
+ }
+ os << pid_array[index];
+ }
+ return os;
+}
+
+} // namespace blender::io
diff --git a/source/blender/io/common/intern/object_identifier.cc b/source/blender/io/common/intern/object_identifier.cc
new file mode 100644
index 00000000000..696bc5d2c34
--- /dev/null
+++ b/source/blender/io/common/intern/object_identifier.cc
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "IO_abstract_hierarchy_iterator.h"
+
+#include "BKE_duplilist.h"
+
+extern "C" {
+#include <limits.h> /* For INT_MAX. */
+}
+#include <cstring>
+#include <sstream>
+
+namespace blender {
+namespace io {
+
+ObjectIdentifier::ObjectIdentifier(Object *object,
+ Object *duplicated_by,
+ const PersistentID &persistent_id)
+ : object(object), duplicated_by(duplicated_by), persistent_id(persistent_id)
+{
+}
+
+ObjectIdentifier::ObjectIdentifier(const ObjectIdentifier &other)
+ : object(other.object), duplicated_by(other.duplicated_by), persistent_id(other.persistent_id)
+{
+}
+
+ObjectIdentifier::~ObjectIdentifier()
+{
+}
+
+ObjectIdentifier ObjectIdentifier::for_real_object(Object *object)
+{
+ return ObjectIdentifier(object, nullptr, PersistentID());
+}
+
+ObjectIdentifier ObjectIdentifier::for_hierarchy_context(const HierarchyContext *context)
+{
+ if (context == nullptr) {
+ return for_graph_root();
+ }
+ if (context->duplicator != nullptr) {
+ return ObjectIdentifier(context->object, context->duplicator, context->persistent_id);
+ }
+ return for_real_object(context->object);
+}
+
+ObjectIdentifier ObjectIdentifier::for_duplicated_object(const DupliObject *dupli_object,
+ Object *duplicated_by)
+{
+ return ObjectIdentifier(dupli_object->ob, duplicated_by, PersistentID(dupli_object));
+}
+
+ObjectIdentifier ObjectIdentifier::for_graph_root()
+{
+ return ObjectIdentifier(nullptr, nullptr, PersistentID());
+}
+
+bool ObjectIdentifier::is_root() const
+{
+ return object == nullptr;
+}
+
+bool operator<(const ObjectIdentifier &obj_ident_a, const ObjectIdentifier &obj_ident_b)
+{
+ if (obj_ident_a.object != obj_ident_b.object) {
+ return obj_ident_a.object < obj_ident_b.object;
+ }
+
+ if (obj_ident_a.duplicated_by != obj_ident_b.duplicated_by) {
+ return obj_ident_a.duplicated_by < obj_ident_b.duplicated_by;
+ }
+
+ if (obj_ident_a.duplicated_by == nullptr) {
+ /* Both are real objects, no need to check the persistent ID. */
+ return false;
+ }
+
+ /* Same object, both are duplicated, use the persistent IDs to determine order. */
+ return obj_ident_a.persistent_id < obj_ident_b.persistent_id;
+}
+
+bool operator==(const ObjectIdentifier &obj_ident_a, const ObjectIdentifier &obj_ident_b)
+{
+ if (obj_ident_a.object != obj_ident_b.object) {
+ return false;
+ }
+ if (obj_ident_a.duplicated_by != obj_ident_b.duplicated_by) {
+ return false;
+ }
+ if (obj_ident_a.duplicated_by == nullptr) {
+ return true;
+ }
+
+ /* Same object, both are duplicated, use the persistent IDs to determine equality. */
+ return obj_ident_a.persistent_id == obj_ident_b.persistent_id;
+}
+
+} // namespace io
+} // namespace blender
diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc
index 2d3972410a4..98aef62f38e 100644
--- a/source/blender/io/usd/intern/usd_capi.cc
+++ b/source/blender/io/usd/intern/usd_capi.cc
@@ -59,7 +59,12 @@ struct ExportJobData {
bool export_ok;
};
-static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
+static void export_startjob(void *customdata,
+ /* Cannot be const, this function implements wm_jobs_start_callback.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ short *stop,
+ short *do_update,
+ float *progress)
{
ExportJobData *data = static_cast<ExportJobData *>(customdata);
data->export_ok = false;
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 4056faf359f..0ad249ef2cd 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -343,6 +343,12 @@ typedef enum eBrushPoseOriginType {
BRUSH_POSE_ORIGIN_FACE_SETS_FK = 2,
} eBrushPoseOriginType;
+typedef enum eBrushSmearDeformType {
+ BRUSH_SMEAR_DEFORM_DRAG = 0,
+ BRUSH_SMEAR_DEFORM_PINCH = 1,
+ BRUSH_SMEAR_DEFORM_EXPAND = 2,
+} eBrushSmearDeformType;
+
/* Gpencilsettings.Vertex_mode */
typedef enum eGp_Vertex_Mode {
/* Affect to Stroke only. */
@@ -500,7 +506,7 @@ typedef struct Brush {
char gpencil_sculpt_tool;
/** Active grease pencil weight tool. */
char gpencil_weight_tool;
- char _pad1[2];
+ char _pad1[6];
float autosmooth_factor;
@@ -555,6 +561,9 @@ typedef struct Brush {
/* multiplane scrape */
float multiplane_scrape_angle;
+ /* smear */
+ int smear_deform_type;
+
/* overlay */
int texture_overlay_alpha;
int mask_overlay_alpha;
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index b54ff7ccc17..909170523a3 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -471,9 +471,10 @@ typedef struct FluidDomainSettings {
int res_max[3]; /* Cell max. */
int res[3]; /* Data resolution (res_max-res_min). */
int total_cells;
- float dx; /* 1.0f / res. */
- float scale; /* Largest domain size. */
- int boundary_width; /* Usually this is just 1. */
+ float dx; /* 1.0f / res. */
+ float scale; /* Largest domain size. */
+ int boundary_width; /* Usually this is just 1. */
+ float gravity_final[3]; /* Scene or domain gravity multiplied with gravity weight. */
/* -- User-accesible fields (from here on). -- */
@@ -481,7 +482,6 @@ typedef struct FluidDomainSettings {
int adapt_margin;
int adapt_res;
float adapt_threshold;
- char _pad1[4]; /* Unused. */
/* Fluid domain options */
int maxres; /* Longest axis on the BB gets this resolution assigned. */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 60ad0eae576..50b4739e09f 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2146,7 +2146,7 @@ typedef struct SimulationModifierData {
ModifierData modifier;
struct Simulation *simulation;
- char data_path[64];
+ char *data_path;
} SimulationModifierData;
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 993aad92564..42ccbc657d8 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -845,14 +845,15 @@ typedef struct NodeTexSky {
float turbidity;
float ground_albedo;
float sun_size;
+ float sun_intensity;
float sun_elevation;
float sun_rotation;
- int altitude;
+ float altitude;
float air_density;
float dust_density;
float ozone_density;
char sun_disc;
- char _pad[3];
+ char _pad[7];
} NodeTexSky;
typedef struct NodeTexImage {
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index 93ba9c425f0..a2b81b731d3 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -31,7 +31,7 @@ typedef struct Simulation {
struct bNodeTree *nodetree;
int flag;
- int _pad;
+ float current_frame;
/** List containing SimulationState objects. */
struct ListBase states;
@@ -41,23 +41,19 @@ typedef struct SimulationState {
struct SimulationState *next;
struct SimulationState *prev;
- /** This is only initialized on cow copies of the simulation. It points to the state on the
- * original data block. That is where the cache is stored. */
- struct SimulationState *orig_state;
-
/** eSimulationStateType */
int type;
int _pad;
- char name[64];
+ char *name;
} SimulationState;
typedef struct ParticleSimulationState {
SimulationState head;
- /** Contains the state of the particles at time current_frame. */
- float current_frame;
+ /** Contains the state of the particles at time Simulation->current_frame. */
int tot_particles;
+ int _pad;
struct CustomData attributes;
/** Caches the state of the particles over time. The cache only exists on the original data
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 1cb42b333c7..0892eff6de9 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1148,8 +1148,9 @@ typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_17 = (1 << 17), /* cleared */
SI_FLAG_UNUSED_18 = (1 << 18), /* cleared */
- /* this means that the image is drawn until it reaches the view edge,
- * in the image view, it's unrelated to the 'tile' mode for texface
+ /**
+ * This means that the image is drawn until it reaches the view edge,
+ * in the image view, it's unrelated to UDIM tiles.
*/
SI_DRAW_TILE = (1 << 19),
SI_SMOOTH_UV = (1 << 20),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index d751ad9ac47..8ea4d3b6476 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -622,8 +622,9 @@ typedef struct UserDef_Experimental {
char use_new_particle_system;
char use_new_hair_type;
char use_cycles_debug;
+ char use_sculpt_vertex_colors;
/** `makesdna` does not allow empty structs. */
- char _pad0[4];
+ char _pad[3];
} UserDef_Experimental;
#define USER_EXPERIMENTAL_TEST(userdef, member) \
@@ -1160,6 +1161,8 @@ typedef enum eDupli_ID_Flags {
USER_DUP_OBJECT = (1 << 24),
/* USER_DUP_COLLECTION = (1 << 25), */ /* UNUSED, keep because we may implement. */
+ /* Duplicate (and hence make local) linked data. */
+ USER_DUP_LINKED_ID = (1 << 30),
} eDupli_ID_Flags;
/**
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index ef174f5858f..4bb32fedd1d 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -191,6 +191,7 @@ typedef struct View3DShading {
int render_pass;
struct IDProperty *prop;
+ void *_pad2;
} View3DShading;
/** 3D Viewport Overlay settings. */
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index f9198194a89..dff07f515b1 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -51,12 +51,10 @@ typedef struct World {
float horr, horg, horb;
/**
- * Exposure= mult factor. unused now, but maybe back later. Kept in to be upward compat.
- * New is exp/range control. linfac & logfac are constants... don't belong in
- * file, but allocating 8 bytes for temp mem isn't useful either.
+ * Exposure is a multiplication factor. Unused now, but maybe back later.
+ * Kept in to be upward compatible.
*/
float exposure, exp, range;
- float linfac, logfac;
/**
* Some world modes
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 9c2ee00a900..c2f1e204073 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -69,6 +69,7 @@ set(DEFSRC
rna_packedfile.c
rna_palette.c
rna_particle.c
+ rna_pointcloud.c
rna_pose.c
rna_render.c
rna_rigidbody.c
@@ -82,7 +83,6 @@ set(DEFSRC
rna_sound.c
rna_space.c
rna_speaker.c
- rna_pointcloud.c
rna_test.c
rna_text.c
rna_texture.c
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 46001f27fef..8d498ab569b 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -518,7 +518,7 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
{
- if (!BKE_lib_override_library_is_enabled() || !ID_IS_OVERRIDABLE_LIBRARY(id)) {
+ if (!ID_IS_OVERRIDABLE_LIBRARY(id)) {
return NULL;
}
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 79cf993e0cc..793552c5c34 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -558,9 +558,15 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_double_array,
};
-static void *rna_idproperty_check_ex(PropertyRNA **prop,
- PointerRNA *ptr,
- const bool return_rnaprop)
+/* This function initializes a PropertyRNAOrID with all required info, from a given PropertyRNA
+ * and PointerRNA data. It deals properly with the three cases (static RNA, runtime RNA, and
+ * IDProperty).
+ * WARNING: given `ptr` PointerRNA is assumed to be a valid data one here, calling code is
+ * responsible to ensure that.
+ */
+void rna_property_rna_or_id_get(PropertyRNA *prop,
+ PointerRNA *ptr,
+ PropertyRNAOrID *r_prop_rna_or_id)
{
/* This is quite a hack, but avoids some complexity in the API. we
* pass IDProperty structs as PropertyRNA pointers to the outside.
@@ -568,36 +574,64 @@ static void *rna_idproperty_check_ex(PropertyRNA **prop,
* distinguish it from IDProperty structs. If it is an ID property,
* we look up an IDP PropertyRNA based on the type, and set the data
* pointer to the IDProperty. */
+ memset(r_prop_rna_or_id, 0, sizeof(*r_prop_rna_or_id));
- if ((*prop)->magic == RNA_MAGIC) {
- if ((*prop)->flag & PROP_IDPROPERTY) {
- IDProperty *idprop = rna_idproperty_find(ptr, (*prop)->identifier);
+ r_prop_rna_or_id->ptr = *ptr;
+ r_prop_rna_or_id->rawprop = prop;
+
+ if (prop->magic == RNA_MAGIC) {
+ r_prop_rna_or_id->rnaprop = prop;
+ r_prop_rna_or_id->identifier = prop->identifier;
- if (idprop && !rna_idproperty_verify_valid(ptr, *prop, idprop)) {
+ r_prop_rna_or_id->is_array = prop->getlength || prop->totarraylength;
+ if (r_prop_rna_or_id->is_array) {
+ int arraylen[RNA_MAX_ARRAY_DIMENSION];
+ r_prop_rna_or_id->array_len = (prop->getlength && ptr->data) ?
+ (uint)prop->getlength(ptr, arraylen) :
+ prop->totarraylength;
+ }
+
+ if (prop->flag & PROP_IDPROPERTY) {
+ IDProperty *idprop = rna_idproperty_find(ptr, prop->identifier);
+
+ if (idprop != NULL && !rna_idproperty_verify_valid(ptr, prop, idprop)) {
IDProperty *group = RNA_struct_idprops(ptr, 0);
IDP_FreeFromGroup(group, idprop);
- return NULL;
+ idprop = NULL;
}
- return idprop;
+ r_prop_rna_or_id->idprop = idprop;
+ r_prop_rna_or_id->is_set = idprop != NULL && (idprop->flag & IDP_FLAG_GHOST) == 0;
}
else {
- return return_rnaprop ? *prop : NULL;
+ /* Full static RNA properties are always set. */
+ r_prop_rna_or_id->is_set = true;
}
}
+ else {
+ IDProperty *idprop = (IDProperty *)prop;
+ /* Given prop may come from the custom properties of another data, ensure we get the one from
+ * given data ptr. */
+ IDProperty *idprop_evaluated = rna_idproperty_find(ptr, idprop->name);
+ if (idprop_evaluated != NULL && idprop->type != idprop_evaluated->type) {
+ idprop_evaluated = NULL;
+ }
- {
- IDProperty *idprop = (IDProperty *)(*prop);
+ r_prop_rna_or_id->idprop = idprop_evaluated;
+ r_prop_rna_or_id->is_idprop = true;
+ /* Full IDProperties are always set, if it exists. */
+ r_prop_rna_or_id->is_set = (idprop_evaluated != NULL);
+ r_prop_rna_or_id->identifier = idprop->name;
if (idprop->type == IDP_ARRAY) {
- *prop = arraytypemap[(int)(idprop->subtype)];
+ r_prop_rna_or_id->rnaprop = arraytypemap[(int)(idprop->subtype)];
+ r_prop_rna_or_id->is_array = true;
+ r_prop_rna_or_id->array_len = idprop_evaluated != NULL ? (uint)idprop_evaluated->len : 0;
}
else {
- *prop = typemap[(int)(idprop->type)];
+ r_prop_rna_or_id->rnaprop = typemap[(int)(idprop->type)];
}
-
- return idprop;
}
}
@@ -605,14 +639,26 @@ static void *rna_idproperty_check_ex(PropertyRNA **prop,
* or NULL (in case IDProp could not be found, or prop is a real RNA property). */
IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
{
- return rna_idproperty_check_ex(prop, ptr, false);
+ PropertyRNAOrID prop_rna_or_id;
+
+ rna_property_rna_or_id_get(*prop, ptr, &prop_rna_or_id);
+
+ *prop = prop_rna_or_id.rnaprop;
+ return prop_rna_or_id.idprop;
}
/* This function always return the valid, real data pointer, be it a regular RNA property one,
* or an IDProperty one. */
PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
{
- return rna_idproperty_check_ex(prop, ptr, true);
+ PropertyRNAOrID prop_rna_or_id;
+
+ rna_property_rna_or_id_get(*prop, ptr, &prop_rna_or_id);
+
+ *prop = prop_rna_or_id.rnaprop;
+ return (prop_rna_or_id.is_idprop || prop_rna_or_id.idprop != NULL) ?
+ (PropertyRNA *)prop_rna_or_id.idprop :
+ prop_rna_or_id.rnaprop;
}
PropertyRNA *rna_ensure_property(PropertyRNA *prop)
@@ -2102,9 +2148,7 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
return false;
}
if (ID_IS_OVERRIDE_LIBRARY(id)) {
- /* We need the real data property in case of IDProperty here... */
- PropertyRNA *real_prop = rna_ensure_property_realdata(&prop, ptr);
- if (real_prop == NULL || !RNA_property_overridable_get(ptr, real_prop)) {
+ if (!RNA_property_overridable_get(ptr, prop)) {
if (!(*r_info)[0]) {
*r_info = N_("Can't edit this property from an override data-block");
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 8cd8f80b7c8..1b846fd898c 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -177,16 +177,13 @@ bool RNA_property_copy(
}
static int rna_property_override_diff(Main *bmain,
- PointerRNA *ptr_a,
- PointerRNA *ptr_b,
- PropertyRNA *prop,
- PropertyRNA *prop_a,
- PropertyRNA *prop_b,
+ PropertyRNAOrID *prop_a,
+ PropertyRNAOrID *prop_b,
const char *rna_path,
const size_t rna_path_len,
eRNACompareMode mode,
IDOverrideLibrary *override,
- const int flags,
+ const eRNAOverrideMatch flags,
eRNAOverrideMatchResult *r_report_flags);
bool RNA_property_equals(
@@ -194,8 +191,12 @@ bool RNA_property_equals(
{
BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
- return (rna_property_override_diff(
- bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, 0, mode, NULL, 0, NULL) == 0);
+ PropertyRNAOrID prop_a, prop_b;
+
+ rna_property_rna_or_id_get(prop, ptr_a, &prop_a);
+ rna_property_rna_or_id_get(prop, ptr_b, &prop_b);
+
+ return (rna_property_override_diff(bmain, &prop_a, &prop_b, NULL, 0, mode, NULL, 0, NULL) == 0);
}
bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
@@ -247,59 +248,42 @@ bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACo
* but we cannot determine an order (greater than/lesser than), we return 1.
*/
static int rna_property_override_diff(Main *bmain,
- PointerRNA *ptr_a,
- PointerRNA *ptr_b,
- PropertyRNA *prop,
- PropertyRNA *prop_a,
- PropertyRNA *prop_b,
+ PropertyRNAOrID *prop_a,
+ PropertyRNAOrID *prop_b,
const char *rna_path,
const size_t rna_path_len,
eRNACompareMode mode,
IDOverrideLibrary *override,
- const int flags,
+ const eRNAOverrideMatch flags,
eRNAOverrideMatchResult *r_report_flags)
{
- if (prop != NULL) {
- BLI_assert(prop_a == NULL && prop_b == NULL);
- prop_a = prop;
- prop_b = prop;
- }
-
- if (ELEM(NULL, prop_a, prop_b)) {
- return (prop_a == prop_b) ? 0 : 1;
- }
+ BLI_assert(!ELEM(NULL, prop_a, prop_b));
- if (!RNA_property_comparable(ptr_a, prop_a) || !RNA_property_comparable(ptr_b, prop_b)) {
+ if (prop_a->rnaprop->flag_override & PROPOVERRIDE_NO_COMPARISON ||
+ prop_b->rnaprop->flag_override & PROPOVERRIDE_NO_COMPARISON) {
return 0;
}
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
- /* uninitialized properties are assumed to match anything */
- if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) {
+ /* Unset properties are assumed to match anything. */
+ if (!prop_a->is_set || !prop_b->is_set) {
return 0;
}
}
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
- /* unset properties never match set properties */
- if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) {
+ /* Unset properties never match set properties. */
+ if (prop_a->is_set != prop_b->is_set) {
return 1;
}
}
- if (prop != NULL) {
- /* Ensure we get real property data, be it an actual RNA property,
- * or an IDProperty in disguise. */
- prop_a = rna_ensure_property_realdata(&prop_a, ptr_a);
- prop_b = rna_ensure_property_realdata(&prop_b, ptr_b);
-
- if (ELEM(NULL, prop_a, prop_b)) {
- return (prop_a == prop_b) ? 0 : 1;
- }
+ if (prop_a->is_idprop && ELEM(NULL, prop_a->idprop, prop_b->idprop)) {
+ return (prop_a->idprop == prop_b->idprop) ? 0 : 1;
}
/* Check if we are working with arrays. */
- const bool is_array_a = RNA_property_array_check(prop_a);
- const bool is_array_b = RNA_property_array_check(prop_b);
+ const bool is_array_a = prop_a->is_array;
+ const bool is_array_b = prop_b->is_array;
if (is_array_a != is_array_b) {
/* Should probably never happen actually... */
@@ -308,8 +292,8 @@ static int rna_property_override_diff(Main *bmain,
}
/* Get the length of the array to work with. */
- const int len_a = RNA_property_array_length(ptr_a, prop_a);
- const int len_b = RNA_property_array_length(ptr_b, prop_b);
+ const uint len_a = prop_a->array_len;
+ const uint len_b = prop_b->array_len;
if (len_a != len_b) {
/* Do not handle override in that case,
@@ -324,47 +308,44 @@ static int rna_property_override_diff(Main *bmain,
RNAPropOverrideDiff override_diff = NULL;
/* Special case for IDProps, we use default callback then. */
- if (prop_a->magic != RNA_MAGIC) {
+ if (prop_a->is_idprop) {
override_diff = rna_property_override_diff_default;
- if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) {
+ if (!prop_b->is_idprop && prop_b->rnaprop->override_diff != override_diff) {
override_diff = NULL;
}
}
- else if (prop_b->magic != RNA_MAGIC) {
+ else if (prop_b->is_idprop) {
override_diff = rna_property_override_diff_default;
- if (prop_a->override_diff != override_diff) {
+ if (prop_a->rnaprop->override_diff != override_diff) {
override_diff = NULL;
}
}
- else if (prop_a->override_diff == prop_b->override_diff) {
- override_diff = prop_a->override_diff;
+ else if (prop_a->rnaprop->override_diff == prop_b->rnaprop->override_diff) {
+ override_diff = prop_a->rnaprop->override_diff;
+ if (override_diff == NULL) {
+ override_diff = rna_property_override_diff_default;
+ }
}
if (override_diff == NULL) {
#ifndef NDEBUG
printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
- rna_path ?
- rna_path :
- (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier),
- prop_a->magic == RNA_MAGIC,
- prop_b->magic == RNA_MAGIC);
+ rna_path ? rna_path : prop_a->identifier,
+ !prop_a->is_idprop,
+ !prop_b->is_idprop);
#endif
BLI_assert(0);
return 1;
}
bool override_changed = false;
- int diff_flags = flags;
- if (!RNA_property_overridable_get(ptr_a, prop_a)) {
+ eRNAOverrideMatch diff_flags = flags;
+ if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop)) {
diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
}
const int diff = override_diff(bmain,
- ptr_a,
- ptr_b,
prop_a,
prop_b,
- len_a,
- len_b,
mode,
override,
rna_path,
@@ -426,10 +407,13 @@ static bool rna_property_override_operation_store(Main *bmain,
}
else if (prop_local->override_store == prop_reference->override_store) {
override_store = prop_local->override_store;
+ if (override_store == NULL) {
+ override_store = rna_property_override_store_default;
+ }
}
if (ptr_storage != NULL && prop_storage->magic == RNA_MAGIC &&
- prop_storage->override_store != override_store) {
+ !ELEM(prop_storage->override_store, NULL, override_store)) {
override_store = NULL;
}
@@ -512,10 +496,13 @@ static bool rna_property_override_operation_apply(Main *bmain,
}
else if (prop_dst->override_apply == prop_src->override_apply) {
override_apply = prop_dst->override_apply;
+ if (override_apply == NULL) {
+ override_apply = rna_property_override_apply_default;
+ }
}
if (ptr_storage && prop_storage->magic == RNA_MAGIC &&
- prop_storage->override_apply != override_apply) {
+ !ELEM(prop_storage->override_apply, NULL, override_apply)) {
override_apply = NULL;
}
@@ -612,38 +599,29 @@ bool RNA_struct_override_matches(Main *bmain,
for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid;
RNA_property_collection_next(&iter)) {
- PropertyRNA *prop_local = iter.ptr.data;
- PropertyRNA *prop_reference = iter.ptr.data;
-
- /* Ensure we get real property data, be it an actual RNA property,
- * or an IDProperty in disguise. */
- prop_local = rna_ensure_property_realdata(&prop_local, ptr_local);
- prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference);
-
- /* IDProps (custom properties) are even more of a PITA here, we cannot use
- * `rna_ensure_property_realdata()` to deal with them, we have to use the path generated from
- * `prop_local` (which is valid) to access to the actual reference counterpart... */
- if (prop_local != NULL && prop_local->magic != RNA_MAGIC && prop_local == prop_reference) {
- /* We could also use (lower in this code, after rna_path has been computed):
- * RNA_path_resolve_property(ptr_reference, rna_path, &some_rna_ptr, &prop_reference);
- * But that would be much more costly, and would also fail when ptr_reference
- * is not an ID pointer itself, so we'd need to rebuild it from its owner_id, then check that
- * generated some_rna_ptr and ptr_reference do point to the same data, etc.
- * For now, let's try that simple access, it won't cover all cases but should handle fine
- * most basic custom properties situations. */
- prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference,
- ((IDProperty *)prop_local)->name);
- }
+ PropertyRNA *rawprop = iter.ptr.data;
+
+ PropertyRNAOrID prop_local;
+ PropertyRNAOrID prop_reference;
+
+ rna_property_rna_or_id_get(rawprop, ptr_local, &prop_local);
+ rna_property_rna_or_id_get(rawprop, ptr_reference, &prop_reference);
- if (ELEM(NULL, prop_local, prop_reference)) {
+ BLI_assert(prop_local.rnaprop != NULL);
+ BLI_assert(prop_local.rnaprop == prop_reference.rnaprop);
+ BLI_assert(prop_local.is_idprop == prop_reference.is_idprop);
+
+ if ((prop_local.is_idprop && prop_local.idprop == NULL) ||
+ (prop_reference.is_idprop && prop_reference.idprop == NULL)) {
continue;
}
- if (ignore_non_overridable && !RNA_property_overridable_get(ptr_local, prop_local)) {
+ if (ignore_non_overridable && !RNA_property_overridable_get(&prop_local.ptr, rawprop)) {
continue;
}
- if (RNA_property_override_flag(prop_local) & PROPOVERRIDE_IGNORE) {
+ if (!prop_local.is_idprop &&
+ RNA_property_override_flag(prop_local.rnaprop) & PROPOVERRIDE_IGNORE) {
continue;
}
@@ -665,11 +643,11 @@ bool RNA_struct_override_matches(Main *bmain,
if (root_path) {
BLI_assert(strlen(root_path) == root_path_len);
- const char *prop_name = RNA_property_identifier(prop_local);
+ const char *prop_name = prop_local.identifier;
const size_t prop_name_len = strlen(prop_name);
/* Inlined building, much much more efficient. */
- if (prop_local->magic == RNA_MAGIC) {
+ if (!prop_local.is_idprop) {
rna_path_len = root_path_len + 1 + prop_name_len;
if (rna_path_len >= RNA_PATH_BUFFSIZE) {
rna_path = MEM_mallocN(rna_path_len + 1, __func__);
@@ -697,7 +675,7 @@ bool RNA_struct_override_matches(Main *bmain,
}
else {
/* This is rather slow, but is not much called, so not really worth optimizing. */
- rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local);
+ rna_path = RNA_path_from_ID_to_property(ptr_local, rawprop);
if (rna_path != NULL) {
rna_path_len = strlen(rna_path);
}
@@ -726,11 +704,8 @@ bool RNA_struct_override_matches(Main *bmain,
eRNAOverrideMatchResult report_flags = 0;
const int diff = rna_property_override_diff(bmain,
- ptr_local,
- ptr_reference,
- NULL,
- prop_local,
- prop_reference,
+ &prop_local,
+ &prop_reference,
rna_path,
rna_path_len,
RNA_EQ_STRICT,
@@ -764,7 +739,7 @@ bool RNA_struct_override_matches(Main *bmain,
/* We are allowed to restore to reference's values. */
if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
/* We should restore that property to its reference value */
- if (RNA_property_editable(ptr_local, prop_local)) {
+ if (RNA_property_editable(ptr_local, rawprop)) {
IDOverrideLibraryPropertyOperation opop_tmp = {
.operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
.subitem_reference_index = -1,
@@ -774,8 +749,8 @@ bool RNA_struct_override_matches(Main *bmain,
ptr_local,
ptr_reference,
NULL,
- prop_local,
- prop_reference,
+ rawprop,
+ rawprop,
NULL,
NULL,
NULL,
@@ -1202,10 +1177,6 @@ eRNAOverrideStatus RNA_property_override_library_status(PointerRNA *ptr,
{
uint override_status = 0;
- if (!BKE_lib_override_library_is_enabled()) {
- return override_status;
- }
-
if (!ptr || !prop || !ptr->owner_id || !ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) {
return override_status;
}
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
index c7995746d08..a5b554ec7a6 100644
--- a/source/blender/makesrna/intern/rna_access_internal.h
+++ b/source/blender/makesrna/intern/rna_access_internal.h
@@ -26,8 +26,11 @@
#include "rna_internal_types.h"
struct IDProperty;
+struct PropertyRNAOrID;
-PropertyRNA *rna_ensure_property(PropertyRNA *prop);
+void rna_property_rna_or_id_get(PropertyRNA *prop,
+ PointerRNA *ptr,
+ PropertyRNAOrID *r_prop_rna_or_id);
void rna_idproperty_touch(struct IDProperty *idprop);
struct IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index b139e4609cd..b4703ab9aa2 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1997,6 +1997,13 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_smear_deform_type_items[] = {
+ {BRUSH_SMEAR_DEFORM_DRAG, "DRAG", 0, "Drag", ""},
+ {BRUSH_SMEAR_DEFORM_PINCH, "PINCH", 0, "Pinch", ""},
+ {BRUSH_SMEAR_DEFORM_EXPAND, "EXPAND", 0, "Expand", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(
srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
@@ -2117,6 +2124,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "smear_deform_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_smear_deform_type_items);
+ RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "pose_deform_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, brush_pose_deform_type_items);
RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index ca34f69ab1e..da1ed166eb2 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -551,7 +551,7 @@ static void rna_def_depsgraph_instance(BlenderRNA *brna)
prop,
"Persistent ID",
"Persistent identifier for inter-frame matching of objects with motion blur");
- RNA_def_property_array(prop, 2 * MAX_DUPLI_RECUR);
+ RNA_def_property_array(prop, MAX_DUPLI_RECUR);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_DepsgraphObjectInstance_persistent_id_get", NULL, NULL);
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index ab0cc6def6f..3387958c2f6 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -161,7 +161,7 @@ static void rna_Fluid_flow_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
rna_Fluid_update(bmain, scene, ptr);
}
-static void rna_Fluid_domain_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_domain_data_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
# ifdef WITH_FLUID
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
@@ -172,6 +172,39 @@ static void rna_Fluid_domain_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
rna_Fluid_update(bmain, scene, ptr);
}
+static void rna_Fluid_domain_noise_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_modifier_reset(settings->fmd);
+# endif
+
+ rna_Fluid_noisecache_reset(bmain, scene, ptr);
+ rna_Fluid_update(bmain, scene, ptr);
+}
+
+static void rna_Fluid_domain_mesh_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_modifier_reset(settings->fmd);
+# endif
+
+ rna_Fluid_meshcache_reset(bmain, scene, ptr);
+ rna_Fluid_update(bmain, scene, ptr);
+}
+
+static void rna_Fluid_domain_particles_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_modifier_reset(settings->fmd);
+# endif
+
+ rna_Fluid_particlescache_reset(bmain, scene, ptr);
+ rna_Fluid_update(bmain, scene, ptr);
+}
+
static void rna_Fluid_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
{
# ifdef WITH_FLUID
@@ -232,7 +265,7 @@ static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *p
if (fmd->domain->type != FLUID_DOMAIN_TYPE_LIQUID) {
rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP);
fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
- rna_Fluid_domain_reset(bmain, scene, ptr);
+ rna_Fluid_domain_data_reset(bmain, scene, ptr);
return;
}
@@ -1350,7 +1383,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_data_reset");
/* fluid domain options */
@@ -1364,7 +1397,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Resolution used for the fluid domain. Value corresponds to the longest domain side "
"(resolution for other domain sides is calculated automatically)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_data_reset");
prop = RNA_def_property(srna, "use_collision_border_front", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_FRONT);
@@ -1547,7 +1580,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"The noise simulation is scaled up by this factor (compared to the "
"base resolution of the domain)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_noise_reset");
prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "noise_type");
@@ -1555,7 +1588,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Noise Method", "Noise method which is used during the high-res simulation");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_noise_reset");
prop = RNA_def_property(srna, "use_noise", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_NOISE);
@@ -1569,7 +1602,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "simulation_method");
RNA_def_property_enum_items(prop, simulation_methods);
RNA_def_property_ui_text(prop, "Simulation Method", "Change the underlying simulation method");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_data_reset");
prop = RNA_def_property(srna, "flip_ratio", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
@@ -1657,7 +1690,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Use Diffusion", "Enable fluid diffusion settings (e.g. viscosity, surface tension)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "surface_tension", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 100.0);
@@ -1724,7 +1757,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"resolution of the domain). For best meshing, it is recommended to "
"adjust the mesh particle radius alongside this value");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_mesh_reset");
prop = RNA_def_property(srna, "mesh_generator", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mesh_generator");
@@ -1924,7 +1957,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"The particle simulation is scaled up by this factor (compared to the "
"base resolution of the domain)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_particles_reset");
prop = RNA_def_property(srna, "use_spray_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_SPRAY);
@@ -2081,7 +2114,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, cache_types);
RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_cachetype_set", NULL);
RNA_def_property_ui_text(prop, "Type", "Change the cache type of the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_domain_data_reset");
prop = RNA_def_property(srna, "cache_resumable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_RESUMABLE_CACHE);
@@ -2158,7 +2191,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"only needed if you plan to analyze the cache (e.g. view grids, velocity vectors, "
"particles) in Mantaflow directly (outside of Blender) after baking the simulation");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_data_reset");
/* time options */
@@ -2655,7 +2688,7 @@ static void rna_def_fluid_effector_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_EFFECTOR_USE_PLANE_INIT);
RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_data_reset");
prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_multi");
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 1c39ad3a1a8..9519e3e1433 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -1817,8 +1817,7 @@ static void rna_def_modifier_gpencilmirror(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MirrorGpencilModifier", "GpencilModifier");
- RNA_def_struct_ui_text(
- srna, "Mirror Modifier", "Change stroke using lattice to deform modifier");
+ RNA_def_struct_ui_text(srna, "Mirror Modifier", "Create mirroring strokes");
RNA_def_struct_sdna(srna, "MirrorGpencilModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 0783addd78b..a8085c00cb3 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -23,6 +23,8 @@
#include "BLI_utildefines.h"
+#include "BLI_compiler_attrs.h"
+
#include "rna_internal_types.h"
#include "UI_resources.h"
@@ -478,9 +480,11 @@ extern StructRNA RNA_PropertyGroupItem;
extern StructRNA RNA_PropertyGroup;
#endif
-struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr);
+struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop,
+ struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop,
- struct PointerRNA *ptr);
+ struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
+struct PropertyRNA *rna_ensure_property(struct PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT;
/* Override default callbacks. */
/* Default override callbacks for all types. */
@@ -489,12 +493,8 @@ struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop,
* Not obvious though, those are fairly more complicated than basic SDNA access.
*/
int rna_property_override_diff_default(struct Main *bmain,
- struct PointerRNA *ptr_a,
- struct PointerRNA *ptr_b,
- struct PropertyRNA *prop_a,
- struct PropertyRNA *prop_b,
- const int len_a,
- const int len_b,
+ struct PropertyRNAOrID *prop_a,
+ struct PropertyRNAOrID *prop_b,
const int mode,
struct IDOverrideLibrary *override,
const char *rna_path,
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 345d84fc5b1..20c8743f768 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -41,6 +41,8 @@ struct Scene;
struct StructRNA;
struct bContext;
+typedef struct IDProperty IDProperty;
+
/* store local properties here */
#define RNA_IDP_UI "_RNA_UI"
@@ -155,24 +157,55 @@ typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *pr
/* Handling override operations, and also comparison. */
+/** Structure storing all needed data to process all three kinds of RNA properties. */
+typedef struct PropertyRNAOrID {
+ PointerRNA ptr;
+
+ /** The PropertyRNA passed as parameter, used to generate that structure's content:
+ * - Static RNA: The RNA property (same as `rnaprop`), never NULL.
+ * - Runtime RNA: The RNA property (same as `rnaprop`), never NULL.
+ * - IDProperty: The IDProperty, never NULL.
+ */
+ PropertyRNA *rawprop;
+ /** The real RNA property of this property, never NULL:
+ * - Static RNA: The rna property, also gives direct access to the data (from any matching
+ * PointerRNA).
+ * - Runtime RNA: The rna property, does not directly gives access to the data.
+ * - IDProperty: The generic PropertyRNA matching its type.
+ */
+ PropertyRNA *rnaprop;
+ /** The IDProperty storing the data of this property, may be NULL:
+ * - Static RNA: Always NULL.
+ * - Runtime RNA: The IDProperty storing the data of that property, may be NULL if never set yet.
+ * - IDProperty: The IDProperty, never NULL.
+ */
+ IDProperty *idprop;
+ /** The name of the property. */
+ const char *identifier;
+
+ /** Whether this property is a 'pure' IDProperty or not. */
+ bool is_idprop;
+ /** For runtime RNA properties, whether it is set, defined, or not.
+ * WARNING: This DOES take into account the `IDP_FLAG_GHOST` flag, i.e. it matches result of
+ * `RNA_property_is_set`. */
+ bool is_set;
+
+ bool is_array;
+ uint array_len;
+} PropertyRNAOrID;
+
/**
- * If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b,
+ * If \a override is NULL, merely do comparison between prop_a and prop_b,
* following comparison mode given.
* If \a override and \a rna_path are not NULL, it will add a new override operation for
* overridable properties that differ and have not yet been overridden
* (and set accordingly \a r_override_changed if given).
*
- * \note Given PropertyRNA are final (in case of IDProps...).
- * \note In non-array cases, \a len values are 0.
* \note \a override, \a rna_path and \a r_override_changed may be NULL pointers.
*/
typedef int (*RNAPropOverrideDiff)(struct Main *bmain,
- struct PointerRNA *ptr_a,
- struct PointerRNA *ptr_b,
- struct PropertyRNA *prop_a,
- struct PropertyRNA *prop_b,
- const int len_a,
- const int len_b,
+ struct PropertyRNAOrID *prop_a,
+ struct PropertyRNAOrID *prop_b,
const int mode,
struct IDOverrideLibrary *override,
const char *rna_path,
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index b99457056fe..e7a898b97ae 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -458,7 +458,7 @@ static void rna_def_layer_objects(BlenderRNA *brna, PropertyRNA *cprop)
NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
RNA_def_property_ui_text(prop, "Active Object", "Active object for this layer");
- /* Could call: ED_object_base_activate(C, rl->basact);
+ /* Could call: `ED_object_base_activate(C, view_layer->basact);`
* but would be a bad level call and it seems the notifier is enough */
RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL);
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 1670e08325f..97702b06b6f 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -410,7 +410,7 @@ void RNA_def_main(BlenderRNA *brna)
srna = RNA_def_struct(brna, "BlendData", NULL);
RNA_def_struct_ui_text(srna,
- "Blendfile Data",
+ "Blend-file Data",
"Main data structure representing a .blend file and all its data-blocks");
RNA_def_struct_ui_icon(srna, ICON_BLENDER);
@@ -436,7 +436,7 @@ void RNA_def_main(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_autopack", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Main_use_autopack_get", "rna_Main_use_autopack_set");
RNA_def_property_ui_text(
- prop, "Use Autopack", "Automatically pack all external data into .blend file");
+ prop, "Use Auto-pack", "Automatically pack all external data into .blend file");
prop = RNA_def_int_vector(srna,
"version",
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index eab7326868b..eb1a09f9c76 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1639,6 +1639,40 @@ static void rna_SimulationModifier_simulation_update(Main *bmain, Scene *scene,
rna_Modifier_dependency_update(bmain, scene, ptr);
}
+static void rna_SimulationModifier_data_path_get(PointerRNA *ptr, char *value)
+{
+ SimulationModifierData *smd = ptr->data;
+
+ if (smd->data_path) {
+ strcpy(value, smd->data_path);
+ }
+ else {
+ value[0] = '\0';
+ }
+}
+
+static int rna_SimulationModifier_data_path_length(PointerRNA *ptr)
+{
+ SimulationModifierData *smd = ptr->data;
+ return smd->data_path ? strlen(smd->data_path) : 0;
+}
+
+static void rna_SimulationModifier_data_path_set(PointerRNA *ptr, const char *value)
+{
+ SimulationModifierData *smd = ptr->data;
+
+ if (smd->data_path) {
+ MEM_freeN(smd->data_path);
+ }
+
+ if (value[0]) {
+ smd->data_path = BLI_strdup(value);
+ }
+ else {
+ smd->data_path = NULL;
+ }
+}
+
/**
* Special set callback that just changes the first bit of the expansion flag.
* This way the expansion state of all the sub-panels is not changed by RNA.
@@ -1654,6 +1688,17 @@ static void rna_Modifier_show_expanded_set(PointerRNA *ptr, bool value)
}
}
+/**
+ * Only check the first bit of the expansion flag for the main panel's expansion,
+ * maintaining compatibility with older versions where there was only one expansion
+ * value.
+ */
+static bool rna_Modifier_show_expanded_get(PointerRNA *ptr)
+{
+ ModifierData *md = ptr->data;
+ return md->ui_expand_flag & (1 << 0);
+}
+
#else
/* NOTE: *MUST* return subdivision_type property. */
@@ -6859,6 +6904,10 @@ static void rna_def_modifier_simulation(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_SimulationModifier_simulation_update");
prop = RNA_def_property(srna, "data_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_SimulationModifier_data_path_get",
+ "rna_SimulationModifier_data_path_length",
+ "rna_SimulationModifier_data_path_set");
RNA_def_property_ui_text(
prop, "Data Path", "Identifier of the simulation component that should be accessed");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -6921,7 +6970,8 @@ void RNA_def_modifier(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Modifier_show_expanded_set");
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Modifier_show_expanded_get", "rna_Modifier_show_expanded_set");
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 6312c84cf9f..332108facb3 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -4421,7 +4421,7 @@ static void def_sh_tex_sky(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "sky_model");
RNA_def_property_enum_items(prop, prop_sky_type);
RNA_def_property_ui_text(prop, "Sky Type", "Which sky model should be used");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "sun_direction", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_ui_text(prop, "Sun Direction", "Direction from where the sun is shining");
@@ -4445,7 +4445,7 @@ static void def_sh_tex_sky(StructRNA *srna)
RNA_def_property_ui_text(prop, "Sun Disc", "Include the sun itself in the output");
RNA_def_property_boolean_sdna(prop, NULL, "sun_disc", 1);
RNA_def_property_boolean_default(prop, true);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "sun_size", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_ui_text(prop, "Sun Size", "Size of sun disc (angular diameter)");
@@ -4453,6 +4453,12 @@ static void def_sh_tex_sky(StructRNA *srna)
RNA_def_property_float_default(prop, DEG2RADF(0.545));
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ prop = RNA_def_property(srna, "sun_intensity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Sun Intensity", "Strength of sun");
+ RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
prop = RNA_def_property(srna, "sun_elevation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_ui_text(prop, "Sun Elevation", "Angle between sun and horizon");
RNA_def_property_range(prop, -M_PI_2, M_PI_2);
@@ -4461,14 +4467,13 @@ static void def_sh_tex_sky(StructRNA *srna)
prop = RNA_def_property(srna, "sun_rotation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_ui_text(prop, "Sun Rotation", "Rotation of sun around zenith");
- RNA_def_property_range(prop, 0.0f, 2.0f * M_PI);
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
- prop = RNA_def_property(srna, "altitude", PROP_INT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Altitude", "Altitude height from sea level in meters");
- RNA_def_property_range(prop, 0, 60000);
- RNA_def_property_int_default(prop, 0);
+ prop = RNA_def_property(srna, "altitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Altitude", "Height from sea level in km");
+ RNA_def_property_range(prop, 0.0f, 60.0f);
+ RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "air_density", PROP_FLOAT, PROP_FACTOR);
@@ -8361,6 +8366,8 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_NodeSocket_node_get", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "Node");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Node", "Node owning this socket");
/* NB: the type property is used by standard sockets.
@@ -9316,6 +9323,8 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "parent");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_parent_set", NULL, "rna_Node_parent_poll");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_struct_type(prop, "Node");
RNA_def_property_ui_text(prop, "Parent", "Parent this node is attached to");
@@ -9530,29 +9539,39 @@ static void rna_def_node_link(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "fromnode");
RNA_def_property_struct_type(prop, "Node");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "From node", "");
prop = RNA_def_property(srna, "to_node", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tonode");
RNA_def_property_struct_type(prop, "Node");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "To node", "");
prop = RNA_def_property(srna, "from_socket", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "fromsock");
RNA_def_property_struct_type(prop, "NodeSocket");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "From socket", "");
prop = RNA_def_property(srna, "to_socket", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tosock");
RNA_def_property_struct_type(prop, "NodeSocket");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "To socket", "");
prop = RNA_def_property(srna, "is_hidden", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_NodeLink_is_hidden_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Is Hidden", "Link is hidden due to invisible sockets");
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 089410ffd25..00d3a6e84b7 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -1579,7 +1579,8 @@ static void rna_Object_modifier_remove(Object *object,
PointerRNA *md_ptr)
{
ModifierData *md = md_ptr->data;
- if (ED_object_modifier_remove(reports, CTX_data_main(C), object, md) == false) {
+ if (ED_object_modifier_remove(reports, CTX_data_main(C), CTX_data_scene(C), object, md) ==
+ false) {
/* error is already set */
return;
}
@@ -1591,7 +1592,7 @@ static void rna_Object_modifier_remove(Object *object,
static void rna_Object_modifier_clear(Object *object, bContext *C)
{
- ED_object_modifier_clear(CTX_data_main(C), object);
+ ED_object_modifier_clear(CTX_data_main(C), CTX_data_scene(C), object);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
}
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 0b932f3236f..2524f590051 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -851,7 +851,7 @@ static void rna_CollisionSettings_dependency_update(Main *bmain, Scene *scene, P
ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Collision);
}
else if (!ob->pd->deflect && md) {
- ED_object_modifier_remove(NULL, bmain, ob, md);
+ ED_object_modifier_remove(NULL, bmain, scene, ob, md);
}
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 623b5864f5b..f9f6defb2f1 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -479,7 +479,7 @@ static StructRNA *rna_Property_refine(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr); /* XXX ptr? */
+ prop = rna_ensure_property(prop);
switch (prop->type) {
case PROP_BOOLEAN:
@@ -504,90 +504,90 @@ static StructRNA *rna_Property_refine(PointerRNA *ptr)
static void rna_Property_identifier_get(PointerRNA *ptr, char *value)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
strcpy(value, ((PropertyRNA *)prop)->identifier);
}
static int rna_Property_identifier_length(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return strlen(prop->identifier);
}
static void rna_Property_name_get(PointerRNA *ptr, char *value)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
strcpy(value, prop->name ? prop->name : "");
}
static int rna_Property_name_length(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return prop->name ? strlen(prop->name) : 0;
}
static void rna_Property_description_get(PointerRNA *ptr, char *value)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
strcpy(value, prop->description ? prop->description : "");
}
static int rna_Property_description_length(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return prop->description ? strlen(prop->description) : 0;
}
static void rna_Property_translation_context_get(PointerRNA *ptr, char *value)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
strcpy(value, prop->translation_context);
}
static int rna_Property_translation_context_length(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return strlen(prop->translation_context);
}
static int rna_Property_type_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return prop->type;
}
static int rna_Property_subtype_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return prop->subtype;
}
static PointerRNA rna_Property_srna_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return rna_pointer_inherit_refine(ptr, &RNA_Struct, prop->srna);
}
static int rna_Property_unit_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return RNA_SUBTYPE_UNIT(prop->subtype);
}
static int rna_Property_icon_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return prop->icon;
}
@@ -698,7 +698,7 @@ static const EnumPropertyItem *rna_Property_tags_itemf(bContext *UNUSED(C),
static int rna_Property_array_length_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return prop->totarraylength;
}
@@ -706,7 +706,7 @@ static void rna_Property_array_dimensions_get(PointerRNA *ptr,
int dimensions[RNA_MAX_ARRAY_DIMENSION])
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
if (prop->arraydimension > 1) {
for (int i = RNA_MAX_ARRAY_DIMENSION; i--;) {
@@ -740,14 +740,14 @@ static bool rna_Property_is_runtime_get(PointerRNA *ptr)
static bool rna_BoolProperty_default_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((BoolPropertyRNA *)prop)->defaultvalue;
}
static int rna_IntProperty_default_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((IntPropertyRNA *)prop)->defaultvalue;
}
/* int/float/bool */
@@ -755,7 +755,7 @@ static int rna_NumberProperty_default_array_get_length(PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
length[0] = prop->totarraylength;
@@ -771,7 +771,7 @@ static bool rna_NumberProperty_is_array_get(PointerRNA *ptr)
static void rna_IntProperty_default_array_get(PointerRNA *ptr, int *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
if (prop->totarraylength > 0) {
PointerRNA null_ptr = PointerRNA_NULL;
RNA_property_int_get_default_array(&null_ptr, prop, values);
@@ -781,7 +781,7 @@ static void rna_IntProperty_default_array_get(PointerRNA *ptr, int *values)
static void rna_BoolProperty_default_array_get(PointerRNA *ptr, bool *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
if (prop->totarraylength > 0) {
PointerRNA null_ptr = PointerRNA_NULL;
RNA_property_boolean_get_default_array(&null_ptr, prop, values);
@@ -791,7 +791,7 @@ static void rna_BoolProperty_default_array_get(PointerRNA *ptr, bool *values)
static void rna_FloatProperty_default_array_get(PointerRNA *ptr, float *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
if (prop->totarraylength > 0) {
PointerRNA null_ptr = PointerRNA_NULL;
RNA_property_float_get_default_array(&null_ptr, prop, values);
@@ -801,103 +801,103 @@ static void rna_FloatProperty_default_array_get(PointerRNA *ptr, float *values)
static int rna_IntProperty_hard_min_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((IntPropertyRNA *)prop)->hardmin;
}
static int rna_IntProperty_hard_max_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((IntPropertyRNA *)prop)->hardmax;
}
static int rna_IntProperty_soft_min_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((IntPropertyRNA *)prop)->softmin;
}
static int rna_IntProperty_soft_max_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((IntPropertyRNA *)prop)->softmax;
}
static int rna_IntProperty_step_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((IntPropertyRNA *)prop)->step;
}
static float rna_FloatProperty_default_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->defaultvalue;
}
static float rna_FloatProperty_hard_min_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->hardmin;
}
static float rna_FloatProperty_hard_max_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->hardmax;
}
static float rna_FloatProperty_soft_min_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->softmin;
}
static float rna_FloatProperty_soft_max_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->softmax;
}
static float rna_FloatProperty_step_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->step;
}
static int rna_FloatProperty_precision_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((FloatPropertyRNA *)prop)->precision;
}
static void rna_StringProperty_default_get(PointerRNA *ptr, char *value)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
strcpy(value, ((StringPropertyRNA *)prop)->defaultvalue);
}
static int rna_StringProperty_default_length(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return strlen(((StringPropertyRNA *)prop)->defaultvalue);
}
static int rna_StringProperty_max_length_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((StringPropertyRNA *)prop)->maxlength;
}
@@ -909,7 +909,7 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C,
PropertyRNA *prop = (PropertyRNA *)ptr->data;
EnumPropertyRNA *eprop;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
eprop = (EnumPropertyRNA *)prop;
/* incompatible default attributes */
@@ -931,7 +931,7 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C,
static int rna_EnumProperty_default_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return ((EnumPropertyRNA *)prop)->defaultvalue;
}
@@ -950,7 +950,7 @@ static void rna_EnumProperty_items_begin(CollectionPropertyIterator *iter, Point
int totitem;
bool free;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
/* eprop = (EnumPropertyRNA *)prop; */
RNA_property_enum_items_ex(
@@ -1016,14 +1016,14 @@ static int rna_EnumPropertyItem_icon_get(PointerRNA *ptr)
static PointerRNA rna_PointerProperty_fixed_type_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return rna_pointer_inherit_refine(ptr, &RNA_Struct, ((PointerPropertyRNA *)prop)->type);
}
static PointerRNA rna_CollectionProperty_fixed_type_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- rna_idproperty_check(&prop, ptr);
+ prop = rna_ensure_property(prop);
return rna_pointer_inherit_refine(ptr, &RNA_Struct, ((CollectionPropertyRNA *)prop)->item_type);
}
@@ -1431,12 +1431,8 @@ static int rna_property_override_diff_propptr(Main *bmain,
RNA_property_##_typename##_set((_ptr), (_prop), (_value)))
int rna_property_override_diff_default(Main *bmain,
- PointerRNA *ptr_a,
- PointerRNA *ptr_b,
- PropertyRNA *prop_a,
- PropertyRNA *prop_b,
- const int len_a,
- const int len_b,
+ PropertyRNAOrID *prop_a,
+ PropertyRNAOrID *prop_b,
const int mode,
IDOverrideLibrary *override,
const char *rna_path,
@@ -1444,6 +1440,13 @@ int rna_property_override_diff_default(Main *bmain,
const int flags,
bool *r_override_changed)
{
+ PointerRNA *ptr_a = &prop_a->ptr;
+ PointerRNA *ptr_b = &prop_b->ptr;
+ PropertyRNA *rawprop_a = prop_a->rawprop;
+ PropertyRNA *rawprop_b = prop_b->rawprop;
+ const uint len_a = prop_a->array_len;
+ const uint len_b = prop_b->array_len;
+
BLI_assert(len_a == len_b);
/* Note: at this point, we are sure that when len_a is zero,
@@ -1452,7 +1455,16 @@ int rna_property_override_diff_default(Main *bmain,
const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 &&
rna_path != NULL;
- switch (RNA_property_type(prop_a)) {
+ const bool no_ownership = (prop_a->rnaprop->flag & PROP_PTR_NO_OWNERSHIP) != 0;
+ const bool no_prop_name = (prop_a->rnaprop->flag_override & PROPOVERRIDE_NO_PROP_NAME) != 0;
+
+ /* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
+ * and that we never remove anything. */
+ const bool use_collection_insertion = (prop_a->rnaprop->flag_override &
+ PROPOVERRIDE_LIBRARY_INSERTION) &&
+ do_create;
+
+ switch (RNA_property_type(prop_a->rnaprop)) {
case PROP_BOOLEAN: {
if (len_a) {
bool array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
@@ -1463,8 +1475,8 @@ int rna_property_override_diff_default(Main *bmain,
array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(bool) * len_b, "RNA equals") :
array_stack_b;
- RNA_property_boolean_get_array(ptr_a, prop_a, array_a);
- RNA_property_boolean_get_array(ptr_b, prop_b, array_b);
+ RNA_property_boolean_get_array(ptr_a, rawprop_a, array_a);
+ RNA_property_boolean_get_array(ptr_b, rawprop_b, array_b);
const int comp = memcmp(array_a, array_b, sizeof(bool) * len_a);
@@ -1496,8 +1508,8 @@ int rna_property_override_diff_default(Main *bmain,
return comp;
}
else {
- const bool value_a = RNA_property_boolean_get(ptr_a, prop_a);
- const bool value_b = RNA_property_boolean_get(ptr_b, prop_b);
+ const bool value_a = RNA_property_boolean_get(ptr_a, rawprop_a);
+ const bool value_b = RNA_property_boolean_get(ptr_b, rawprop_b);
const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
if (do_create && comp != 0) {
@@ -1528,8 +1540,8 @@ int rna_property_override_diff_default(Main *bmain,
array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") :
array_stack_b;
- RNA_property_int_get_array(ptr_a, prop_a, array_a);
- RNA_property_int_get_array(ptr_b, prop_b, array_b);
+ RNA_property_int_get_array(ptr_a, rawprop_a, array_a);
+ RNA_property_int_get_array(ptr_b, rawprop_b, array_b);
const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
@@ -1561,8 +1573,8 @@ int rna_property_override_diff_default(Main *bmain,
return comp;
}
else {
- const int value_a = RNA_property_int_get(ptr_a, prop_a);
- const int value_b = RNA_property_int_get(ptr_b, prop_b);
+ const int value_a = RNA_property_int_get(ptr_a, rawprop_a);
+ const int value_b = RNA_property_int_get(ptr_b, rawprop_b);
const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
if (do_create && comp != 0) {
@@ -1593,8 +1605,8 @@ int rna_property_override_diff_default(Main *bmain,
array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_b, "RNA equals") :
array_stack_b;
- RNA_property_float_get_array(ptr_a, prop_a, array_a);
- RNA_property_float_get_array(ptr_b, prop_b, array_b);
+ RNA_property_float_get_array(ptr_a, rawprop_a, array_a);
+ RNA_property_float_get_array(ptr_b, rawprop_b, array_b);
const int comp = memcmp(array_a, array_b, sizeof(float) * len_a);
@@ -1626,8 +1638,8 @@ int rna_property_override_diff_default(Main *bmain,
return comp;
}
else {
- const float value_a = RNA_property_float_get(ptr_a, prop_a);
- const float value_b = RNA_property_float_get(ptr_b, prop_b);
+ const float value_a = RNA_property_float_get(ptr_a, rawprop_a);
+ const float value_b = RNA_property_float_get(ptr_b, rawprop_b);
const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
if (do_create && comp != 0) {
@@ -1649,8 +1661,8 @@ int rna_property_override_diff_default(Main *bmain,
}
case PROP_ENUM: {
- const int value_a = RNA_property_enum_get(ptr_a, prop_a);
- const int value_b = RNA_property_enum_get(ptr_b, prop_b);
+ const int value_a = RNA_property_enum_get(ptr_a, rawprop_a);
+ const int value_b = RNA_property_enum_get(ptr_b, rawprop_b);
const int comp = value_a != value_b;
if (do_create && comp != 0) {
@@ -1674,9 +1686,9 @@ int rna_property_override_diff_default(Main *bmain,
char fixed_a[4096], fixed_b[4096];
int len_str_a, len_str_b;
char *value_a = RNA_property_string_get_alloc(
- ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a);
+ ptr_a, rawprop_a, fixed_a, sizeof(fixed_a), &len_str_a);
char *value_b = RNA_property_string_get_alloc(
- ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
+ ptr_b, rawprop_b, fixed_b, sizeof(fixed_b), &len_str_b);
/* TODO we could do a check on length too,
* but then we would not have a 'real' string comparison...
* Maybe behind a eRNAOverrideMatch flag? */
@@ -1712,16 +1724,13 @@ int rna_property_override_diff_default(Main *bmain,
}
case PROP_POINTER: {
- if (STREQ(RNA_property_identifier(prop_a), "rna_type")) {
+ if (STREQ(prop_a->identifier, "rna_type")) {
/* Dummy 'pass' answer, this is a meta-data and must be ignored... */
return 0;
}
else {
- PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
- PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
- const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
- const bool no_prop_name = (RNA_property_override_flag(prop_a) &
- PROPOVERRIDE_NO_PROP_NAME) != 0;
+ PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, rawprop_a);
+ PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, rawprop_b);
return rna_property_override_diff_propptr(bmain,
&propptr_a,
&propptr_b,
@@ -1742,14 +1751,6 @@ int rna_property_override_diff_default(Main *bmain,
}
case PROP_COLLECTION: {
- /* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
- * and that we never remove anything. */
- const bool use_insertion = (RNA_property_override_flag(prop_a) &
- PROPOVERRIDE_LIBRARY_INSERTION) &&
- do_create;
- const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
- const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) !=
- 0;
bool equals = true;
bool abort = false;
bool is_first_insert = true;
@@ -1757,8 +1758,8 @@ int rna_property_override_diff_default(Main *bmain,
int idx_b = 0;
CollectionPropertyIterator iter_a, iter_b;
- RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
- RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
+ RNA_property_collection_begin(ptr_a, rawprop_a, &iter_a);
+ RNA_property_collection_begin(ptr_b, rawprop_b, &iter_b);
char buff_a[4096];
char buff_prev_a[4096] = {0};
@@ -1773,7 +1774,7 @@ int rna_property_override_diff_default(Main *bmain,
do {
bool is_id = false, is_null = false, is_type_diff = false;
- is_valid_for_insertion = use_insertion;
+ is_valid_for_insertion = use_collection_insertion;
/* If false, it means that the whole data itself is different,
* so no point in going inside of it at all! */
@@ -1846,7 +1847,7 @@ int rna_property_override_diff_default(Main *bmain,
/* Collections do not support replacement of their data (except for collections of ID
* pointers), since they do not support removing, only in *some* cases, insertion. We
* also assume then that _a data is the one where things are inserted. */
- if (is_valid_for_insertion && use_insertion) {
+ if (is_valid_for_insertion && use_collection_insertion) {
bool created;
IDOverrideLibraryProperty *op = BKE_lib_override_library_property_get(
override, rna_path, &created);
@@ -1930,7 +1931,7 @@ int rna_property_override_diff_default(Main *bmain,
break;
}
- if (!(use_insertion && !(is_id || is_valid_for_diffing))) {
+ if (!(use_collection_insertion && !(is_id || is_valid_for_diffing))) {
break;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d141e6f3b19..9b98be61cbf 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -6463,7 +6463,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "simplify_gpencil_shader_fx", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FX);
- RNA_def_property_ui_text(prop, "ShadersFX", "Display Shader FX");
+ RNA_def_property_ui_text(prop, "Shaders Effects", "Display Shader Effects");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_tint", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index e9c59fc5011..a66e20258d2 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -98,13 +98,13 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
}
}
-static void rna_Scene_uvedit_aspect(Scene *scene, Object *ob, float *aspect)
+static void rna_Scene_uvedit_aspect(Scene *UNUSED(scene), Object *ob, float *aspect)
{
if ((ob->type == OB_MESH) && (ob->mode == OB_MODE_EDIT)) {
BMEditMesh *em;
em = BKE_editmesh_from_object(ob);
if (EDBM_uv_check(em)) {
- ED_uvedit_get_aspect(scene, ob, em->bm, aspect, aspect + 1);
+ ED_uvedit_get_aspect(ob, aspect, aspect + 1);
return;
}
}
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 20ae69dc031..ea6421c8d11 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -90,6 +90,12 @@ static bool rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr))
return wm ? (ED_screen_animation_playing(wm) != NULL) : 0;
}
+static bool rna_Screen_is_scrubbing_get(PointerRNA *ptr)
+{
+ bScreen *screen = (bScreen *)ptr->data;
+ return screen->scrubbing;
+}
+
static int rna_region_alignment_get(PointerRNA *ptr)
{
ARegion *region = ptr->data;
@@ -548,6 +554,12 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Screen_is_animation_playing_get", NULL);
RNA_def_property_ui_text(prop, "Animation Playing", "Animation playback is active");
+ prop = RNA_def_property(srna, "is_scrubbing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Screen_is_scrubbing_get", NULL);
+ RNA_def_property_ui_text(
+ prop, "User is Scrubbing", "True when the user is scrubbing through time");
+
prop = RNA_def_property(srna, "is_temporary", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_sdna(prop, NULL, "temp", 1);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 7342879e9e6..de225e3c685 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -749,6 +749,25 @@ static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create)
return seq->prop;
}
+static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain)
+{
+ Scene *scene = (Scene *)scene_id;
+ bool has_reloaded;
+ bool can_produce_frames;
+
+ BKE_sequence_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames);
+
+ if (has_reloaded && can_produce_frames) {
+ BKE_sequence_calc(scene, seq);
+ BKE_sequence_invalidate_cache_raw(scene, seq);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
+ }
+
+ return can_produce_frames;
+}
+
static PointerRNA rna_MovieSequence_metadata_get(Sequence *seq)
{
if (seq == NULL || seq->anims.first == NULL) {
@@ -2385,6 +2404,13 @@ static void rna_def_movie(BlenderRNA *brna)
"rna_Sequence_filepath_set");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update");
+ func = RNA_def_function(srna, "reload_if_needed", "rna_MovieSequence_reload_if_needed");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ /* return type */
+ parm = RNA_def_boolean(
+ func, "can_produce_frames", 0, "True if the strip can produce frames, False otherwise", "");
+ RNA_def_function_return(func, parm);
+
/* metadata */
func = RNA_def_function(srna, "metadata", "rna_MovieSequence_metadata_get");
RNA_def_function_ui_description(func, "Retrieve metadata of the movie file");
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 277ef4d152f..4157747455d 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -79,7 +79,6 @@ static Sequence *alloc_generic_sequence(
Editing *ed, const char *name, int frame_start, int channel, int type, const char *file)
{
Sequence *seq;
- Strip *strip;
StripElem *se;
seq = BKE_sequence_alloc(ed->seqbasep, frame_start, channel, type);
@@ -87,8 +86,7 @@ static Sequence *alloc_generic_sequence(
BLI_strncpy(seq->name + 2, name, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
- seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->strip->us = 1;
+ Strip *strip = seq->strip;
if (file) {
strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
@@ -207,33 +205,28 @@ static Sequence *rna_Sequences_new_image(ID *id,
return seq;
}
-static Sequence *rna_Sequences_new_movie(ID *id,
- Editing *ed,
- ReportList *reports,
- const char *name,
- const char *file,
- int channel,
- int frame_start)
+static Sequence *rna_Sequences_new_movie(
+ ID *id, Editing *ed, const char *name, const char *file, int channel, int frame_start)
{
Scene *scene = (Scene *)id;
Sequence *seq;
StripAnim *sanim;
- struct anim *an = openanim(file, IB_rect, 0, NULL);
+ seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file);
+ struct anim *an = openanim(file, IB_rect, 0, NULL);
if (an == NULL) {
- BKE_report(reports, RPT_ERROR, "Sequences.new_movie: unable to open movie file");
- return NULL;
+ /* Without anim, the strip gets duration 0, which makes it impossible to select in the UI. */
+ seq->len = 1;
}
+ else {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = an;
- seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file);
-
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = an;
-
- seq->anim_preseek = IMB_anim_get_preseek(an);
- seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
+ seq->anim_preseek = IMB_anim_get_preseek(an);
+ seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
+ }
BKE_sequence_calc_disp(scene, seq);
BKE_sequence_invalidate_cache_composite(scene, seq);
@@ -669,7 +662,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "new_movie", "rna_Sequences_new_movie");
- RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new movie sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index 80f3cab147c..e1970a57a91 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -168,7 +168,7 @@ static char *rna_ShaderFx_path(PointerRNA *ptr)
static void rna_ShaderFx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->owner_id);
+ WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, ptr->owner_id);
}
static void rna_ShaderFx_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -220,7 +220,7 @@ static void rna_def_shader_fx_blur(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "radius");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Size", "Factor of Blur");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samples");
@@ -228,18 +228,18 @@ static void rna_def_shader_fx_blur(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 32, 2, -1);
RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "rotation");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(prop, "Rotation", "Rotation of the effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_dof_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_BLUR_DOF_MODE);
RNA_def_property_ui_text(prop, "Use as Depth Of Field", "Blur using camera depth of field");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_colorize(BlenderRNA *brna)
@@ -256,27 +256,27 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "factor");
RNA_def_property_range(prop, 0, 1.0);
RNA_def_property_ui_text(prop, "Factor", "Mix factor");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "low_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "low_color");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Low Color", "First color used for effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "high_color");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "High Color", "Second color used for effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, rna_enum_shaderfx_colorize_modes_items);
RNA_def_property_ui_text(prop, "Mode", "Effect mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_wave(BlenderRNA *brna)
@@ -298,25 +298,25 @@ static void rna_def_shader_fx_wave(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "orientation");
RNA_def_property_enum_items(prop, prop_shaderfx_wave_type_items);
RNA_def_property_ui_text(prop, "Orientation", "Direction of the wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "amplitude");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of Wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "period");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(prop, "Period", "Period of Wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "phase");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(prop, "Phase", "Phase Shift of Wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_pixel(BlenderRNA *brna)
@@ -334,12 +334,12 @@ static void rna_def_shader_fx_pixel(BlenderRNA *brna)
RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_array(prop, 2);
RNA_def_property_ui_text(prop, "Size", "Pixel size");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", FX_PIXEL_FILTER_NEAREST);
RNA_def_property_ui_text(prop, "Antialiasing", "Antialiase pixels");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_rim(BlenderRNA *brna)
@@ -356,34 +356,34 @@ static void rna_def_shader_fx_rim(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "offset");
RNA_def_property_range(prop, SHRT_MIN, SHRT_MAX);
RNA_def_property_ui_text(prop, "Offset", "Offset of the rim");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "rim_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rim_rgb");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Rim Color", "Color used for Rim");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mask_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "mask_rgb");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Mask Color", "Color that must be kept");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, rna_enum_shaderfx_rim_modes_items);
RNA_def_property_ui_text(prop, "Mode", "Blend mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "blur", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "blur");
RNA_def_property_range(prop, 0, SHRT_MAX);
RNA_def_property_ui_text(
prop, "Blur", "Number of pixels for blurring rim (set to 0 to disable)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samples");
@@ -391,7 +391,7 @@ static void rna_def_shader_fx_rim(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 32, 2, -1);
RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_shadow(BlenderRNA *brna)
@@ -420,58 +420,58 @@ static void rna_def_shader_fx_shadow(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "offset");
RNA_def_property_range(prop, SHRT_MIN, SHRT_MAX);
RNA_def_property_ui_text(prop, "Offset", "Offset of the shadow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "scale");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(prop, "Scale", "Offset of the shadow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "shadow_rgba");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Shadow Color", "Color used for Shadow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "orientation");
RNA_def_property_enum_items(prop, prop_shaderfx_shadow_type_items);
RNA_def_property_ui_text(prop, "Orientation", "Direction of the wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "amplitude");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of Wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "period");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(prop, "Period", "Period of Wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "phase");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(prop, "Phase", "Phase Shift of Wave");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "rotation");
RNA_def_property_range(prop, DEG2RAD(-360), DEG2RAD(360));
RNA_def_property_ui_range(prop, DEG2RAD(-360), DEG2RAD(360), 5, 2);
RNA_def_property_ui_text(prop, "Rotation", "Rotation around center or object");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "blur", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "blur");
RNA_def_property_range(prop, 0, SHRT_MAX);
RNA_def_property_ui_text(
prop, "Blur", "Number of pixels for blurring shadow (set to 0 to disable)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samples");
@@ -479,17 +479,17 @@ static void rna_def_shader_fx_shadow(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 32, 2, -1);
RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_object", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SHADOW_USE_OBJECT);
RNA_def_property_ui_text(prop, "Use Object", "Use object as center of rotation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_wave", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SHADOW_USE_WAVE);
RNA_def_property_ui_text(prop, "Wave", "Use wave effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_glow(BlenderRNA *brna)
@@ -507,41 +507,41 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "glow_color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Glow Color", "Color used for generated glow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "glow_color[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Effect Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "select_color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Select Color", "Color selected to apply glow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, rna_enum_shaderfx_glow_modes_items);
RNA_def_property_ui_text(prop, "Mode", "Glow mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "threshold");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 3);
RNA_def_property_ui_text(prop, "Threshold", "Limit to select color for glow effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
/* Use blur fields to make compatible with blur filter */
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "blur");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Size", "Size of the effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samples");
@@ -549,26 +549,26 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 1, 32, 2, -1);
RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_glow_under", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_GLOW_USE_ALPHA);
RNA_def_property_ui_text(
prop, "Glow Under", "Glow only areas with alpha (not supported with Regular blend mode)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "rotation");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(prop, "Rotation", "Rotation of the effect");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
/* blend mode */
prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
RNA_def_property_enum_items(prop, rna_enum_glow_blend_modes_items);
RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_swirl(BlenderRNA *brna)
@@ -585,19 +585,19 @@ static void rna_def_shader_fx_swirl(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "radius");
RNA_def_property_range(prop, 0, SHRT_MAX);
RNA_def_property_ui_text(prop, "Radius", "Radius to apply");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "angle");
RNA_def_property_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360));
RNA_def_property_ui_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360), 5, 2);
RNA_def_property_ui_text(prop, "Angle", "Angle of rotation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_transparent", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SWIRL_MAKE_TRANSPARENT);
RNA_def_property_ui_text(prop, "Transparent", "Make image transparent outside of radius");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Object to determine center location");
@@ -620,12 +620,12 @@ static void rna_def_shader_fx_flip(BlenderRNA *brna)
prop = RNA_def_property(srna, "flip_horizontal", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_HORIZONTAL);
RNA_def_property_ui_text(prop, "Horizontal", "Flip image horizontally");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "flip_vertical", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_VERTICAL);
RNA_def_property_ui_text(prop, "Vertical", "Flip image vertically");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
}
void RNA_def_shader_fx(BlenderRNA *brna)
@@ -644,7 +644,7 @@ void RNA_def_shader_fx(BlenderRNA *brna)
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShaderFx_name_set");
RNA_def_property_ui_text(prop, "Name", "Effect name");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX | NA_RENAME, NULL);
RNA_def_struct_name_property(srna, prop);
/* enums */
@@ -661,7 +661,7 @@ void RNA_def_shader_fx(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Realtime", "Display effect in viewport");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_ON, 1);
prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
@@ -669,12 +669,12 @@ void RNA_def_shader_fx(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Render", "Use effect during render");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_ON, 1);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, NULL);
prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Editmode);
RNA_def_property_ui_text(prop, "Edit Mode", "Display effect in Edit mode");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0);
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index c31b313d827..956fb65054b 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -3973,12 +3973,13 @@ static void rna_def_userdef_studiolights(BlenderRNA *brna)
func = RNA_def_function(srna, "new", "rna_StudioLights_new");
RNA_def_function_ui_description(func, "Create studiolight from default lighting");
- parm = RNA_def_string(func,
- "path",
- NULL,
- 0,
- "Path",
- "Path to the file that will contain the lighing info (without extension)");
+ parm = RNA_def_string(
+ func,
+ "path",
+ NULL,
+ 0,
+ "Path",
+ "Path to the file that will contain the lighting info (without extension)");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight");
RNA_def_function_return(func, parm);
@@ -6084,6 +6085,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_cycles_debug", 1);
RNA_def_property_ui_text(prop, "Cycles Debug", "Enable Cycles debugging options for developers");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "use_sculpt_vertex_colors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_sculpt_vertex_colors", 1);
+ RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "Use the new Vertex Painting system");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 80a1ebab64e..cf87e3598b6 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -23,9 +23,9 @@ set(INC
intern
../blenfont
../blenkernel
- ../blentranslation
../blenlib
../blenloader
+ ../blentranslation
../bmesh
../depsgraph
../editors/include
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index f6ad25ce282..4e46e135b72 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -254,7 +254,7 @@ static void remap_faces_3_6_9_12(Mesh *mesh,
Mesh *split,
MFace *mf,
int *facepa,
- int *vertpa,
+ const int *vertpa,
int i,
EdgeHash *eh,
int cur,
@@ -322,7 +322,7 @@ static void remap_faces_5_10(Mesh *mesh,
Mesh *split,
MFace *mf,
int *facepa,
- int *vertpa,
+ const int *vertpa,
int i,
EdgeHash *eh,
int cur,
@@ -378,7 +378,7 @@ static void remap_faces_15(Mesh *mesh,
Mesh *split,
MFace *mf,
int *facepa,
- int *vertpa,
+ const int *vertpa,
int i,
EdgeHash *eh,
int cur,
@@ -462,7 +462,7 @@ static void remap_faces_7_11_13_14(Mesh *mesh,
Mesh *split,
MFace *mf,
int *facepa,
- int *vertpa,
+ const int *vertpa,
int i,
EdgeHash *eh,
int cur,
@@ -531,7 +531,7 @@ static void remap_faces_19_21_22(Mesh *mesh,
Mesh *split,
MFace *mf,
int *facepa,
- int *vertpa,
+ const int *vertpa,
int i,
EdgeHash *eh,
int cur,
@@ -585,7 +585,7 @@ static void remap_faces_23(Mesh *mesh,
Mesh *split,
MFace *mf,
int *facepa,
- int *vertpa,
+ const int *vertpa,
int i,
EdgeHash *eh,
int cur,
diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc
index 85eb66cd826..69a7bfd91ac 100644
--- a/source/blender/modifiers/intern/MOD_simulation.cc
+++ b/source/blender/modifiers/intern/MOD_simulation.cc
@@ -29,6 +29,7 @@
#include "BLI_float3.hh"
#include "BLI_listbase.h"
+#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
@@ -47,6 +48,8 @@
#include "BKE_pointcloud.h"
#include "BKE_simulation.h"
+#include "BLO_read_write.h"
+
/* SpaceType struct has a member called 'new' which obviously conflicts with C++
* so temporarily redefining the new keyword to make it compile. */
#define new extern_new
@@ -93,9 +96,14 @@ static const ParticleSimulationState *find_particle_state(SimulationModifierData
if (smd->simulation == nullptr) {
return nullptr;
}
+ if (smd->data_path == nullptr) {
+ return nullptr;
+ }
LISTBASE_FOREACH (const SimulationState *, state, &smd->simulation->states) {
- if (state->type == SIM_STATE_TYPE_PARTICLES) {
- return (ParticleSimulationState *)state;
+ if (STREQ(smd->data_path, state->name)) {
+ if (state->type == SIM_STATE_TYPE_PARTICLES) {
+ return (ParticleSimulationState *)state;
+ }
}
}
return nullptr;
@@ -121,7 +129,7 @@ static PointCloud *modifyPointCloud(ModifierData *md,
memcpy(pointcloud->co, positions, sizeof(float3) * state->tot_particles);
for (int i = 0; i < state->tot_particles; i++) {
- pointcloud->radius[i] = 0.05f;
+ pointcloud->radius[i] = 0.1f;
}
return pointcloud;
@@ -146,6 +154,37 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_Simulation, panel_draw);
}
+static void blendWrite(BlendWriter *writer, const ModifierData *md)
+{
+ const SimulationModifierData *smd = (const SimulationModifierData *)md;
+ BLO_write_string(writer, smd->data_path);
+}
+
+static void blendRead(BlendDataReader *reader, ModifierData *md)
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+ BLO_read_data_address(reader, &smd->data_path);
+}
+
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
+{
+ const SimulationModifierData *smd = (const SimulationModifierData *)md;
+ SimulationModifierData *tsmd = (SimulationModifierData *)target;
+
+ BKE_modifier_copydata_generic(md, target, flag);
+ if (smd->data_path != nullptr) {
+ tsmd->data_path = BLI_strdup(smd->data_path);
+ }
+}
+
+static void freeData(ModifierData *md)
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+ if (smd->data_path) {
+ MEM_freeN(smd->data_path);
+ }
+}
+
ModifierTypeInfo modifierType_Simulation = {
/* name */ "Simulation",
/* structName */ "SimulationModifierData",
@@ -153,7 +192,7 @@ ModifierTypeInfo modifierType_Simulation = {
/* type */ eModifierTypeType_None,
/* flags */ (ModifierTypeFlag)0,
- /* copyData */ BKE_modifier_copydata_generic,
+ /* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
@@ -166,7 +205,7 @@ ModifierTypeInfo modifierType_Simulation = {
/* initData */ NULL,
/* requiredDataMask */ NULL,
- /* freeData */ NULL,
+ /* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
@@ -176,6 +215,6 @@ ModifierTypeInfo modifierType_Simulation = {
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
- /* blendRead */ NULL,
+ /* blendWrite */ blendWrite,
+ /* blendRead */ blendRead,
};
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index a56194354f8..7e5e4ecd9d3 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -284,7 +284,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
- edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder");
+ edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod order");
/* save doing 2 loops here... */
#if 0
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 137f52782a9..01b9e972086 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -231,12 +231,19 @@ static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v)
/* Apply as shapekey. */
if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {
- uiItemEnumO(layout,
- "OBJECT_OT_modifier_apply",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply As Shapekey"),
- ICON_SHAPEKEY_DATA,
- "apply_as",
- MODIFIER_APPLY_SHAPE);
+ uiItemBooleanO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply As Shapekey"),
+ ICON_SHAPEKEY_DATA,
+ "OBJECT_OT_modifier_apply_as_shapekey",
+ "keep_modifier",
+ false);
+
+ uiItemBooleanO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Save As Shapekey"),
+ ICON_SHAPEKEY_DATA,
+ "OBJECT_OT_modifier_apply_as_shapekey",
+ "keep_modifier",
+ true);
}
/* Duplicate. */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 31b5e922dab..2381e499eee 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenlib
../blentranslation
../depsgraph
+ ../functions
../gpu
../imbuf
../makesdna
@@ -37,6 +38,7 @@ set(INC
../render/extern/include
../../../intern/glew-mx
../../../intern/guardedalloc
+ ../../../intern/sky/include
)
set(INC_SYS
@@ -176,7 +178,7 @@ set(SRC
shader/nodes/node_shader_light_path.c
shader/nodes/node_shader_map_range.c
shader/nodes/node_shader_mapping.c
- shader/nodes/node_shader_math.c
+ shader/nodes/node_shader_math.cc
shader/nodes/node_shader_mixRgb.c
shader/nodes/node_shader_mix_shader.c
shader/nodes/node_shader_normal.c
@@ -192,7 +194,7 @@ set(SRC
shader/nodes/node_shader_script.c
shader/nodes/node_shader_sepcombHSV.c
shader/nodes/node_shader_sepcombRGB.c
- shader/nodes/node_shader_sepcombXYZ.c
+ shader/nodes/node_shader_sepcombXYZ.cc
shader/nodes/node_shader_shaderToRgb.c
shader/nodes/node_shader_squeeze.c
shader/nodes/node_shader_subsurface_scattering.c
@@ -214,10 +216,10 @@ set(SRC
shader/nodes/node_shader_uvAlongStroke.c
shader/nodes/node_shader_uvmap.c
shader/nodes/node_shader_valToRgb.c
- shader/nodes/node_shader_value.c
+ shader/nodes/node_shader_value.cc
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
- shader/nodes/node_shader_vector_math.c
+ shader/nodes/node_shader_vector_math.cc
shader/nodes/node_shader_vector_rotate.c
shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_volume_absorption.c
@@ -277,7 +279,7 @@ set(SRC
intern/node_util.c
composite/node_composite_util.h
- function/node_function_util.h
+ function/node_function_util.hh
shader/node_shader_util.h
simulation/node_simulation_util.h
texture/node_texture_util.h
@@ -296,6 +298,8 @@ set(SRC
)
set(LIB
+ bf_functions
+ bf_intern_sky
)
if(WITH_PYTHON)
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index 0927ba335fe..342c330a8fa 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -14,7 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "node_function_util.h"
+#include "node_function_util.hh"
#include "node_util.h"
bool fn_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
diff --git a/source/blender/nodes/function/node_function_util.h b/source/blender/nodes/function/node_function_util.hh
index 85e252f9bdd..938cb5dd593 100644
--- a/source/blender/nodes/function/node_function_util.h
+++ b/source/blender/nodes/function/node_function_util.hh
@@ -19,6 +19,7 @@
#include <string.h>
+#include "BLI_float3.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -26,6 +27,7 @@
#include "DNA_node_types.h"
#include "BKE_node.h"
+#include "BKE_node_tree_multi_function.hh"
#include "BLT_translation.h"
@@ -33,6 +35,8 @@
#include "node_util.h"
+#include "FN_multi_function_builder.hh"
+
void fn_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
bool fn_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index 615ad4c6733..3a145311a08 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -19,7 +19,7 @@
#include "RNA_enum_types.h"
-#include "node_function_util.h"
+#include "node_function_util.hh"
static bNodeSocketTemplate fn_node_boolean_math_in[] = {
{SOCK_BOOLEAN, N_("Boolean")},
@@ -50,6 +50,33 @@ static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char
BLI_strncpy(label, IFACE_(name), maxlen);
}
+static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
+{
+ static blender::fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{
+ "And", [](bool a, bool b) { return a && b; }};
+ static blender::fn::CustomMF_SI_SI_SO<bool, bool, bool> or_fn{
+ "Or", [](bool a, bool b) { return a || b; }};
+ static blender::fn::CustomMF_SI_SO<bool, bool> not_fn{"Not", [](bool a) { return !a; }};
+
+ switch (bnode.custom1) {
+ case NODE_BOOLEAN_MATH_AND:
+ return and_fn;
+ case NODE_BOOLEAN_MATH_OR:
+ return or_fn;
+ case NODE_BOOLEAN_MATH_NOT:
+ return not_fn;
+ }
+
+ BLI_assert(false);
+ return blender::fn::dummy_multi_function;
+}
+
+static void node_boolean_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
+ builder.set_matching_fn(fn);
+}
+
void register_node_type_fn_boolean_math()
{
static bNodeType ntype;
@@ -58,5 +85,6 @@ void register_node_type_fn_boolean_math()
node_type_socket_templates(&ntype, fn_node_boolean_math_in, fn_node_boolean_math_out);
node_type_label(&ntype, node_boolean_math_label);
node_type_update(&ntype, node_boolean_math_update);
+ ntype.expand_in_mf_network = node_boolean_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_combine_strings.cc b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
index 1b6091451d9..a880933bc12 100644
--- a/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
+++ b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
@@ -1,4 +1,20 @@
-#include "node_function_util.h"
+/*
+ * 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_function_util.hh"
static bNodeSocketTemplate fn_node_combine_strings_in[] = {
{SOCK_STRING, N_("A")},
@@ -11,11 +27,20 @@ static bNodeSocketTemplate fn_node_combine_strings_out[] = {
{-1, ""},
};
+static void fn_node_combine_strings_expand_in_mf_network(
+ blender::bke::NodeMFNetworkBuilder &builder)
+{
+ static blender::fn::CustomMF_SI_SI_SO<std::string, std::string, std::string> combine_fn{
+ "Combine Strings", [](const std::string &a, const std::string &b) { return a + b; }};
+ builder.set_matching_fn(combine_fn);
+}
+
void register_node_type_fn_combine_strings()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_COMBINE_STRINGS, "Combine Strings", 0, 0);
node_type_socket_templates(&ntype, fn_node_combine_strings_in, fn_node_combine_strings_out);
+ ntype.expand_in_mf_network = fn_node_combine_strings_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
index 9788402850b..fb2c4d88caf 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -14,12 +14,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <cmath>
+
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "RNA_enum_types.h"
-#include "node_function_util.h"
+#include "node_function_util.hh"
static bNodeSocketTemplate fn_node_float_compare_in[] = {
{SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
@@ -54,6 +56,46 @@ static void node_float_compare_label(bNodeTree *UNUSED(ntree),
BLI_strncpy(label, IFACE_(name), maxlen);
}
+static const blender::fn::MultiFunction &get_multi_function(bNode &node)
+{
+ static blender::fn::CustomMF_SI_SI_SO<float, float, bool> less_than_fn{
+ "Less Than", [](float a, float b) { return a < b; }};
+ static blender::fn::CustomMF_SI_SI_SO<float, float, bool> less_equal_fn{
+ "Less Equal", [](float a, float b) { return a <= b; }};
+ static blender::fn::CustomMF_SI_SI_SO<float, float, bool> greater_than_fn{
+ "Greater Than", [](float a, float b) { return a > b; }};
+ static blender::fn::CustomMF_SI_SI_SO<float, float, bool> greater_equal_fn{
+ "Greater Equal", [](float a, float b) { return a >= b; }};
+ static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> equal_fn{
+ "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
+ static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> not_equal_fn{
+ "Not Equal", [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
+
+ switch (node.custom1) {
+ case NODE_FLOAT_COMPARE_LESS_THAN:
+ return less_than_fn;
+ case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ return less_equal_fn;
+ case NODE_FLOAT_COMPARE_GREATER_THAN:
+ return greater_than_fn;
+ case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ return greater_equal_fn;
+ case NODE_FLOAT_COMPARE_EQUAL:
+ return equal_fn;
+ case NODE_FLOAT_COMPARE_NOT_EQUAL:
+ return not_equal_fn;
+ }
+
+ BLI_assert(false);
+ return blender::fn::dummy_multi_function;
+}
+
+static void node_float_compare_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
+ builder.set_matching_fn(fn);
+}
+
void register_node_type_fn_float_compare()
{
static bNodeType ntype;
@@ -62,5 +104,6 @@ void register_node_type_fn_float_compare()
node_type_socket_templates(&ntype, fn_node_float_compare_in, fn_node_float_compare_out);
node_type_label(&ntype, node_float_compare_label);
node_type_update(&ntype, node_float_compare_update);
+ ntype.expand_in_mf_network = node_float_compare_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
index 2ac86ee2407..c61c941ee0d 100644
--- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
+++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
@@ -1,15 +1,45 @@
-#include "node_function_util.h"
+/*
+ * 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_function_util.hh"
static bNodeSocketTemplate fn_node_group_instance_id_out[] = {
{SOCK_STRING, N_("Identifier")},
{-1, ""},
};
+static void fn_node_group_instance_id_expand_in_mf_network(
+ blender::bke::NodeMFNetworkBuilder &builder)
+{
+ const blender::bke::DNode &node = builder.dnode();
+ std::string id = "/";
+ for (const blender::bke::DParentNode *parent = node.parent(); parent;
+ parent = parent->parent()) {
+ id = "/" + parent->node_ref().name() + id;
+ }
+ builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(
+ std::move(id));
+}
+
void register_node_type_fn_group_instance_id()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_GROUP_INSTANCE_ID, "Group Instance ID", 0, 0);
node_type_socket_templates(&ntype, nullptr, fn_node_group_instance_id_out);
+ ntype.expand_in_mf_network = fn_node_group_instance_id_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_switch.cc b/source/blender/nodes/function/nodes/node_fn_switch.cc
index cb721058875..281ddb05c76 100644
--- a/source/blender/nodes/function/nodes/node_fn_switch.cc
+++ b/source/blender/nodes/function/nodes/node_fn_switch.cc
@@ -15,7 +15,7 @@
*/
#include "BLI_listbase.h"
-#include "node_function_util.h"
+#include "node_function_util.hh"
static bNodeSocketTemplate fn_node_switch_in[] = {
{SOCK_BOOLEAN, N_("Switch")},
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index b23511c3bdb..02124465dda 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -25,6 +25,8 @@
#include "DNA_node_types.h"
+#include "BLI_color.hh"
+#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -32,6 +34,7 @@
#include "BKE_lib_id.h"
#include "BKE_node.h"
+#include "BKE_node_tree_multi_function.hh"
#include "RNA_access.h"
#include "RNA_types.h"
@@ -510,35 +513,105 @@ static bNodeSocketType *make_socket_type_control_flow(int type)
return stype;
}
+static bNodeSocketType *make_socket_type_bool()
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
+ socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<bool>(); };
+ socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) {
+ bool value = builder.socket_default_value<bNodeSocketValueBoolean>()->value;
+ builder.set_constant_value(value);
+ };
+ return socktype;
+}
+
+static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
+ socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<float>(); };
+ socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) {
+ float value = builder.socket_default_value<bNodeSocketValueFloat>()->value;
+ builder.set_constant_value(value);
+ };
+ return socktype;
+}
+
+static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
+ socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<int>(); };
+ socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) {
+ int value = builder.socket_default_value<bNodeSocketValueInt>()->value;
+ builder.set_constant_value(value);
+ };
+ return socktype;
+}
+
+static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
+ socktype->get_mf_data_type = []() {
+ return blender::fn::MFDataType::ForSingle<blender::float3>();
+ };
+ socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) {
+ blender::float3 value = builder.socket_default_value<bNodeSocketValueVector>()->value;
+ builder.set_constant_value(value);
+ };
+ return socktype;
+}
+
+static bNodeSocketType *make_socket_type_rgba()
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
+ socktype->get_mf_data_type = []() {
+ return blender::fn::MFDataType::ForSingle<blender::Color4f>();
+ };
+ socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) {
+ blender::Color4f value = builder.socket_default_value<bNodeSocketValueRGBA>()->value;
+ builder.set_constant_value(value);
+ };
+ return socktype;
+}
+
+static bNodeSocketType *make_socket_type_string()
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
+ socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<std::string>(); };
+ socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) {
+ std::string value = builder.socket_default_value<bNodeSocketValueString>()->value;
+ builder.set_constant_value(value);
+ };
+ return socktype;
+}
+
void register_standard_node_socket_types(void)
{
/* draw callbacks are set in drawnode.c to avoid bad-level calls */
- nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_NONE));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_UNSIGNED));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_PERCENTAGE));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_FACTOR));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_ANGLE));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_TIME));
+ nodeRegisterSocketType(make_socket_type_float(PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_float(PROP_UNSIGNED));
+ nodeRegisterSocketType(make_socket_type_float(PROP_PERCENTAGE));
+ nodeRegisterSocketType(make_socket_type_float(PROP_FACTOR));
+ nodeRegisterSocketType(make_socket_type_float(PROP_ANGLE));
+ nodeRegisterSocketType(make_socket_type_float(PROP_TIME));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_NONE));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_UNSIGNED));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_PERCENTAGE));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_FACTOR));
+ nodeRegisterSocketType(make_socket_type_int(PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_int(PROP_UNSIGNED));
+ nodeRegisterSocketType(make_socket_type_int(PROP_PERCENTAGE));
+ nodeRegisterSocketType(make_socket_type_int(PROP_FACTOR));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_bool());
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_NONE));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_TRANSLATION));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_DIRECTION));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_VELOCITY));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_ACCELERATION));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_EULER));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_XYZ));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_TRANSLATION));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_DIRECTION));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_VELOCITY));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_ACCELERATION));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_EULER));
+ nodeRegisterSocketType(make_socket_type_vector(PROP_XYZ));
- nodeRegisterSocketType(make_standard_socket_type(SOCK_RGBA, PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_rgba());
- nodeRegisterSocketType(make_standard_socket_type(SOCK_STRING, PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_string());
nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE));
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index fbb9979cdfa..fc262544b4f 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -70,6 +70,12 @@
#include "GPU_uniformbuffer.h"
#ifdef __cplusplus
+# include "FN_multi_function_builder.hh"
+
+# include "BKE_node_tree_multi_function.hh"
+
+# include "BLI_float3.hh"
+
extern "C" {
#endif
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
deleted file mode 100644
index 8abebbf5081..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate sh_node_math_in[] = {
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
-
-static int gpu_shader_math(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- static const char *names[] = {
- [NODE_MATH_ADD] = "math_add",
- [NODE_MATH_SUBTRACT] = "math_subtract",
- [NODE_MATH_MULTIPLY] = "math_multiply",
- [NODE_MATH_DIVIDE] = "math_divide",
- [NODE_MATH_MULTIPLY_ADD] = "math_multiply_add",
-
- [NODE_MATH_POWER] = "math_power",
- [NODE_MATH_LOGARITHM] = "math_logarithm",
- [NODE_MATH_EXPONENT] = "math_exponent",
- [NODE_MATH_SQRT] = "math_sqrt",
- [NODE_MATH_INV_SQRT] = "math_inversesqrt",
- [NODE_MATH_ABSOLUTE] = "math_absolute",
- [NODE_MATH_RADIANS] = "math_radians",
- [NODE_MATH_DEGREES] = "math_degrees",
-
- [NODE_MATH_MINIMUM] = "math_minimum",
- [NODE_MATH_MAXIMUM] = "math_maximum",
- [NODE_MATH_LESS_THAN] = "math_less_than",
- [NODE_MATH_GREATER_THAN] = "math_greater_than",
- [NODE_MATH_SIGN] = "math_sign",
- [NODE_MATH_COMPARE] = "math_compare",
- [NODE_MATH_SMOOTH_MIN] = "math_smoothmin",
- [NODE_MATH_SMOOTH_MAX] = "math_smoothmax",
-
- [NODE_MATH_ROUND] = "math_round",
- [NODE_MATH_FLOOR] = "math_floor",
- [NODE_MATH_CEIL] = "math_ceil",
- [NODE_MATH_FRACTION] = "math_fraction",
- [NODE_MATH_MODULO] = "math_modulo",
- [NODE_MATH_TRUNC] = "math_trunc",
- [NODE_MATH_SNAP] = "math_snap",
- [NODE_MATH_WRAP] = "math_wrap",
- [NODE_MATH_PINGPONG] = "math_pingpong",
-
- [NODE_MATH_SINE] = "math_sine",
- [NODE_MATH_COSINE] = "math_cosine",
- [NODE_MATH_TANGENT] = "math_tangent",
- [NODE_MATH_SINH] = "math_sinh",
- [NODE_MATH_COSH] = "math_cosh",
- [NODE_MATH_TANH] = "math_tanh",
- [NODE_MATH_ARCSINE] = "math_arcsine",
- [NODE_MATH_ARCCOSINE] = "math_arccosine",
- [NODE_MATH_ARCTANGENT] = "math_arctangent",
- [NODE_MATH_ARCTAN2] = "math_arctan2",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- int ret = GPU_stack_link(mat, node, names[node->custom1], in, out);
-
- if (ret && node->custom2 & SHD_MATH_CLAMP) {
- float min[3] = {0.0f, 0.0f, 0.0f};
- float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(
- mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
- }
- return ret;
- }
- else {
- return 0;
- }
-}
-
-void register_node_type_sh_math(void)
-{
- static bNodeType ntype;
-
- sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
- node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
- node_type_label(&ntype, node_math_label);
- node_type_gpu(&ntype, gpu_shader_math);
- node_type_update(&ntype, node_math_update);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
new file mode 100644
index 00000000000..a0eb5099f9d
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** SCALAR MATH ******************** */
+static bNodeSocketTemplate sh_node_math_in[] = {
+ {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {-1, ""}};
+
+static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_MATH_ADD:
+ return "math_add";
+ case NODE_MATH_SUBTRACT:
+ return "math_subtract";
+ case NODE_MATH_MULTIPLY:
+ return "math_multiply";
+ case NODE_MATH_DIVIDE:
+ return "math_divide";
+ case NODE_MATH_MULTIPLY_ADD:
+ return "math_multiply_add";
+
+ case NODE_MATH_POWER:
+ return "math_power";
+ case NODE_MATH_LOGARITHM:
+ return "math_logarithm";
+ case NODE_MATH_EXPONENT:
+ return "math_exponent";
+ case NODE_MATH_SQRT:
+ return "math_sqrt";
+ case NODE_MATH_INV_SQRT:
+ return "math_inversesqrt";
+ case NODE_MATH_ABSOLUTE:
+ return "math_absolute";
+ case NODE_MATH_RADIANS:
+ return "math_radians";
+ case NODE_MATH_DEGREES:
+ return "math_degrees";
+
+ case NODE_MATH_MINIMUM:
+ return "math_minimum";
+ case NODE_MATH_MAXIMUM:
+ return "math_maximum";
+ case NODE_MATH_LESS_THAN:
+ return "math_less_than";
+ case NODE_MATH_GREATER_THAN:
+ return "math_greater_than";
+ case NODE_MATH_SIGN:
+ return "math_sign";
+ case NODE_MATH_COMPARE:
+ return "math_compare";
+ case NODE_MATH_SMOOTH_MIN:
+ return "math_smoothmin";
+ case NODE_MATH_SMOOTH_MAX:
+ return "math_smoothmax";
+
+ case NODE_MATH_ROUND:
+ return "math_round";
+ case NODE_MATH_FLOOR:
+ return "math_floor";
+ case NODE_MATH_CEIL:
+ return "math_ceil";
+ case NODE_MATH_FRACTION:
+ return "math_fraction";
+ case NODE_MATH_MODULO:
+ return "math_modulo";
+ case NODE_MATH_TRUNC:
+ return "math_trunc";
+ case NODE_MATH_SNAP:
+ return "math_snap";
+ case NODE_MATH_WRAP:
+ return "math_wrap";
+ case NODE_MATH_PINGPONG:
+ return "math_pingpong";
+
+ case NODE_MATH_SINE:
+ return "math_sine";
+ case NODE_MATH_COSINE:
+ return "math_cosine";
+ case NODE_MATH_TANGENT:
+ return "math_tangent";
+ case NODE_MATH_SINH:
+ return "math_sinh";
+ case NODE_MATH_COSH:
+ return "math_cosh";
+ case NODE_MATH_TANH:
+ return "math_tanh";
+ case NODE_MATH_ARCSINE:
+ return "math_arcsine";
+ case NODE_MATH_ARCCOSINE:
+ return "math_arccosine";
+ case NODE_MATH_ARCTANGENT:
+ return "math_arctangent";
+ case NODE_MATH_ARCTAN2:
+ return "math_arctan2";
+ }
+ return nullptr;
+}
+
+static int gpu_shader_math(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const char *name = gpu_shader_get_name(node->custom1);
+ if (name != nullptr) {
+ int ret = GPU_stack_link(mat, node, name, in, out);
+
+ if (ret && node->custom2 & SHD_MATH_CLAMP) {
+ float min[3] = {0.0f, 0.0f, 0.0f};
+ float max[3] = {1.0f, 1.0f, 1.0f};
+ GPU_link(
+ mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
+ }
+ return ret;
+ }
+ else {
+ return 0;
+ }
+}
+
+static void sh_node_math_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ /* TODO: Implement clamp and other operations. */
+ const int mode = builder.bnode().custom1;
+ switch (mode) {
+ case NODE_MATH_ADD: {
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{
+ "Add", [](float a, float b) { return a + b; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_MATH_SUBTRACT: {
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{
+ "Subtract", [](float a, float b) { return a - b; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_MATH_MULTIPLY: {
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{
+ "Multiply", [](float a, float b) { return a * b; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_MATH_DIVIDE: {
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{
+ "Divide", [](float a, float b) { return (b != 0.0f) ? a / b : 0.0f; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default:
+ BLI_assert(false);
+ break;
+ }
+}
+
+void register_node_type_sh_math(void)
+{
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
+ node_type_label(&ntype, node_math_label);
+ node_type_gpu(&ntype, gpu_shader_math);
+ node_type_update(&ntype, node_math_update);
+ ntype.expand_in_mf_network = sh_node_math_expand_in_mf_network;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
index 429b1a3e818..4dbe10f3982 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
@@ -44,6 +44,42 @@ static int gpu_shader_sepxyz(GPUMaterial *mat,
return GPU_stack_link(mat, node, "separate_xyz", in, out);
}
+class MF_SeparateXYZ : public blender::fn::MultiFunction {
+ public:
+ MF_SeparateXYZ()
+ {
+ blender::fn::MFSignatureBuilder signature = this->get_builder("Separate XYZ");
+ signature.single_input<blender::float3>("XYZ");
+ signature.single_output<float>("X");
+ signature.single_output<float>("Y");
+ signature.single_output<float>("Z");
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ blender::fn::VSpan<blender::float3> vectors = params.readonly_single_input<blender::float3>(
+ 0, "XYZ");
+ blender::MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X");
+ blender::MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y");
+ blender::MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z");
+
+ for (uint i : mask) {
+ blender::float3 xyz = vectors[i];
+ xs[i] = xyz.x;
+ ys[i] = xyz.y;
+ zs[i] = xyz.z;
+ }
+ }
+};
+
+static void sh_node_sepxyz_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ static MF_SeparateXYZ separate_fn;
+ builder.set_matching_fn(separate_fn);
+}
+
void register_node_type_sh_sepxyz(void)
{
static bNodeType ntype;
@@ -51,6 +87,7 @@ void register_node_type_sh_sepxyz(void)
sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out);
node_type_gpu(&ntype, gpu_shader_sepxyz);
+ ntype.expand_in_mf_network = sh_node_sepxyz_expand_in_mf_network;
nodeRegisterType(&ntype);
}
@@ -76,6 +113,39 @@ static int gpu_shader_combxyz(GPUMaterial *mat,
return GPU_stack_link(mat, node, "combine_xyz", in, out);
}
+class MF_CombineXYZ : public blender::fn::MultiFunction {
+ public:
+ MF_CombineXYZ()
+ {
+ blender::fn::MFSignatureBuilder signature = this->get_builder("Combine XYZ");
+ signature.single_input<float>("X");
+ signature.single_input<float>("Y");
+ signature.single_input<float>("Z");
+ signature.single_output<blender::float3>("XYZ");
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ blender::fn::VSpan<float> xs = params.readonly_single_input<float>(0, "X");
+ blender::fn::VSpan<float> ys = params.readonly_single_input<float>(1, "Y");
+ blender::fn::VSpan<float> zs = params.readonly_single_input<float>(2, "Z");
+ blender::MutableSpan<blender::float3> vectors =
+ params.uninitialized_single_output<blender::float3>(3, "XYZ");
+
+ for (uint i : mask) {
+ vectors[i] = {xs[i], ys[i], zs[i]};
+ }
+ }
+};
+
+static void sh_node_combxyz_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ static MF_CombineXYZ combine_fn;
+ builder.set_matching_fn(combine_fn);
+}
+
void register_node_type_sh_combxyz(void)
{
static bNodeType ntype;
@@ -83,6 +153,7 @@ void register_node_type_sh_combxyz(void)
sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out);
node_type_gpu(&ntype, gpu_shader_combxyz);
+ ntype.expand_in_mf_network = sh_node_combxyz_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
index 0daa948c139..d2c4413b862 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
@@ -18,6 +18,7 @@
*/
#include "../node_shader_util.h"
+#include "sky_model.h"
/* **************** OUTPUT ******************** */
@@ -43,9 +44,10 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
tex->ground_albedo = 0.3f;
tex->sun_disc = true;
tex->sun_size = DEG2RADF(0.545);
+ tex->sun_intensity = 1.0f;
tex->sun_elevation = M_PI_2;
tex->sun_rotation = 0.0f;
- tex->altitude = 0;
+ tex->altitude = 0.0f;
tex->air_density = 1.0f;
tex->dust_density = 1.0f;
tex->ozone_density = 1.0f;
@@ -53,19 +55,172 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = tex;
}
+typedef struct SkyModelPreetham {
+ float config_Y[5], config_x[5], config_y[5]; /* named after xyY color space */
+ float radiance[3];
+} SkyModelPreetham;
+
+typedef struct XYZ_to_RGB /* transposed imbuf_xyz_to_rgb, passed as 3x vec3 */
+{
+ float r[3], g[3], b[3];
+} XYZ_to_RGB;
+
+static float sky_perez_function(const float *lam, float theta, float gamma)
+{
+ float ctheta = cosf(theta);
+ float cgamma = cosf(gamma);
+
+ return (1.0 + lam[0] * expf(lam[1] / ctheta)) *
+ (1.0 + lam[2] * expf(lam[3] * gamma) + lam[4] * cgamma * cgamma);
+}
+
+static void sky_precompute_old(SkyModelPreetham *sunsky, const float sun_angles[], float turbidity)
+{
+ float theta = sun_angles[0];
+ float theta2 = theta * theta;
+ float theta3 = theta2 * theta;
+ float T = turbidity;
+ float T2 = T * T;
+ float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI - 2.0f * theta);
+
+ sunsky->radiance[0] = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
+ sunsky->radiance[0] *= 0.06f;
+
+ sunsky->radiance[1] = (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
+ (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) *
+ T +
+ (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
+
+ sunsky->radiance[2] = (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
+ (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) *
+ T +
+ (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
+
+ sunsky->config_Y[0] = (0.1787f * T - 1.4630f);
+ sunsky->config_Y[1] = (-0.3554f * T + 0.4275f);
+ sunsky->config_Y[2] = (-0.0227f * T + 5.3251f);
+ sunsky->config_Y[3] = (0.1206f * T - 2.5771f);
+ sunsky->config_Y[4] = (-0.0670f * T + 0.3703f);
+
+ sunsky->config_x[0] = (-0.0193f * T - 0.2592f);
+ sunsky->config_x[1] = (-0.0665f * T + 0.0008f);
+ sunsky->config_x[2] = (-0.0004f * T + 0.2125f);
+ sunsky->config_x[3] = (-0.0641f * T - 0.8989f);
+ sunsky->config_x[4] = (-0.0033f * T + 0.0452f);
+
+ sunsky->config_y[0] = (-0.0167f * T - 0.2608f);
+ sunsky->config_y[1] = (-0.0950f * T + 0.0092f);
+ sunsky->config_y[2] = (-0.0079f * T + 0.2102f);
+ sunsky->config_y[3] = (-0.0441f * T - 1.6537f);
+ sunsky->config_y[4] = (-0.0109f * T + 0.0529f);
+
+ sunsky->radiance[0] /= sky_perez_function(sunsky->config_Y, 0, theta);
+ sunsky->radiance[1] /= sky_perez_function(sunsky->config_x, 0, theta);
+ sunsky->radiance[2] /= sky_perez_function(sunsky->config_y, 0, theta);
+}
+
+static void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data)
+{
+ const float *xyz_to_rgb = IMB_colormangement_get_xyz_to_rgb();
+ data->r[0] = xyz_to_rgb[0];
+ data->r[1] = xyz_to_rgb[3];
+ data->r[2] = xyz_to_rgb[6];
+ data->g[0] = xyz_to_rgb[1];
+ data->g[1] = xyz_to_rgb[4];
+ data->g[2] = xyz_to_rgb[7];
+ data->b[0] = xyz_to_rgb[2];
+ data->b[1] = xyz_to_rgb[5];
+ data->b[2] = xyz_to_rgb[8];
+}
+
static int node_shader_gpu_tex_sky(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(mat, CD_ORCO, "");
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
+ node_shader_gpu_tex_mapping(mat, node, in, out);
+ NodeTexSky *tex = (NodeTexSky *)node->storage;
+ float sun_angles[2]; /* [0]=theta=zenith angle [1]=phi=azimuth */
+ sun_angles[0] = acosf(tex->sun_direction[2]);
+ sun_angles[1] = atan2f(tex->sun_direction[0], tex->sun_direction[1]);
+
+ if (tex->sky_model == 0) {
+ /* Preetham */
+ SkyModelPreetham sunsky;
+ sky_precompute_old(&sunsky, sun_angles, tex->turbidity);
+ XYZ_to_RGB xyz_to_rgb;
+ get_XYZ_to_RGB_for_gpu(&xyz_to_rgb);
+ return GPU_stack_link(mat,
+ node,
+ "node_tex_sky_preetham",
+ in,
+ out,
+ /* Pass config_Y/x/y as 3x(vec4+float) */
+ GPU_uniform(&sunsky.config_Y[0]),
+ GPU_uniform(&sunsky.config_Y[4]),
+ GPU_uniform(&sunsky.config_x[0]),
+ GPU_uniform(&sunsky.config_x[4]),
+ GPU_uniform(&sunsky.config_y[0]),
+ GPU_uniform(&sunsky.config_y[4]),
+ GPU_uniform(sun_angles),
+ GPU_uniform(sunsky.radiance),
+ GPU_uniform(xyz_to_rgb.r),
+ GPU_uniform(xyz_to_rgb.g),
+ GPU_uniform(xyz_to_rgb.b));
+ }
+ else if (tex->sky_model == 1) {
+ /* Hosek / Wilkie */
+ sun_angles[0] = fmin(M_PI_2, sun_angles[0]); /* clamp to horizon */
+ SKY_ArHosekSkyModelState *sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init(
+ tex->turbidity, tex->ground_albedo, fmax(0.0, M_PI_2 - sun_angles[0]));
+ /* Pass sky_state->configs[3][9] as 3*(vec4+vec4)+vec3 */
+ float config_x07[8], config_y07[8], config_z07[8], config_xyz8[3];
+ for (int i = 0; i < 8; ++i) {
+ config_x07[i] = (float)sky_state->configs[0][i];
+ config_y07[i] = (float)sky_state->configs[1][i];
+ config_z07[i] = (float)sky_state->configs[2][i];
+ }
+ for (int i = 0; i < 3; ++i) {
+ config_xyz8[i] = (float)sky_state->configs[i][8];
+ }
+ float radiance[3];
+ for (int i = 0; i < 3; i++) {
+ radiance[i] = sky_state->radiances[i] * (2 * M_PI / 683);
+ }
+ SKY_arhosekskymodelstate_free(sky_state);
+ XYZ_to_RGB xyz_to_rgb;
+ get_XYZ_to_RGB_for_gpu(&xyz_to_rgb);
+ return GPU_stack_link(mat,
+ node,
+ "node_tex_sky_hosekwilkie",
+ in,
+ out,
+ GPU_uniform(&config_x07[0]),
+ GPU_uniform(&config_x07[4]),
+ GPU_uniform(&config_y07[0]),
+ GPU_uniform(&config_y07[4]),
+ GPU_uniform(&config_z07[0]),
+ GPU_uniform(&config_z07[4]),
+ GPU_uniform(config_xyz8),
+ GPU_uniform(sun_angles),
+ GPU_uniform(radiance),
+ GPU_uniform(xyz_to_rgb.r),
+ GPU_uniform(xyz_to_rgb.g),
+ GPU_uniform(xyz_to_rgb.b));
+ }
+ else {
+ return GPU_stack_link(mat, node, "node_tex_sky_nishita", in, out);
}
+}
- node_shader_gpu_tex_mapping(mat, node, in, out);
+static void node_shader_update_sky(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
- return GPU_stack_link(mat, node, "node_tex_sky", in, out);
+ NodeTexSky *tex = (NodeTexSky *)node->storage;
+ nodeSetSocketAvailability(sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
}
/* node type definition */
@@ -79,6 +234,8 @@ void register_node_type_sh_tex_sky(void)
node_type_init(&ntype, node_shader_init_tex_sky);
node_type_storage(&ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_sky);
+ /* remove Vector input for Nishita */
+ node_type_update(&ntype, node_shader_update_sky);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.c b/source/blender/nodes/shader/nodes/node_shader_value.cc
index c32e9e1d581..64701018d63 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.c
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -39,13 +39,21 @@ static int gpu_shader_value(GPUMaterial *mat,
return GPU_stack_link(mat, node, "set_value", in, out, link);
}
+static void sh_node_value_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ const bNodeSocket *bsocket = builder.dnode().output(0).bsocket();
+ const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value;
+ builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
+}
+
void register_node_type_sh_value(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
node_type_socket_templates(&ntype, NULL, sh_node_value_out);
node_type_gpu(&ntype, gpu_shader_value);
+ ntype.expand_in_mf_network = sh_node_value_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.c b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index b719fe03d9b..414d05e996a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -34,44 +34,74 @@ static bNodeSocketTemplate sh_node_vector_math_in[] = {
static bNodeSocketTemplate sh_node_vector_math_out[] = {
{SOCK_VECTOR, N_("Vector")}, {SOCK_FLOAT, N_("Value")}, {-1, ""}};
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_VECTOR_MATH_ADD:
+ return "vector_math_add";
+ case NODE_VECTOR_MATH_SUBTRACT:
+ return "vector_math_subtract";
+ case NODE_VECTOR_MATH_MULTIPLY:
+ return "vector_math_multiply";
+ case NODE_VECTOR_MATH_DIVIDE:
+ return "vector_math_divide";
+
+ case NODE_VECTOR_MATH_CROSS_PRODUCT:
+ return "vector_math_cross";
+ case NODE_VECTOR_MATH_PROJECT:
+ return "vector_math_project";
+ case NODE_VECTOR_MATH_REFLECT:
+ return "vector_math_reflect";
+ case NODE_VECTOR_MATH_DOT_PRODUCT:
+ return "vector_math_dot";
+
+ case NODE_VECTOR_MATH_DISTANCE:
+ return "vector_math_distance";
+ case NODE_VECTOR_MATH_LENGTH:
+ return "vector_math_length";
+ case NODE_VECTOR_MATH_SCALE:
+ return "vector_math_scale";
+ case NODE_VECTOR_MATH_NORMALIZE:
+ return "vector_math_normalize";
+
+ case NODE_VECTOR_MATH_SNAP:
+ return "vector_math_snap";
+ case NODE_VECTOR_MATH_FLOOR:
+ return "vector_math_floor";
+ case NODE_VECTOR_MATH_CEIL:
+ return "vector_math_ceil";
+ case NODE_VECTOR_MATH_MODULO:
+ return "vector_math_modulo";
+ case NODE_VECTOR_MATH_FRACTION:
+ return "vector_math_fraction";
+ case NODE_VECTOR_MATH_ABSOLUTE:
+ return "vector_math_absolute";
+ case NODE_VECTOR_MATH_MINIMUM:
+ return "vector_math_minimum";
+ case NODE_VECTOR_MATH_MAXIMUM:
+ return "vector_math_maximum";
+ case NODE_VECTOR_MATH_WRAP:
+ return "vector_math_wrap";
+ case NODE_VECTOR_MATH_SINE:
+ return "vector_math_sine";
+ case NODE_VECTOR_MATH_COSINE:
+ return "vector_math_cosine";
+ case NODE_VECTOR_MATH_TANGENT:
+ return "vector_math_tangent";
+ }
+
+ return nullptr;
+}
+
static int gpu_shader_vector_math(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- static const char *names[] = {
- [NODE_VECTOR_MATH_ADD] = "vector_math_add",
- [NODE_VECTOR_MATH_SUBTRACT] = "vector_math_subtract",
- [NODE_VECTOR_MATH_MULTIPLY] = "vector_math_multiply",
- [NODE_VECTOR_MATH_DIVIDE] = "vector_math_divide",
-
- [NODE_VECTOR_MATH_CROSS_PRODUCT] = "vector_math_cross",
- [NODE_VECTOR_MATH_PROJECT] = "vector_math_project",
- [NODE_VECTOR_MATH_REFLECT] = "vector_math_reflect",
- [NODE_VECTOR_MATH_DOT_PRODUCT] = "vector_math_dot",
-
- [NODE_VECTOR_MATH_DISTANCE] = "vector_math_distance",
- [NODE_VECTOR_MATH_LENGTH] = "vector_math_length",
- [NODE_VECTOR_MATH_SCALE] = "vector_math_scale",
- [NODE_VECTOR_MATH_NORMALIZE] = "vector_math_normalize",
-
- [NODE_VECTOR_MATH_SNAP] = "vector_math_snap",
- [NODE_VECTOR_MATH_FLOOR] = "vector_math_floor",
- [NODE_VECTOR_MATH_CEIL] = "vector_math_ceil",
- [NODE_VECTOR_MATH_MODULO] = "vector_math_modulo",
- [NODE_VECTOR_MATH_FRACTION] = "vector_math_fraction",
- [NODE_VECTOR_MATH_ABSOLUTE] = "vector_math_absolute",
- [NODE_VECTOR_MATH_MINIMUM] = "vector_math_minimum",
- [NODE_VECTOR_MATH_MAXIMUM] = "vector_math_maximum",
- [NODE_VECTOR_MATH_WRAP] = "vector_math_wrap",
- [NODE_VECTOR_MATH_SINE] = "vector_math_sine",
- [NODE_VECTOR_MATH_COSINE] = "vector_math_cosine",
- [NODE_VECTOR_MATH_TANGENT] = "vector_math_tangent",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- return GPU_stack_link(mat, node, names[node->custom1], in, out);
+ const char *name = gpu_shader_get_name(node->custom1);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
}
else {
return 0;
@@ -80,8 +110,8 @@ static int gpu_shader_vector_math(GPUMaterial *mat,
static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node)
{
- bNodeSocket *sockB = BLI_findlink(&node->inputs, 1);
- bNodeSocket *sockC = BLI_findlink(&node->inputs, 2);
+ bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector");
@@ -130,6 +160,43 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node
}
}
+static void sh_node_vector_math_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder)
+{
+ using blender::float3;
+
+ /* TODO: Implement other operations. */
+ const int mode = builder.bnode().custom1;
+ switch (mode) {
+ case NODE_VECTOR_MATH_ADD: {
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ "Add", [](float3 a, float3 b) { return a + b; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_VECTOR_MATH_SUBTRACT: {
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ "Subtract", [](float3 a, float3 b) { return a - b; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_VECTOR_MATH_MULTIPLY: {
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ "Multiply", [](float3 a, float3 b) { return a * b; }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_VECTOR_MATH_DIVIDE: {
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ "Divide", [](float3 a, float3 b) { return float3::safe_divide(a, b); }};
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default:
+ BLI_assert(false);
+ break;
+ };
+}
+
void register_node_type_sh_vect_math(void)
{
static bNodeType ntype;
@@ -139,6 +206,7 @@ void register_node_type_sh_vect_math(void)
node_type_label(&ntype, node_vector_math_label);
node_type_gpu(&ntype, gpu_shader_vector_math);
node_type_update(&ntype, node_shader_update_vector_math);
+ ntype.expand_in_mf_network = sh_node_vector_math_expand_in_mf_network;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
index 70c924a7f85..40576b68dd5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
@@ -39,6 +39,10 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
+ if (U.experimental.use_sculpt_vertex_colors) {
+ GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_PROP_COLOR, vertexColor->layer_name);
+ return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
+ }
GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index 6246bf54f75..1764d0a910c 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -303,7 +303,7 @@ void BPH_hair_volume_grid_clear(HairGrid *grid)
}
}
-BLI_INLINE bool hair_grid_point_valid(const float vec[3], float gmin[3], float gmax[3])
+BLI_INLINE bool hair_grid_point_valid(const float vec[3], const float gmin[3], const float gmax[3])
{
return !(vec[0] < gmin[0] || vec[1] < gmin[1] || vec[2] < gmin[2] || vec[0] > gmax[0] ||
vec[1] > gmax[1] || vec[2] > gmax[2]);
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 5ec4c750d5d..54d38f3c10b 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -90,7 +90,7 @@ typedef struct fmatrix3x3 {
///////////////////////////
/* simple vector code */
/* STATUS: verified */
-DO_INLINE void mul_fvector_S(float to[3], float from[3], float scalar)
+DO_INLINE void mul_fvector_S(float to[3], const float from[3], float scalar)
{
to[0] = from[0] * scalar;
to[1] = from[1] * scalar;
@@ -429,7 +429,7 @@ DO_INLINE void mul_fmatrix_S(float matrix[3][3], float scalar)
/* a vector multiplied by a 3x3 matrix */
/* STATUS: verified */
-DO_INLINE void mul_fvector_fmatrix(float *to, float *from, float matrix[3][3])
+DO_INLINE void mul_fvector_fmatrix(float *to, const float *from, float matrix[3][3])
{
to[0] = matrix[0][0] * from[0] + matrix[1][0] * from[1] + matrix[2][0] * from[2];
to[1] = matrix[0][1] * from[0] + matrix[1][1] * from[1] + matrix[2][1] * from[2];
@@ -478,7 +478,7 @@ DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float fro
to[2] += dot_v3v3(matrix[2], from);
}
-DO_INLINE void muladd_fmatrixT_fvector(float to[3], float matrix[3][3], float from[3])
+DO_INLINE void muladd_fmatrixT_fvector(float to[3], float matrix[3][3], const float from[3])
{
to[0] += matrix[0][0] * from[0] + matrix[1][0] * from[1] + matrix[2][0] * from[2];
to[1] += matrix[0][1] * from[0] + matrix[1][1] * from[1] + matrix[2][1] * from[2];
@@ -1869,7 +1869,7 @@ bool BPH_mass_spring_force_spring_bending(
}
}
-BLI_INLINE void poly_avg(lfVector *data, int *inds, int len, float r_avg[3])
+BLI_INLINE void poly_avg(lfVector *data, const int *inds, int len, float r_avg[3])
{
float fact = 1.0f / (float)len;
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 5471fc25f37..2ad2794c76f 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -487,7 +487,7 @@ static int gl_buffer_type_from_py_buffer(Py_buffer *pybuffer)
return -1; /* UNKNOWN */
}
-static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2)
+static bool compare_dimensions(int ndim, const int *dim1, const Py_ssize_t *dim2)
{
for (int i = 0; i < ndim; i++) {
if (dim1[i] != dim2[i]) {
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 957d49eb04e..4ee936aff91 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -50,7 +50,6 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
#include "BKE_global.h"
-#include "BKE_lib_override.h"
#include "DNA_ID.h"
@@ -392,29 +391,6 @@ static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void
return PyC_UnicodeFromByte(G.autoexec_fail);
}
-PyDoc_STRVAR(bpy_app_use_override_library_doc,
- "Boolean, whether library override is exposed in UI or not.");
-static PyObject *bpy_app_use_override_library_get(PyObject *UNUSED(self), void *UNUSED(closure))
-{
- return PyBool_FromLong((long)BKE_lib_override_library_is_enabled());
-}
-
-static int bpy_app_use_override_library_set(PyObject *UNUSED(self),
- PyObject *value,
- void *UNUSED(closure))
-{
- const int param = PyC_Long_AsBool(value);
-
- if (param == -1 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "bpy.app.use_override_library must be a boolean");
- return -1;
- }
-
- BKE_lib_override_library_enable((const bool)param);
-
- return 0;
-}
-
static PyGetSetDef bpy_app_getsets[] = {
{"debug", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG},
{"debug_ffmpeg",
@@ -485,11 +461,6 @@ static PyGetSetDef bpy_app_getsets[] = {
(void *)G_DEBUG_GPU_MEM},
{"debug_io", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG_IO},
- {"use_override_library",
- bpy_app_use_override_library_get,
- bpy_app_use_override_library_set,
- bpy_app_use_override_library_doc,
- NULL},
{"use_event_simulate",
bpy_app_global_flag_get,
bpy_app_global_flag_set__only_disable,
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index fe086b61097..97344ce1326 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -48,6 +48,6 @@ struct bContext *BPy_GetContext(void);
void BPy_SetContext(struct bContext *C);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
-extern void bpy_context_clear(struct bContext *C, PyGILState_STATE *gilstate);
+extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate);
#endif /* __BPY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 6da1715b02d..be5a92309f2 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -136,7 +136,7 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
}
/* context should be used but not now because it causes some bugs */
-void bpy_context_clear(bContext *UNUSED(C), PyGILState_STATE *gilstate)
+void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
{
py_call_level--;
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 3df0d805c5b..a1f9d4afc51 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -88,6 +88,37 @@ static const EnumPropertyItem property_flag_enum_items[] = {
"'LIBRARY_EDITABLE'].\n" \
" :type options: set\n"
+static const EnumPropertyItem property_flag_override_items[] = {
+ {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
+ "LIBRARY_OVERRIDABLE",
+ 0,
+ "Library Overridable",
+ "Allow that property to be overridable from library linked data-blocks"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+#define BPY_PROPDEF_OPTIONS_OVERRIDE_DOC \
+ " :arg options: Enumerator in ['LIBRARY_OVERRIDE'].\n" \
+ " :type options: set\n"
+
+static const EnumPropertyItem property_flag_override_collection_items[] = {
+ {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
+ "LIBRARY_OVERRIDABLE",
+ 0,
+ "Library Overridable",
+ "Make that property editable in library overrides of linked data-blocks"},
+ {PROPOVERRIDE_NO_PROP_NAME,
+ "NO_PROPERTY_NAME",
+ 0,
+ "No Name",
+ "Do not use the names of the items, only their indices in the collection"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+#define BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC \
+ " :arg options: Enumerator in ['LIBRARY_OVERRIDE', 'NO_PROPERTY_NAME'].\n" \
+ " :type options: set\n"
+
/* subtypes */
/* XXX Keep in sync with rna_rna.c's rna_enum_property_subtype_items ???
* Currently it is not...
@@ -202,6 +233,11 @@ static void bpy_prop_assign_flag(PropertyRNA *prop, const int flag)
}
}
+static void bpy_prop_assign_flag_override(PropertyRNA *prop, const int flag_override)
+{
+ RNA_def_property_override_flag(prop, flag_override);
+}
+
/* operators and classes use this so it can store the args given but defer
* running it until the operator runs where these values are used to setup
* the default args for that operator instance */
@@ -1959,7 +1995,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
/* terse macros for error checks shared between all funcs cant use function
* calls because of static strings passed to pyrna_set_to_enum_bitfield */
-#define BPY_PROPDEF_CHECK(_func, _property_flag_items) \
+#define BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items) \
if (UNLIKELY(id_len >= MAX_IDPROP_NAME)) { \
PyErr_Format(PyExc_TypeError, \
#_func "(): '%.200s' too long, max length is %d", \
@@ -1975,6 +2011,12 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
_property_flag_items, pyopts, &opts, #_func "(options={ ...}):"))) { \
return NULL; \
} \
+ if (UNLIKELY(pyopts_override && pyrna_set_to_enum_bitfield(_property_flag_override_items, \
+ pyopts_override, \
+ &opts_override, \
+ #_func "(override={ ...}):"))) { \
+ return NULL; \
+ } \
{ \
const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna); \
if (py_tags && !tag_defines) { \
@@ -1990,8 +2032,9 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
} \
(void)0
-#define BPY_PROPDEF_SUBTYPE_CHECK(_func, _property_flag_items, _subtype) \
- BPY_PROPDEF_CHECK(_func, _property_flag_items); \
+#define BPY_PROPDEF_SUBTYPE_CHECK( \
+ _func, _property_flag_items, _property_flag_override_items, _subtype) \
+ BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items); \
if (UNLIKELY(pysubtype && RNA_enum_value_from_id(_subtype, pysubtype, &subtype) == 0)) { \
const char *enum_str = BPy_enum_as_string(_subtype); \
PyErr_Format(PyExc_TypeError, \
@@ -2099,7 +2142,8 @@ PyDoc_STRVAR(BPy_BoolProperty_doc,
"description=\"\", "
"default=False, "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "override=set(), "
+ "tags=set(), "
"subtype='NONE', "
"update=None, "
"get=None, "
@@ -2107,8 +2151,9 @@ PyDoc_STRVAR(BPy_BoolProperty_doc,
"\n"
" Returns a new boolean property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_OPTIONS_DOC
- BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
+ BPY_PROPDEF_SUBTYPE_NUMBER_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC
+ BPY_PROPDEF_SET_DOC);
static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2121,7 +2166,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
bool def = false;
PropertyRNA *prop;
PyObject *pyopts = NULL;
+ PyObject *pyopts_override = NULL;
int opts = 0;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2136,6 +2183,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
"description",
"default",
"options",
+ "override",
"tags",
"subtype",
"update",
@@ -2143,7 +2191,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#|ssO&O!O!sOOO:BoolProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|ssO&O!O!O!sOOO:BoolProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2156,6 +2204,8 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&update_cb,
@@ -2164,7 +2214,10 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty, property_flag_items, property_subtype_number_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_number_items);
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
@@ -2186,6 +2239,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_boolean(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2194,24 +2250,26 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
Py_RETURN_NONE;
}
-PyDoc_STRVAR(BPy_BoolVectorProperty_doc,
- ".. function:: BoolVectorProperty(name=\"\", "
- "description=\"\", "
- "default=(False, False, False), "
- "options={'ANIMATABLE'}, "
- "tags={}, "
- "subtype='NONE', "
- "size=3, "
- "update=None, "
- "get=None, "
- "set=None)\n"
- "\n"
- " Returns a new vector boolean property definition.\n"
- "\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
- " :arg default: sequence of booleans the length of *size*.\n"
- " :type default: sequence\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_TAGS_DOC
- BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+PyDoc_STRVAR(
+ BPy_BoolVectorProperty_doc,
+ ".. function:: BoolVectorProperty(name=\"\", "
+ "description=\"\", "
+ "default=(False, False, False), "
+ "options={'ANIMATABLE'}, "
+ "override=set(), "
+ "tags=set(), "
+ "subtype='NONE', "
+ "size=3, "
+ "update=None, "
+ "get=None, "
+ "set=None)\n"
+ "\n"
+ " Returns a new vector boolean property definition.\n"
+ "\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ " :arg default: sequence of booleans the length of *size*.\n"
+ " :type default: sequence\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
+ BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
+ BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2226,7 +2284,9 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
PropertyRNA *prop;
PyObject *pydef = NULL;
PyObject *pyopts = NULL;
+ PyObject *pyopts_override = NULL;
int opts = 0;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2241,6 +2301,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
"description",
"default",
"options",
+ "override",
"tags",
"subtype",
"size",
@@ -2249,7 +2310,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#|ssOO!O!siOOO:BoolVectorProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|ssOO!O!O!siOOO:BoolVectorProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2261,6 +2322,8 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&size,
@@ -2270,8 +2333,10 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(
- BoolVectorProperty, property_flag_items, property_subtype_array_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(BoolVectorProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_array_items);
if (size < 1 || size > PYRNA_STACK_ARRAY) {
PyErr_Format(
@@ -2314,6 +2379,9 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_boolean_array(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2322,28 +2390,29 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
Py_RETURN_NONE;
}
-PyDoc_STRVAR(BPy_IntProperty_doc,
- ".. function:: IntProperty(name=\"\", "
- "description=\"\", "
- "default=0, "
- "min=-2**31, max=2**31-1, "
- "soft_min=-2**31, soft_max=2**31-1, "
- "step=1, "
- "options={'ANIMATABLE'}, "
- "tags={}, "
- "subtype='NONE', "
- "update=None, "
- "get=None, "
- "set=None)\n"
- "\n"
- " Returns a new int property definition.\n"
- "\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_NUM_MIN_DOC
- " :type min: int\n" BPY_PROPDEF_NUM_MAX_DOC
- " :type max: int\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
- " :type soft_min: int\n" BPY_PROPDEF_NUM_SOFTMIN_DOC
- " :type soft_max: int\n" BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC
- BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+PyDoc_STRVAR(
+ BPy_IntProperty_doc,
+ ".. function:: IntProperty(name=\"\", "
+ "description=\"\", "
+ "default=0, "
+ "min=-2**31, max=2**31-1, "
+ "soft_min=-2**31, soft_max=2**31-1, "
+ "step=1, "
+ "options={'ANIMATABLE'}, "
+ "override=set(), "
+ "tags=set(), "
+ "subtype='NONE', "
+ "update=None, "
+ "get=None, "
+ "set=None)\n"
+ "\n"
+ " Returns a new int property definition.\n"
+ "\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_NUM_MIN_DOC
+ " :type min: int\n" BPY_PROPDEF_NUM_MAX_DOC " :type max: int\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
+ " :type soft_min: int\n" BPY_PROPDEF_NUM_SOFTMIN_DOC
+ " :type soft_max: int\n" BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC
+ BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC
+ BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2357,6 +2426,8 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
PyObject *pyopts = NULL;
int opts = 0;
+ PyObject *pyopts_override = NULL;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2376,6 +2447,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
"soft_max",
"step",
"options",
+ "override",
"tags",
"subtype",
"update",
@@ -2383,7 +2455,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#|ssiiiiiiO!O!sOOO:IntProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|ssiiiiiiO!O!O!sOOO:IntProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2400,6 +2472,8 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&update_cb,
@@ -2408,7 +2482,10 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(IntProperty, property_flag_items, property_subtype_number_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(IntProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_number_items);
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
@@ -2432,6 +2509,9 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_int(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2447,7 +2527,8 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc,
"soft_max=2**31-1, "
"step=1, "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "override=set(), "
+ "tags=set(), "
"subtype='NONE', "
"size=3, "
"update=None, "
@@ -2462,8 +2543,9 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc,
" :type max: int\n" BPY_PROPDEF_NUM_SOFTMIN_DOC
" :type soft_min: int\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
" :type soft_max: int\n" BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC
- BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
- BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
+ BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC
+ BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2480,6 +2562,8 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *pydef = NULL;
PyObject *pyopts = NULL;
int opts = 0;
+ PyObject *pyopts_override = NULL;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2499,6 +2583,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
"soft_max",
"step",
"options",
+ "override",
"tags",
"subtype",
"size",
@@ -2507,7 +2592,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#|ssOiiiiiO!O!siOOO:IntVectorProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|ssOiiiiiO!O!O!siOOO:IntVectorProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2524,6 +2609,8 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&size,
@@ -2533,8 +2620,10 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(
- IntVectorProperty, property_flag_items, property_subtype_array_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(IntVectorProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_array_items);
if (size < 1 || size > PYRNA_STACK_ARRAY) {
PyErr_Format(
@@ -2575,6 +2664,9 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_int_array(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2591,7 +2683,8 @@ PyDoc_STRVAR(BPy_FloatProperty_doc,
"step=3, "
"precision=2, "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "override=set(), "
+ "tags=set(), "
"subtype='NONE', "
"unit='NONE', "
"update=None, "
@@ -2604,9 +2697,9 @@ PyDoc_STRVAR(BPy_FloatProperty_doc,
" :type max: float\n" BPY_PROPDEF_NUM_SOFTMIN_DOC
" :type soft_min: float\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
" :type soft_max: float\n" BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC
- BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC
- BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC
- BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
+ BPY_PROPDEF_SUBTYPE_NUMBER_DOC BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_UPDATE_DOC
+ BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2622,6 +2715,8 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
PyObject *pyopts = NULL;
int opts = 0;
+ PyObject *pyopts_override = NULL;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2633,26 +2728,11 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *py_tags = NULL;
static const char *_keywords[] = {
- "attr",
- "name",
- "description",
- "default",
- "min",
- "max",
- "soft_min",
- "soft_max",
- "step",
- "precision",
- "options",
- "tags",
- "subtype",
- "unit",
- "update",
- "get",
- "set",
- NULL,
+ "attr", "name", "description", "default", "min", "max", "soft_min",
+ "soft_max", "step", "precision", "options", "override", "tags", "subtype",
+ "unit", "update", "get", "set", NULL,
};
- static _PyArg_Parser _parser = {"s#|ssffffffiO!O!ssOOO:FloatProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|ssffffffiO!O!O!ssOOO:FloatProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2670,6 +2750,8 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&pyunit,
@@ -2679,7 +2761,10 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty, property_flag_items, property_subtype_number_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_number_items);
if (pyunit && RNA_enum_value_from_id(rna_enum_property_unit_items, pyunit, &unit) == 0) {
PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit", pyunit);
@@ -2708,6 +2793,9 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_float(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2724,7 +2812,8 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc,
"step=3, "
"precision=2, "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "override=set(), "
+ "tags=set(), "
"subtype='NONE', "
"unit='NONE', "
"size=3, "
@@ -2739,8 +2828,8 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc,
" :type min: float\n" BPY_PROPDEF_NUM_MAX_DOC
" :type max: float\n" BPY_PROPDEF_NUM_SOFTMIN_DOC
" :type soft_min: float\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
- " :type soft_max: float\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_TAGS_DOC
- BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC
+ " :type soft_max: float\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
+ BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC
BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -2759,6 +2848,8 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
PyObject *pydef = NULL;
PyObject *pyopts = NULL;
int opts = 0;
+ PyObject *pyopts_override = NULL;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2770,11 +2861,11 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
PyObject *py_tags = NULL;
static const char *_keywords[] = {
- "attr", "name", "description", "default", "min", "max", "soft_min",
- "soft_max", "step", "precision", "options", "tags", "subtype", "unit",
- "size", "update", "get", "set", NULL,
+ "attr", "name", "description", "default", "min", "max", "soft_min",
+ "soft_max", "step", "precision", "options", "override", "tags", "subtype",
+ "unit", "size", "update", "get", "set", NULL,
};
- static _PyArg_Parser _parser = {"s#|ssOfffffiO!O!ssiOOO:FloatVectorProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|ssOfffffiO!O!O!ssiOOO:FloatVectorProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2792,6 +2883,8 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&pyunit,
@@ -2802,8 +2895,10 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(
- FloatVectorProperty, property_flag_items, property_subtype_array_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(FloatVectorProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_array_items);
if (pyunit && RNA_enum_value_from_id(rna_enum_property_unit_items, pyunit, &unit) == 0) {
PyErr_Format(PyExc_TypeError, "FloatVectorProperty(unit='%s'): invalid unit", pyunit);
@@ -2850,6 +2945,9 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_float_array(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2863,7 +2961,8 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
"default=\"\", "
"maxlen=0, "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "options=set(), "
+ "tags=set(), "
"subtype='NONE', "
"update=None, "
"get=None, "
@@ -2874,9 +2973,9 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
" :arg default: initializer string.\n"
" :type default: string\n"
" :arg maxlen: maximum length of the string.\n"
- " :type maxlen: int\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_TAGS_DOC
- BPY_PROPDEF_SUBTYPE_STRING_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC
- BPY_PROPDEF_SET_DOC);
+ " :type maxlen: int\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
+ BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_STRING_DOC BPY_PROPDEF_UPDATE_DOC
+ BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2890,6 +2989,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PropertyRNA *prop;
PyObject *pyopts = NULL;
int opts = 0;
+ PyObject *pyopts_override = NULL;
+ int opts_override = 0;
int prop_tags = 0;
const char *pysubtype = NULL;
int subtype = PROP_NONE;
@@ -2905,6 +3006,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"default",
"maxlen",
"options",
+ "override",
"tags",
"subtype",
"update",
@@ -2912,7 +3014,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#|sssiO!O!sOOO:StringProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#|sssiO!O!O!sOOO:StringProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -2925,6 +3027,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&pysubtype,
&update_cb,
@@ -2933,7 +3037,10 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
return NULL;
}
- BPY_PROPDEF_SUBTYPE_CHECK(StringProperty, property_flag_items, property_subtype_string_items);
+ BPY_PROPDEF_SUBTYPE_CHECK(StringProperty,
+ property_flag_items,
+ property_flag_override_items,
+ property_subtype_string_items);
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
@@ -2961,6 +3068,9 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_string(prop, get_cb, set_cb);
RNA_def_property_duplicate_pointers(srna, prop);
@@ -2975,7 +3085,8 @@ PyDoc_STRVAR(
"description=\"\", "
"default=None, "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "override=set(), "
+ "tags=set(), "
"update=None, "
"get=None, "
"set=None)\n"
@@ -3019,8 +3130,9 @@ PyDoc_STRVAR(
"instead.\n"
" WARNING: Strings can not be specified for dynamic enums\n"
" (i.e. if a callback function is given as *items* parameter).\n"
- " :type default: string, integer or set\n" BPY_PROPDEF_OPTIONS_ENUM_DOC BPY_PROPDEF_TAGS_DOC
- BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ " :type default: string, integer or set\n" BPY_PROPDEF_OPTIONS_ENUM_DOC
+ BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_UPDATE_DOC
+ BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3037,6 +3149,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
PyObject *pyopts = NULL;
int opts = 0;
+ PyObject *pyopts_override = NULL;
+ int opts_override = 0;
int prop_tags = 0;
bool is_itemf = false;
PyObject *update_cb = NULL;
@@ -3051,13 +3165,14 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
"description",
"default",
"options",
+ "override",
"tags",
"update",
"get",
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#O|ssOO!O!OOO:EnumProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#O|ssOO!O!O!OOO:EnumProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -3070,6 +3185,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&update_cb,
&get_cb,
@@ -3077,7 +3194,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items);
+ BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items, property_flag_override_items);
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
@@ -3149,6 +3266,9 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
bpy_prop_callback_assign_update(prop, update_cb);
bpy_prop_callback_assign_enum(prop, get_cb, set_cb, (is_itemf ? items : NULL));
RNA_def_property_duplicate_pointers(srna, prop);
@@ -3194,14 +3314,15 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'}, "
- "tags={}, "
+ "override=set(), "
+ "tags=set(), "
"poll=None, "
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
"\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
- BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_POLL_DOC
- BPY_PROPDEF_UPDATE_DOC);
+ BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
+ BPY_PROPDEF_POLL_DOC BPY_PROPDEF_UPDATE_DOC);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3215,8 +3336,10 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
StructRNA *ptype;
PyObject *type = Py_None;
PyObject *pyopts = NULL;
+ PyObject *pyopts_override = NULL;
PyObject *py_tags = NULL;
int opts = 0;
+ int opts_override = 0;
int prop_tags = 0;
PyObject *update_cb = NULL, *poll_cb = NULL;
@@ -3226,12 +3349,13 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
"name",
"description",
"options",
+ "override",
"tags",
"poll",
"update",
NULL,
};
- static _PyArg_Parser _parser = {"s#O|ssO!O!OO:PointerProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#O|ssO!O!O!OO:PointerProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -3243,13 +3367,15 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags,
&poll_cb,
&update_cb)) {
return NULL;
}
- BPY_PROPDEF_CHECK(PointerProperty, property_flag_items);
+ BPY_PROPDEF_CHECK(PointerProperty, property_flag_items, property_flag_override_items);
ptype = pointer_type_from_py(type, "PointerProperty(...)");
if (!ptype) {
@@ -3275,6 +3401,9 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
if (RNA_struct_idprops_contains_datablock(ptype)) {
if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
@@ -3293,11 +3422,13 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc,
"name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'}, "
- "tags={})\n"
+ "override=set(), "
+ "tags=set())\n"
"\n"
" Returns a new collection property definition.\n"
"\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
- BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_TAGS_DOC);
+ BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC
+ BPY_PROPDEF_TAGS_DOC);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3311,8 +3442,10 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
StructRNA *ptype;
PyObject *type = Py_None;
PyObject *pyopts = NULL;
+ PyObject *pyopts_override = NULL;
PyObject *py_tags = NULL;
int opts = 0;
+ int opts_override = 0;
int prop_tags = 0;
static const char *_keywords[] = {
@@ -3321,10 +3454,11 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
"name",
"description",
"options",
+ "override",
"tags",
NULL,
};
- static _PyArg_Parser _parser = {"s#O|ssO!O!:CollectionProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"s#O|ssO!O!O!:CollectionProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
@@ -3336,11 +3470,14 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
&PySet_Type,
&pyopts,
&PySet_Type,
+ &pyopts_override,
+ &PySet_Type,
&py_tags)) {
return NULL;
}
- BPY_PROPDEF_CHECK(CollectionProperty, property_flag_items);
+ BPY_PROPDEF_CHECK(
+ CollectionProperty, property_flag_items, property_flag_override_collection_items);
ptype = pointer_type_from_py(type, "CollectionProperty(...):");
if (!ptype) {
@@ -3362,6 +3499,9 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+ if (pyopts_override) {
+ bpy_prop_assign_flag_override(prop, opts_override);
+ }
if (RNA_struct_idprops_contains_datablock(ptype)) {
if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index d792b2032b5..1c84e95672f 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -415,7 +415,7 @@ char pyrna_struct_keyframe_delete_doc[] =
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
"yet.\n"
" :type group: str\n"
- " :return: Success of keyframe deleation.\n"
+ " :return: Success of keyframe deletion.\n"
" :rtype: boolean\n";
PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
{
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index b607f1635e6..a4df8c3aef1 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -132,7 +132,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d
PyDoc_STRVAR(bpy_user_map_doc,
".. method:: user_map([subset=(id1, id2, ...)], key_types={..}, value_types={..})\n"
"\n"
- " Returns a mapping of all ID datablocks in current ``bpy.data`` to a set of all "
+ " Returns a mapping of all ID data-blocks in current ``bpy.data`` to a set of all "
"datablocks using them.\n"
"\n"
" For list of valid set members for key_types & value_types, see: "
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 63137e094b7..3e30c81c8c6 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -2526,7 +2526,6 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
}
if (mat1 && mat2) {
-#ifdef USE_MATHUTILS_ELEM_MUL
/* MATRIX * MATRIX */
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2540,7 +2539,6 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
mul_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
-#endif
}
else if (mat2) {
/*FLOAT/INT * MATRIX */
@@ -2584,7 +2582,6 @@ static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
}
if (mat1 && mat2) {
-#ifdef USE_MATHUTILS_ELEM_MUL
/* MATRIX *= MATRIX */
if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) {
PyErr_SetString(PyExc_ValueError,
@@ -2594,14 +2591,6 @@ static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
}
mul_vn_vn(mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
-#else
- PyErr_Format(PyExc_TypeError,
- "In place element-wise multiplication: "
- "not supported between '%.200s' and '%.200s' types",
- Py_TYPE(m1)->tp_name,
- Py_TYPE(m2)->tp_name);
- return NULL;
-#endif
}
else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
/* MATRIX *= FLOAT/INT */
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 7ce0ea5f249..2b7761b7678 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -962,11 +962,9 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
}
if (quat1 && quat2) { /* QUAT * QUAT (element-wise product) */
-#ifdef USE_MATHUTILS_ELEM_MUL
float quat[QUAT_SIZE];
mul_vn_vnvn(quat, quat1->quat, quat2->quat, QUAT_SIZE);
return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
-#endif
}
/* the only case this can happen (for a supported type is "FLOAT * QUAT") */
else if (quat2) { /* FLOAT * QUAT */
@@ -1007,17 +1005,8 @@ static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
}
}
- if (quat1 && quat2) { /* QUAT *= QUAT (inplace element-wise product) */
-#ifdef USE_MATHUTILS_ELEM_MUL
+ if (quat1 && quat2) { /* QUAT *= QUAT (in-place element-wise product). */
mul_vn_vn(quat1->quat, quat2->quat, QUAT_SIZE);
-#else
- PyErr_Format(PyExc_TypeError,
- "In place element-wise multiplication: "
- "not supported between '%.200s' and '%.200s' types",
- Py_TYPE(q1)->tp_name,
- Py_TYPE(q2)->tp_name);
- return NULL;
-#endif
}
else if (quat1 && (((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
/* QUAT *= FLOAT */
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 15ae811fd91..4b47440a530 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -1738,7 +1738,7 @@ static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar);
return Vector_CreatePyObject_alloc(tvec, vec->size, Py_TYPE(vec));
}
-#ifdef USE_MATHUTILS_ELEM_MUL
+
static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
{
float *tvec = PyMem_Malloc(vec1->size * sizeof(float));
@@ -1752,7 +1752,7 @@ static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
mul_vn_vnvn(tvec, vec1->vec, vec2->vec, vec1->size);
return Vector_CreatePyObject_alloc(tvec, vec1->size, Py_TYPE(vec1));
}
-#endif
+
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -1775,7 +1775,6 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
/* make sure v1 is always the vector */
if (vec1 && vec2) {
-#ifdef USE_MATHUTILS_ELEM_MUL
if (vec1->size != vec2->size) {
PyErr_SetString(PyExc_ValueError,
"Vector multiplication: "
@@ -1785,7 +1784,6 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
/* element-wise product */
return vector_mul_vec(vec1, vec2);
-#endif
}
else if (vec1) {
if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */
@@ -1832,7 +1830,6 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
/* Intentionally don't support (Quaternion, Matrix) here, uses reverse order instead. */
if (vec1 && vec2) {
-#ifdef USE_MATHUTILS_ELEM_MUL
if (vec1->size != vec2->size) {
PyErr_SetString(PyExc_ValueError,
"Vector multiplication: "
@@ -1840,16 +1837,8 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
return NULL;
}
- /* element-wise product inplace */
+ /* Element-wise product in-place. */
mul_vn_vn(vec1->vec, vec2->vec, vec1->size);
-#else
- PyErr_Format(PyExc_TypeError,
- "In place element-wise multiplication: "
- "not supported between '%.200s' and '%.200s' types",
- Py_TYPE(v1)->tp_name,
- Py_TYPE(v2)->tp_name);
- return NULL;
-#endif
}
else if (vec1 && (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) ==
0)) { /* VEC *= FLOAT */
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 59c0021e0f3..93dbac32c19 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1537,9 +1537,9 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject *UNUSED(self), PyObject *poi
* to fill values, with start_table and len_table giving the start index
* and length of the toplevel_len sub-lists.
*/
-static PyObject *list_of_lists_from_arrays(int *array,
- int *start_table,
- int *len_table,
+static PyObject *list_of_lists_from_arrays(const int *array,
+ const int *start_table,
+ const int *len_table,
int toplevel_len)
{
PyObject *ret, *sublist;
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 06f77854595..6e336604b59 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -694,14 +694,7 @@ void RE_bake_pixels_populate(Mesh *me,
const BakeImages *bake_images,
const char *uv_layer)
{
- BakeDataZSpan bd;
- size_t i;
- int a, p_id;
-
const MLoopUV *mloopuv;
- const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
- MLoopTri *looptri;
-
if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
@@ -714,25 +707,26 @@ void RE_bake_pixels_populate(Mesh *me,
return;
}
+ BakeDataZSpan bd;
bd.pixel_array = pixel_array;
bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan");
/* initialize all pixel arrays so we know which ones are 'blank' */
- for (i = 0; i < num_pixels; i++) {
+ for (int i = 0; i < num_pixels; i++) {
pixel_array[i].primitive_id = -1;
pixel_array[i].object_id = 0;
}
- for (i = 0; i < bake_images->size; i++) {
+ for (int i = 0; i < bake_images->size; i++) {
zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height);
}
- looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
+ const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
- p_id = -1;
- for (i = 0; i < tottri; i++) {
+ for (int i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
float vec[3][2];
@@ -744,9 +738,9 @@ void RE_bake_pixels_populate(Mesh *me,
}
bd.bk_image = &bake_images->data[image_id];
- bd.primitive_id = ++p_id;
+ bd.primitive_id = i;
- for (a = 0; a < 3; a++) {
+ for (int a = 0; a < 3; a++) {
const float *uv = mloopuv[lt->tri[a]].uv;
/* Note, workaround for pixel aligned UVs which are common and can screw up our
@@ -761,7 +755,7 @@ void RE_bake_pixels_populate(Mesh *me,
zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);
}
- for (i = 0; i < bake_images->size; i++) {
+ for (int i = 0; i < bake_images->size; i++) {
zbuf_free_span(&bd.zspan[i]);
}
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 7c301f7d591..b30821a1b73 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -1319,8 +1319,11 @@ static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
}
}
-static void bake_ibuf_normalize_displacement(
- ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max)
+static void bake_ibuf_normalize_displacement(ImBuf *ibuf,
+ const float *displacement,
+ const char *mask,
+ float displacement_min,
+ float displacement_max)
{
int i;
const float *current_displacement = displacement;
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 9926e08c968..b37eeed3681 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -902,7 +902,7 @@ static void do_2d_mapping(
float fx, fy, fac1, area[8];
int ok, proj, areaflag = 0, wrap;
- /* mtex variables localized, only cubemap doesn't cooperate yet... */
+ /* #MTex variables localized, only cube-map doesn't cooperate yet. */
wrap = mtex->mapping;
tex = mtex->tex;
diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt
index 740f7c126d1..a12f36f9713 100644
--- a/source/blender/shader_fx/CMakeLists.txt
+++ b/source/blender/shader_fx/CMakeLists.txt
@@ -24,8 +24,8 @@ set(INC
intern
../blenfont
../blenkernel
- ../blentranslation
../blenlib
+ ../blentranslation
../bmesh
../depsgraph
../editors/include
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 482589e2ccb..3d4c84805f9 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -744,8 +744,13 @@ void *WM_jobs_customdata_get(struct wmJob *);
void WM_jobs_customdata_set(struct wmJob *, void *customdata, void (*free)(void *));
void WM_jobs_timer(struct wmJob *, double timestep, unsigned int note, unsigned int endnote);
void WM_jobs_delay_start(struct wmJob *, double delay_time);
+
+typedef void (*wm_jobs_start_callback)(void *custom_data,
+ short *stop,
+ short *do_update,
+ float *progress);
void WM_jobs_callbacks(struct wmJob *,
- void (*startjob)(void *, short *, short *, float *),
+ wm_jobs_start_callback startjob,
void (*initjob)(void *),
void (*update)(void *),
void (*endjob)(void *));
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 4acce793707..b4b3d0957af 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -361,6 +361,7 @@ typedef struct wmNotifier {
#define ND_LOD (30 << 16)
#define ND_DRAW_RENDER_VIEWPORT \
(31 << 16) /* for camera & sequencer viewport update, also /w NC_SCENE */
+#define ND_SHADERFX (32 << 16)
/* NC_MATERIAL Material */
#define ND_SHADING (30 << 16)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 53d6df915d6..05ef4bfac30 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -591,7 +591,7 @@ static int wm_handler_ui_call(bContext *C,
return WM_HANDLER_CONTINUE;
}
- /* UI is quite aggressive with swallowing events, like scrollwheel */
+ /* UI is quite aggressive with swallowing events, like scroll-wheel. */
/* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */
if (do_wheel_ui == false) {
if (is_wheel) {
@@ -608,7 +608,7 @@ static int wm_handler_ui_call(bContext *C,
return WM_UI_HANDLER_CONTINUE;
}
- /* we set context to where ui handler came from */
+ /* We set context to where UI handler came from. */
if (handler->context.area) {
CTX_wm_area_set(C, handler->context.area);
}
@@ -810,7 +810,7 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot)
return true;
}
- /* Assume a ui callback will draw something. */
+ /* Assume a UI callback will draw something. */
if (ot->ui) {
return false;
}
@@ -2707,7 +2707,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
handler_base = handler_base_next) {
handler_base_next = handler_base->next;
- /* during this loop, ui handlers for nested menus can tag multiple handlers free */
+ /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* pass */
}
@@ -2829,7 +2829,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
/* XXX code this for all modal ops, and ensure free only happens here */
- /* modal ui handler can be tagged to be freed */
+ /* Modal UI handler can be tagged to be freed. */
if (BLI_findindex(handlers, handler_base) !=
-1) { /* could be freed already by regular modal ops */
if (handler_base->flag & WM_HANDLER_DO_FREE) {
@@ -4834,7 +4834,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C,
const wmEvent *event)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
- /* during this loop, ui handlers for nested menus can tag multiple handlers free */
+ /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* pass */
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index d5a240a358e..f431a6f431b 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1027,13 +1027,6 @@ void wm_homefile_read(bContext *C,
},
NULL);
}
- if (BLI_listbase_is_empty(&U.themes)) {
- if (G.debug & G_DEBUG) {
- printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n",
- filepath_startup);
- }
- success = false;
- }
if (success) {
if (update_defaults) {
if (use_data) {
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index c10f03f3dab..87a19d832c9 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -86,7 +86,7 @@ struct wmJob {
* This performs the actual parallel work.
* Executed in worker thread(s).
*/
- void (*startjob)(void *, short *stop, short *do_update, float *progress);
+ wm_jobs_start_callback startjob;
/**
* Called if thread defines so (see `do_update` flag), and max once per timer step.
* Executed in main thread.
@@ -378,7 +378,7 @@ void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
}
void WM_jobs_callbacks(wmJob *wm_job,
- void (*startjob)(void *, short *, short *, float *),
+ wm_jobs_start_callback startjob,
void (*initjob)(void *),
void (*update)(void *),
void (*endjob)(void *))
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index a2389b02d8f..20a75ebe3b9 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -51,7 +51,6 @@
# include "BKE_global.h"
# include "BKE_image.h"
# include "BKE_lib_id.h"
-# include "BKE_lib_override.h"
# include "BKE_main.h"
# include "BKE_report.h"
# include "BKE_scene.h"
@@ -619,7 +618,6 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf("Misc Options:\n");
BLI_argsPrintArgDoc(ba, "--app-template");
BLI_argsPrintArgDoc(ba, "--factory-startup");
- BLI_argsPrintArgDoc(ba, "--disable-library-override");
BLI_argsPrintArgDoc(ba, "--enable-event-simulate");
printf("\n");
BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
@@ -683,7 +681,6 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
# ifdef WITH_SDL
printf(" $SDL_AUDIODRIVER LibSDL audio driver - alsa, esd, dma.\n");
# endif
- printf(" $PYTHONHOME Path to the Python directory, eg. /usr/lib/python.\n\n");
exit(0);
@@ -1122,17 +1119,6 @@ static int arg_handle_factory_startup_set(int UNUSED(argc),
return 0;
}
-static const char arg_handle_disable_override_library_doc[] =
- "\n\t"
- "Disable Library Override features in the UI.";
-static int arg_handle_disable_override_library(int UNUSED(argc),
- const char **UNUSED(argv),
- void *UNUSED(data))
-{
- BKE_lib_override_library_enable(false);
- return 0;
-}
-
static const char arg_handle_enable_event_simulate_doc[] =
"\n\t"
"Enable event simulation testing feature 'bpy.types.Window.event_simulate'.";
@@ -1460,7 +1446,7 @@ static int arg_handle_image_type_set(int argc, const char **argv, void *data)
return 1;
}
else {
- printf("\nError: you must specify a format after '-F / --render-foramt'.\n");
+ printf("\nError: you must specify a format after '-F / --render-format'.\n");
return 0;
}
}
@@ -2226,8 +2212,6 @@ void main_args_setup(bContext *C, bArgs *ba)
BLI_argsAdd(ba, 1, NULL, "--app-template", CB(arg_handle_app_template), NULL);
BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
- BLI_argsAdd(
- ba, 1, NULL, "--disable-library-override", CB(arg_handle_disable_override_library), NULL);
BLI_argsAdd(ba, 1, NULL, "--enable-event-simulate", CB(arg_handle_enable_event_simulate), NULL);
/* TODO, add user env vars? */
diff --git a/tests/gtests/blenlib/BLI_array_test.cc b/tests/gtests/blenlib/BLI_array_test.cc
index 9c77c69e296..3ff5baf1d94 100644
--- a/tests/gtests/blenlib/BLI_array_test.cc
+++ b/tests/gtests/blenlib/BLI_array_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_array.hh"
#include "BLI_strict_flags.h"
#include "testing/testing.h"
@@ -138,23 +140,22 @@ TEST(array, NoInitializationSizeConstructor)
{
using MyArray = Array<ConstructibleType>;
- AlignedBuffer<sizeof(MyArray), alignof(MyArray)> buffer;
- char *buffer_ptr = (char *)buffer.ptr();
- memset(buffer_ptr, 100, sizeof(MyArray));
+ TypedBuffer<MyArray> buffer;
+ memset(buffer, 100, sizeof(MyArray));
/* Doing this to avoid some compiler optimization. */
for (uint i : IndexRange(sizeof(MyArray))) {
- EXPECT_EQ(buffer_ptr[i], 100);
+ EXPECT_EQ(((char *)buffer.ptr())[i], 100);
}
{
- MyArray &array = *new (buffer.ptr()) MyArray(1, NoInitialization());
+ MyArray &array = *new (buffer) MyArray(1, NoInitialization());
EXPECT_EQ(array[0].value, 100);
array.clear_without_destruct();
array.~Array();
}
{
- MyArray &array = *new (buffer.ptr()) MyArray(1);
+ MyArray &array = *new (buffer) MyArray(1);
EXPECT_EQ(array[0].value, 42);
array.~Array();
}
diff --git a/tests/gtests/blenlib/BLI_disjoint_set_test.cc b/tests/gtests/blenlib/BLI_disjoint_set_test.cc
new file mode 100644
index 00000000000..30503954c62
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_disjoint_set_test.cc
@@ -0,0 +1,36 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_disjoint_set.hh"
+#include "BLI_strict_flags.h"
+
+#include "testing/testing.h"
+
+namespace blender {
+
+TEST(disjoint_set, Test)
+{
+ DisjointSet disjoint_set(6);
+ EXPECT_FALSE(disjoint_set.in_same_set(1, 2));
+ EXPECT_FALSE(disjoint_set.in_same_set(5, 3));
+ EXPECT_TRUE(disjoint_set.in_same_set(2, 2));
+ EXPECT_EQ(disjoint_set.find_root(3), 3u);
+
+ disjoint_set.join(1, 2);
+
+ EXPECT_TRUE(disjoint_set.in_same_set(1, 2));
+ EXPECT_FALSE(disjoint_set.in_same_set(0, 1));
+
+ disjoint_set.join(3, 4);
+
+ EXPECT_FALSE(disjoint_set.in_same_set(2, 3));
+ EXPECT_TRUE(disjoint_set.in_same_set(3, 4));
+
+ disjoint_set.join(1, 4);
+
+ EXPECT_TRUE(disjoint_set.in_same_set(1, 4));
+ EXPECT_TRUE(disjoint_set.in_same_set(1, 3));
+ EXPECT_TRUE(disjoint_set.in_same_set(2, 4));
+ EXPECT_FALSE(disjoint_set.in_same_set(0, 4));
+}
+
+} // namespace blender
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
index 1002ff7d2df..201598869e8 100644
--- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
@@ -535,42 +535,6 @@ static void int2_ghash_tests(GHash *ghash, const char *id, const unsigned int nb
printf("========== ENDED %s ==========\n\n", id);
}
-TEST(ghash, Int2GHash2000)
-{
- GHash *ghash = BLI_ghash_new(
- BLI_ghashutil_uinthash_v2_p, BLI_ghashutil_uinthash_v2_cmp, __func__);
-
- int2_ghash_tests(ghash, "Int2GHash - GHash - 2000", 2000);
-}
-
-#ifdef GHASH_RUN_BIG
-TEST(ghash, Int2GHash20000000)
-{
- GHash *ghash = BLI_ghash_new(
- BLI_ghashutil_uinthash_v2_p, BLI_ghashutil_uinthash_v2_cmp, __func__);
-
- int2_ghash_tests(ghash, "Int2GHash - GHash - 20000000", 20000000);
-}
-#endif
-
-TEST(ghash, Int2Murmur2a2000)
-{
- GHash *ghash = BLI_ghash_new(
- BLI_ghashutil_uinthash_v2_p_murmur, BLI_ghashutil_uinthash_v2_cmp, __func__);
-
- int2_ghash_tests(ghash, "Int2GHash - Murmur - 2000", 2000);
-}
-
-#ifdef GHASH_RUN_BIG
-TEST(ghash, Int2Murmur2a20000000)
-{
- GHash *ghash = BLI_ghash_new(
- BLI_ghashutil_uinthash_v2_p_murmur, BLI_ghashutil_uinthash_v2_cmp, __func__);
-
- int2_ghash_tests(ghash, "Int2GHash - Murmur - 20000000", 20000000);
-}
-#endif
-
/* MultiSmall: create and manipulate a lot of very small ghashes
* (90% < 10 items, 9% < 100 items, 1% < 1000 items). */
diff --git a/tests/gtests/blenlib/BLI_index_mask_test.cc b/tests/gtests/blenlib/BLI_index_mask_test.cc
index 50b32be6364..6d9b7c70ab2 100644
--- a/tests/gtests/blenlib/BLI_index_mask_test.cc
+++ b/tests/gtests/blenlib/BLI_index_mask_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_index_mask.hh"
#include "testing/testing.h"
diff --git a/tests/gtests/blenlib/BLI_index_range_test.cc b/tests/gtests/blenlib/BLI_index_range_test.cc
index e484da5ef42..0f4fb7ef03b 100644
--- a/tests/gtests/blenlib/BLI_index_range_test.cc
+++ b/tests/gtests/blenlib/BLI_index_range_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_index_range.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
diff --git a/tests/gtests/blenlib/BLI_linear_allocator_test.cc b/tests/gtests/blenlib/BLI_linear_allocator_test.cc
index bbea4c1239f..7ef9d433a4d 100644
--- a/tests/gtests/blenlib/BLI_linear_allocator_test.cc
+++ b/tests/gtests/blenlib/BLI_linear_allocator_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_linear_allocator.hh"
#include "BLI_strict_flags.h"
#include "testing/testing.h"
diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc
index 3b72795d36f..4fb97c40e86 100644
--- a/tests/gtests/blenlib/BLI_map_test.cc
+++ b/tests/gtests/blenlib/BLI_map_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_map.hh"
#include "BLI_rand.h"
#include "BLI_set.hh"
diff --git a/tests/gtests/blenlib/BLI_math_bits_test.cc b/tests/gtests/blenlib/BLI_math_bits_test.cc
index 9baa471cf48..4fa4809beed 100644
--- a/tests/gtests/blenlib/BLI_math_bits_test.cc
+++ b/tests/gtests/blenlib/BLI_math_bits_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_math_bits.h"
#include "testing/testing.h"
#include <iostream>
diff --git a/tests/gtests/blenlib/BLI_memory_utils_test.cc b/tests/gtests/blenlib/BLI_memory_utils_test.cc
new file mode 100644
index 00000000000..b99db5c5eca
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_memory_utils_test.cc
@@ -0,0 +1,159 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_float3.hh"
+#include "BLI_memory_utils.hh"
+#include "BLI_strict_flags.h"
+#include "testing/testing.h"
+
+namespace blender {
+
+struct MyValue {
+ static inline int alive = 0;
+
+ MyValue()
+ {
+ if (alive == 15) {
+ throw std::exception();
+ }
+
+ alive++;
+ }
+
+ MyValue(const MyValue &other)
+ {
+ if (alive == 15) {
+ throw std::exception();
+ }
+
+ alive++;
+ }
+
+ ~MyValue()
+ {
+ alive--;
+ }
+};
+
+TEST(memory_utils, DefaultConstructN_ActuallyCallsConstructor)
+{
+ constexpr int amount = 10;
+ TypedBuffer<MyValue, amount> buffer;
+
+ EXPECT_EQ(MyValue::alive, 0);
+ default_construct_n(buffer.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, amount);
+ destruct_n(buffer.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, 0);
+}
+
+TEST(memory_utils, DefaultConstructN_StrongExceptionSafety)
+{
+ constexpr int amount = 20;
+ TypedBuffer<MyValue, amount> buffer;
+
+ EXPECT_EQ(MyValue::alive, 0);
+ EXPECT_THROW(default_construct_n(buffer.ptr(), amount), std::exception);
+ EXPECT_EQ(MyValue::alive, 0);
+}
+
+TEST(memory_utils, UninitializedCopyN_ActuallyCopies)
+{
+ constexpr int amount = 5;
+ TypedBuffer<MyValue, amount> buffer1;
+ TypedBuffer<MyValue, amount> buffer2;
+
+ EXPECT_EQ(MyValue::alive, 0);
+ default_construct_n(buffer1.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, amount);
+ uninitialized_copy_n(buffer1.ptr(), amount, buffer2.ptr());
+ EXPECT_EQ(MyValue::alive, 2 * amount);
+ destruct_n(buffer1.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, amount);
+ destruct_n(buffer2.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, 0);
+}
+
+TEST(memory_utils, UninitializedCopyN_StrongExceptionSafety)
+{
+ constexpr int amount = 10;
+ TypedBuffer<MyValue, amount> buffer1;
+ TypedBuffer<MyValue, amount> buffer2;
+
+ EXPECT_EQ(MyValue::alive, 0);
+ default_construct_n(buffer1.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, amount);
+ EXPECT_THROW(uninitialized_copy_n(buffer1.ptr(), amount, buffer2.ptr()), std::exception);
+ EXPECT_EQ(MyValue::alive, amount);
+ destruct_n(buffer1.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, 0);
+}
+
+TEST(memory_utils, UninitializedFillN_ActuallyCopies)
+{
+ constexpr int amount = 10;
+ TypedBuffer<MyValue, amount> buffer;
+
+ EXPECT_EQ(MyValue::alive, 0);
+ {
+ MyValue value;
+ EXPECT_EQ(MyValue::alive, 1);
+ uninitialized_fill_n(buffer.ptr(), amount, value);
+ EXPECT_EQ(MyValue::alive, 1 + amount);
+ destruct_n(buffer.ptr(), amount);
+ EXPECT_EQ(MyValue::alive, 1);
+ }
+ EXPECT_EQ(MyValue::alive, 0);
+}
+
+TEST(memory_utils, UninitializedFillN_StrongExceptionSafety)
+{
+ constexpr int amount = 20;
+ TypedBuffer<MyValue, amount> buffer;
+
+ EXPECT_EQ(MyValue::alive, 0);
+ {
+ MyValue value;
+ EXPECT_EQ(MyValue::alive, 1);
+ EXPECT_THROW(uninitialized_fill_n(buffer.ptr(), amount, value), std::exception);
+ EXPECT_EQ(MyValue::alive, 1);
+ }
+ EXPECT_EQ(MyValue::alive, 0);
+}
+
+class TestBaseClass {
+ virtual void mymethod(){};
+};
+
+class TestChildClass : public TestBaseClass {
+ void mymethod() override
+ {
+ }
+};
+
+static_assert(is_convertible_pointer_v<int *, int *>);
+static_assert(is_convertible_pointer_v<int *, const int *>);
+static_assert(is_convertible_pointer_v<int *, int *const>);
+static_assert(is_convertible_pointer_v<int *, const int *const>);
+static_assert(!is_convertible_pointer_v<const int *, int *>);
+static_assert(!is_convertible_pointer_v<int, int *>);
+static_assert(!is_convertible_pointer_v<int *, int>);
+static_assert(is_convertible_pointer_v<TestBaseClass *, const TestBaseClass *>);
+static_assert(!is_convertible_pointer_v<const TestBaseClass *, TestBaseClass *>);
+static_assert(is_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
+static_assert(!is_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
+static_assert(is_convertible_pointer_v<const TestChildClass *, const TestBaseClass *>);
+static_assert(!is_convertible_pointer_v<TestBaseClass, const TestChildClass *>);
+static_assert(!is_convertible_pointer_v<float3, float *>);
+static_assert(!is_convertible_pointer_v<float *, float3>);
+static_assert(!is_convertible_pointer_v<int **, int *>);
+static_assert(!is_convertible_pointer_v<int *, int **>);
+static_assert(is_convertible_pointer_v<int **, int **>);
+static_assert(is_convertible_pointer_v<const int **, const int **>);
+static_assert(!is_convertible_pointer_v<const int **, int **>);
+static_assert(!is_convertible_pointer_v<int *const *, int **>);
+static_assert(!is_convertible_pointer_v<int *const *const, int **>);
+static_assert(is_convertible_pointer_v<int **, int **const>);
+static_assert(is_convertible_pointer_v<int **, int *const *>);
+static_assert(is_convertible_pointer_v<int **, int const *const *>);
+
+} // namespace blender
diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc
index ac78eb786df..189f0c1b134 100644
--- a/tests/gtests/blenlib/BLI_set_test.cc
+++ b/tests/gtests/blenlib/BLI_set_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include <set>
#include <unordered_set>
@@ -403,6 +405,51 @@ TEST(set, IntrusiveIntKey)
EXPECT_TRUE(set.remove(4));
}
+struct MyKeyType {
+ uint32_t key;
+ int32_t attached_data;
+
+ uint32_t hash() const
+ {
+ return key;
+ }
+
+ friend bool operator==(const MyKeyType &a, const MyKeyType &b)
+ {
+ return a.key == b.key;
+ }
+};
+
+TEST(set, LookupKey)
+{
+ Set<MyKeyType> set;
+ set.add({1, 10});
+ set.add({2, 20});
+ EXPECT_EQ(set.lookup_key({1, 30}).attached_data, 10);
+ EXPECT_EQ(set.lookup_key({2, 0}).attached_data, 20);
+}
+
+TEST(set, LookupKeyDefault)
+{
+ Set<MyKeyType> set;
+ set.add({1, 10});
+ set.add({2, 20});
+
+ MyKeyType fallback{5, 50};
+ EXPECT_EQ(set.lookup_key_default({1, 66}, fallback).attached_data, 10);
+ EXPECT_EQ(set.lookup_key_default({4, 40}, fallback).attached_data, 50);
+}
+
+TEST(set, LookupKeyPtr)
+{
+ Set<MyKeyType> set;
+ set.add({1, 10});
+ set.add({2, 20});
+ EXPECT_EQ(set.lookup_key_ptr({1, 50})->attached_data, 10);
+ EXPECT_EQ(set.lookup_key_ptr({2, 50})->attached_data, 20);
+ EXPECT_EQ(set.lookup_key_ptr({3, 50}), nullptr);
+}
+
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/
diff --git a/tests/gtests/blenlib/BLI_span_test.cc b/tests/gtests/blenlib/BLI_span_test.cc
index 375cb694b7b..ccc63fd80eb 100644
--- a/tests/gtests/blenlib/BLI_span_test.cc
+++ b/tests/gtests/blenlib/BLI_span_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_span.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
@@ -283,4 +285,14 @@ TEST(span, CastLargerSize)
EXPECT_EQ(new_a_span.size(), 2u);
}
+TEST(span, VoidPointerSpan)
+{
+ int a;
+ float b;
+ double c;
+
+ auto func1 = [](Span<void *> span) { EXPECT_EQ(span.size(), 3u); };
+ func1({&a, &b, &c});
+}
+
} // namespace blender
diff --git a/tests/gtests/blenlib/BLI_stack_cxx_test.cc b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
index b59ac1f7ec1..c8433b4fd87 100644
--- a/tests/gtests/blenlib/BLI_stack_cxx_test.cc
+++ b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_stack.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
diff --git a/tests/gtests/blenlib/BLI_string_ref_test.cc b/tests/gtests/blenlib/BLI_string_ref_test.cc
index 1f84b8577b4..0d1880229c7 100644
--- a/tests/gtests/blenlib/BLI_string_ref_test.cc
+++ b/tests/gtests/blenlib/BLI_string_ref_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_strict_flags.h"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
diff --git a/tests/gtests/blenlib/BLI_vector_set_test.cc b/tests/gtests/blenlib/BLI_vector_set_test.cc
index 982081f4b4c..3c3b4d55959 100644
--- a/tests/gtests/blenlib/BLI_vector_set_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_set_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_strict_flags.h"
#include "BLI_vector_set.hh"
#include "testing/testing.h"
diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc
index ea4711ca015..25435739a43 100644
--- a/tests/gtests/blenlib/BLI_vector_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_test.cc
@@ -1,3 +1,5 @@
+/* Apache License, Version 2.0 */
+
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
#include "testing/testing.h"
@@ -57,6 +59,18 @@ TEST(vector, InitializerListConstructor)
EXPECT_EQ(vec[3], 6);
}
+TEST(vector, ConvertingConstructor)
+{
+ std::array<float, 5> values = {5.4f, 7.3f, -8.1f, 5.0f, 0.0f};
+ Vector<int> vec = values;
+ EXPECT_EQ(vec.size(), 5u);
+ EXPECT_EQ(vec[0], 5);
+ EXPECT_EQ(vec[1], 7);
+ EXPECT_EQ(vec[2], -8);
+ EXPECT_EQ(vec[3], 5);
+ EXPECT_EQ(vec[4], 0);
+}
+
struct TestListValue {
TestListValue *next, *prev;
int value;
@@ -499,7 +513,7 @@ class TypeConstructMock {
{
}
- TypeConstructMock(TypeConstructMock &&other) : move_constructed(true)
+ TypeConstructMock(TypeConstructMock &&other) noexcept : move_constructed(true)
{
}
@@ -513,7 +527,7 @@ class TypeConstructMock {
return *this;
}
- TypeConstructMock &operator=(TypeConstructMock &&other)
+ TypeConstructMock &operator=(TypeConstructMock &&other) noexcept
{
if (this == &other) {
return *this;
@@ -637,4 +651,13 @@ TEST(vector, OveralignedValues)
}
}
+TEST(vector, ConstructVoidPointerVector)
+{
+ int a;
+ float b;
+ double c;
+ Vector<void *> vec = {&a, &b, &c};
+ EXPECT_EQ(vec.size(), 3u);
+}
+
} // namespace blender
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index ba493b22b42..496fe44234e 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -43,6 +43,7 @@ BLENDER_TEST(BLI_array "bf_blenlib")
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_delaunay_2d "bf_blenlib")
+BLENDER_TEST(BLI_disjoint_set "bf_blenlib")
BLENDER_TEST(BLI_edgehash "bf_blenlib")
BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
@@ -63,6 +64,7 @@ BLENDER_TEST(BLI_math_geom "bf_blenlib")
BLENDER_TEST(BLI_math_matrix "bf_blenlib")
BLENDER_TEST(BLI_math_vector "bf_blenlib")
BLENDER_TEST(BLI_memiter "bf_blenlib")
+BLENDER_TEST(BLI_memory_utils "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
BLENDER_TEST(BLI_set "bf_blenlib")
diff --git a/tests/gtests/functions/FN_array_spans_test.cc b/tests/gtests/functions/FN_array_spans_test.cc
index fa483ebf0f8..988d48fa452 100644
--- a/tests/gtests/functions/FN_array_spans_test.cc
+++ b/tests/gtests/functions/FN_array_spans_test.cc
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "testing/testing.h"
diff --git a/tests/gtests/functions/FN_attributes_ref_test.cc b/tests/gtests/functions/FN_attributes_ref_test.cc
index eda4592d214..1c05bb930db 100644
--- a/tests/gtests/functions/FN_attributes_ref_test.cc
+++ b/tests/gtests/functions/FN_attributes_ref_test.cc
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "BLI_float3.hh"
#include "FN_attributes_ref.hh"
diff --git a/tests/gtests/functions/FN_cpp_type_test.cc b/tests/gtests/functions/FN_cpp_type_test.cc
index f6ae0877ed1..da5ce3416ce 100644
--- a/tests/gtests/functions/FN_cpp_type_test.cc
+++ b/tests/gtests/functions/FN_cpp_type_test.cc
@@ -1,22 +1,9 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "FN_cpp_type.hh"
+#include "FN_cpp_types.hh"
namespace blender::fn {
@@ -50,7 +37,7 @@ struct TestType {
other.value = copy_constructed_from_value;
}
- TestType(TestType &&other)
+ TestType(TestType &&other) noexcept
{
value = move_constructed_value;
other.value = move_constructed_from_value;
@@ -63,12 +50,28 @@ struct TestType {
return *this;
}
- TestType &operator=(TestType &&other)
+ TestType &operator=(TestType &&other) noexcept
{
value = move_assigned_value;
other.value = move_assigned_from_value;
return *this;
}
+
+ friend std::ostream &operator<<(std::ostream &stream, const TestType &value)
+ {
+ stream << value.value;
+ return stream;
+ }
+
+ friend bool operator==(const TestType &a, const TestType &b)
+ {
+ return false;
+ }
+
+ uint32_t hash() const
+ {
+ return 0;
+ }
};
MAKE_CPP_TYPE(TestType, TestType)
@@ -305,4 +308,13 @@ TEST(cpp_type, FillUninitialized)
EXPECT_EQ(buffer2[9], 0);
}
+TEST(cpp_type, DebugPrint)
+{
+ int value = 42;
+ std::stringstream ss;
+ CPPType_int32.debug_print((void *)&value, ss);
+ std::string text = ss.str();
+ EXPECT_EQ(text, "42");
+}
+
} // namespace blender::fn
diff --git a/tests/gtests/functions/FN_generic_vector_array_test.cc b/tests/gtests/functions/FN_generic_vector_array_test.cc
index 3308913a72e..7ce7b543218 100644
--- a/tests/gtests/functions/FN_generic_vector_array_test.cc
+++ b/tests/gtests/functions/FN_generic_vector_array_test.cc
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "FN_cpp_types.hh"
#include "FN_generic_vector_array.hh"
diff --git a/tests/gtests/functions/FN_multi_function_network_test.cc b/tests/gtests/functions/FN_multi_function_network_test.cc
index 07068aecdb6..5507733c8be 100644
--- a/tests/gtests/functions/FN_multi_function_network_test.cc
+++ b/tests/gtests/functions/FN_multi_function_network_test.cc
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "testing/testing.h"
diff --git a/tests/gtests/functions/FN_multi_function_test.cc b/tests/gtests/functions/FN_multi_function_test.cc
index 07dffeeb948..8cc8f91a300 100644
--- a/tests/gtests/functions/FN_multi_function_test.cc
+++ b/tests/gtests/functions/FN_multi_function_test.cc
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "testing/testing.h"
@@ -329,4 +315,72 @@ TEST(multi_function, CustomMF_Constant)
EXPECT_EQ(outputs[3], 42);
}
+TEST(multi_function, CustomMF_GenericConstant)
+{
+ int value = 42;
+ CustomMF_GenericConstant fn{CPPType_int32, (const void *)&value};
+ EXPECT_EQ(fn.param_name(0), "42");
+
+ Array<int> outputs(4, 0);
+
+ MFParamsBuilder params(fn, outputs.size());
+ params.add_uninitialized_single_output(outputs.as_mutable_span());
+
+ MFContextBuilder context;
+
+ fn.call({0, 1, 2}, params, context);
+
+ EXPECT_EQ(outputs[0], 42);
+ EXPECT_EQ(outputs[1], 42);
+ EXPECT_EQ(outputs[2], 42);
+ EXPECT_EQ(outputs[3], 0);
+}
+
+TEST(multi_function, CustomMF_GenericConstantArray)
+{
+ std::array<int, 4> values = {3, 4, 5, 6};
+ CustomMF_GenericConstantArray fn{GSpan(Span(values))};
+ EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]");
+
+ GVectorArray g_vector_array{CPPType_int32, 4};
+ GVectorArrayRef<int> vector_array = g_vector_array;
+
+ MFParamsBuilder params(fn, g_vector_array.size());
+ params.add_vector_output(g_vector_array);
+
+ MFContextBuilder context;
+
+ fn.call({1, 2, 3}, params, context);
+
+ EXPECT_EQ(vector_array[0].size(), 0);
+ EXPECT_EQ(vector_array[1].size(), 4);
+ EXPECT_EQ(vector_array[2].size(), 4);
+ EXPECT_EQ(vector_array[3].size(), 4);
+ for (uint i = 1; i < 4; i++) {
+ EXPECT_EQ(vector_array[i][0], 3);
+ EXPECT_EQ(vector_array[i][1], 4);
+ EXPECT_EQ(vector_array[i][2], 5);
+ EXPECT_EQ(vector_array[i][3], 6);
+ }
+}
+
+TEST(multi_function, CustomMF_Convert)
+{
+ CustomMF_Convert<float, int> fn;
+
+ Array<float> inputs = {5.4f, 7.1f, 9.0f};
+ Array<int> outputs(inputs.size(), 0);
+
+ MFParamsBuilder params(fn, inputs.size());
+ params.add_readonly_single_input(inputs.as_span());
+ params.add_uninitialized_single_output(outputs.as_mutable_span());
+
+ MFContextBuilder context;
+ fn.call({0, 2}, params, context);
+
+ EXPECT_EQ(outputs[0], 5);
+ EXPECT_EQ(outputs[1], 0);
+ EXPECT_EQ(outputs[2], 9);
+}
+
} // namespace blender::fn
diff --git a/tests/gtests/functions/FN_spans_test.cc b/tests/gtests/functions/FN_spans_test.cc
index 43deb80ed23..8968d49c082 100644
--- a/tests/gtests/functions/FN_spans_test.cc
+++ b/tests/gtests/functions/FN_spans_test.cc
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+/* Apache License, Version 2.0 */
#include "testing/testing.h"
diff --git a/tests/gtests/usd/CMakeLists.txt b/tests/gtests/usd/CMakeLists.txt
index d2bfe5e1306..0caa2fac155 100644
--- a/tests/gtests/usd/CMakeLists.txt
+++ b/tests/gtests/usd/CMakeLists.txt
@@ -67,6 +67,7 @@ get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP)
set(SRC
abstract_hierarchy_iterator_test.cc
hierarchy_context_order_test.cc
+ object_identifier_test.cc
)
# TODO(Sybren): re-enable this unit test.
diff --git a/tests/gtests/usd/object_identifier_test.cc b/tests/gtests/usd/object_identifier_test.cc
new file mode 100644
index 00000000000..810d4470260
--- /dev/null
+++ b/tests/gtests/usd/object_identifier_test.cc
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+#include "IO_abstract_hierarchy_iterator.h"
+
+#include "testing/testing.h"
+
+#include "BLI_utildefines.h"
+
+#include <climits>
+
+namespace blender {
+namespace io {
+
+namespace {
+
+/* Return object pointer for use in tests. This makes it possible to reliably test for
+ * order/equality functions while using hard-coded values for simplicity. */
+Object *fake_pointer(int value)
+{
+ return static_cast<Object *>(POINTER_FROM_INT(value));
+}
+
+/* PersistentID subclass for use in tests, making it easier to construct test values. */
+class TestPersistentID : public PersistentID {
+ public:
+ TestPersistentID(int value0,
+ int value1,
+ int value2,
+ int value3,
+ int value4,
+ int value5,
+ int value6,
+ int value7)
+ {
+ persistent_id_[0] = value0;
+ persistent_id_[1] = value1;
+ persistent_id_[2] = value2;
+ persistent_id_[3] = value3;
+ persistent_id_[4] = value4;
+ persistent_id_[5] = value5;
+ persistent_id_[6] = value6;
+ persistent_id_[7] = value7;
+ }
+ TestPersistentID(int value0, int value1, int value2)
+ : TestPersistentID(value0, value1, value2, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX)
+ {
+ }
+ TestPersistentID(int value0, int value1) : TestPersistentID(value0, value1, INT_MAX)
+ {
+ }
+ explicit TestPersistentID(int value0) : TestPersistentID(value0, INT_MAX)
+ {
+ }
+};
+
+/* ObjectIdentifier subclass for use in tests, making it easier to construct test values. */
+class TestObjectIdentifier : public ObjectIdentifier {
+ public:
+ TestObjectIdentifier(Object *object, Object *duplicated_by, const PersistentID &persistent_id)
+ : ObjectIdentifier(object, duplicated_by, persistent_id)
+ {
+ }
+};
+
+} // namespace
+
+class ObjectIdentifierOrderTest : public testing::Test {
+};
+
+TEST_F(ObjectIdentifierOrderTest, graph_root)
+{
+ ObjectIdentifier id_root_1 = ObjectIdentifier::for_graph_root();
+ ObjectIdentifier id_root_2 = ObjectIdentifier::for_graph_root();
+ EXPECT_TRUE(id_root_1 == id_root_2);
+ EXPECT_FALSE(id_root_1 < id_root_2);
+ EXPECT_FALSE(id_root_2 < id_root_1);
+
+ ObjectIdentifier id_a = ObjectIdentifier::for_real_object(fake_pointer(1));
+ EXPECT_FALSE(id_root_1 == id_a);
+ EXPECT_TRUE(id_root_1 < id_a);
+ EXPECT_FALSE(id_a < id_root_1);
+
+ ObjectIdentifier id_accidental_root = ObjectIdentifier::for_real_object(nullptr);
+ EXPECT_TRUE(id_root_1 == id_accidental_root);
+ EXPECT_FALSE(id_root_1 < id_accidental_root);
+ EXPECT_FALSE(id_accidental_root < id_root_1);
+}
+
+TEST_F(ObjectIdentifierOrderTest, real_objects)
+{
+ ObjectIdentifier id_a = ObjectIdentifier::for_real_object(fake_pointer(1));
+ ObjectIdentifier id_b = ObjectIdentifier::for_real_object(fake_pointer(2));
+ EXPECT_FALSE(id_a == id_b);
+ EXPECT_TRUE(id_a < id_b);
+}
+
+TEST_F(ObjectIdentifierOrderTest, duplicated_objects)
+{
+ ObjectIdentifier id_real_a = ObjectIdentifier::for_real_object(fake_pointer(1));
+ TestObjectIdentifier id_dupli_a(fake_pointer(1), fake_pointer(2), TestPersistentID(0));
+ TestObjectIdentifier id_dupli_b(fake_pointer(1), fake_pointer(3), TestPersistentID(0));
+ TestObjectIdentifier id_different_dupli_b(fake_pointer(1), fake_pointer(3), TestPersistentID(1));
+
+ EXPECT_FALSE(id_real_a == id_dupli_a);
+ EXPECT_FALSE(id_dupli_a == id_dupli_b);
+ EXPECT_TRUE(id_real_a < id_dupli_a);
+ EXPECT_TRUE(id_real_a < id_dupli_b);
+ EXPECT_TRUE(id_dupli_a < id_dupli_b);
+ EXPECT_TRUE(id_dupli_a < id_different_dupli_b);
+
+ EXPECT_FALSE(id_dupli_b == id_different_dupli_b);
+ EXPECT_FALSE(id_dupli_a == id_different_dupli_b);
+ EXPECT_TRUE(id_dupli_b < id_different_dupli_b);
+ EXPECT_FALSE(id_different_dupli_b < id_dupli_b);
+}
+
+TEST_F(ObjectIdentifierOrderTest, behaviour_as_map_keys)
+{
+ ObjectIdentifier id_root = ObjectIdentifier::for_graph_root();
+ ObjectIdentifier id_another_root = ObjectIdentifier::for_graph_root();
+ ObjectIdentifier id_real_a = ObjectIdentifier::for_real_object(fake_pointer(1));
+ TestObjectIdentifier id_dupli_a(fake_pointer(1), fake_pointer(2), TestPersistentID(0));
+ TestObjectIdentifier id_dupli_b(fake_pointer(1), fake_pointer(3), TestPersistentID(0));
+ AbstractHierarchyIterator::ExportGraph graph;
+
+ /* This inserts the keys with default values. */
+ graph[id_root];
+ graph[id_real_a];
+ graph[id_dupli_a];
+ graph[id_dupli_b];
+ graph[id_another_root];
+
+ EXPECT_EQ(4, graph.size());
+
+ graph.erase(id_another_root);
+ EXPECT_EQ(3, graph.size());
+
+ TestObjectIdentifier id_another_dupli_b(fake_pointer(1), fake_pointer(3), TestPersistentID(0));
+ graph.erase(id_another_dupli_b);
+ EXPECT_EQ(2, graph.size());
+}
+
+TEST_F(ObjectIdentifierOrderTest, map_copy_and_update)
+{
+ ObjectIdentifier id_root = ObjectIdentifier::for_graph_root();
+ ObjectIdentifier id_real_a = ObjectIdentifier::for_real_object(fake_pointer(1));
+ TestObjectIdentifier id_dupli_a(fake_pointer(1), fake_pointer(2), TestPersistentID(0));
+ TestObjectIdentifier id_dupli_b(fake_pointer(1), fake_pointer(3), TestPersistentID(0));
+ TestObjectIdentifier id_dupli_c(fake_pointer(1), fake_pointer(3), TestPersistentID(1));
+ AbstractHierarchyIterator::ExportGraph graph;
+
+ /* This inserts the keys with default values. */
+ graph[id_root];
+ graph[id_real_a];
+ graph[id_dupli_a];
+ graph[id_dupli_b];
+ graph[id_dupli_c];
+ EXPECT_EQ(5, graph.size());
+
+ AbstractHierarchyIterator::ExportGraph graph_copy = graph;
+ EXPECT_EQ(5, graph_copy.size());
+
+ // Updating a value in a copy should not update the original.
+ HierarchyContext ctx1;
+ HierarchyContext ctx2;
+ ctx1.object = fake_pointer(1);
+ ctx2.object = fake_pointer(2);
+
+ graph_copy[id_root].insert(&ctx1);
+ EXPECT_EQ(0, graph[id_root].size());
+
+ // Deleting a key in the copy should not update the original.
+ graph_copy.erase(id_dupli_c);
+ EXPECT_EQ(4, graph_copy.size());
+ EXPECT_EQ(5, graph.size());
+}
+
+class PersistentIDTest : public testing::Test {
+};
+
+TEST_F(PersistentIDTest, is_from_same_instancer)
+{
+ PersistentID child_id_a = TestPersistentID(42, 327);
+ PersistentID child_id_b = TestPersistentID(17, 327);
+ PersistentID child_id_c = TestPersistentID(17);
+
+ EXPECT_TRUE(child_id_a.is_from_same_instancer_as(child_id_b));
+ EXPECT_FALSE(child_id_a.is_from_same_instancer_as(child_id_c));
+}
+
+TEST_F(PersistentIDTest, instancer_id)
+{
+ PersistentID child_id = TestPersistentID(42, 327);
+
+ PersistentID expect_instancer_id = TestPersistentID(327);
+ EXPECT_EQ(expect_instancer_id, child_id.instancer_pid());
+
+ PersistentID empty_id;
+ EXPECT_EQ(empty_id, child_id.instancer_pid().instancer_pid());
+
+ EXPECT_LT(child_id, expect_instancer_id);
+ EXPECT_LT(expect_instancer_id, empty_id);
+}
+
+TEST_F(PersistentIDTest, as_object_name_suffix)
+{
+ EXPECT_EQ("", PersistentID().as_object_name_suffix());
+ EXPECT_EQ("47", TestPersistentID(47).as_object_name_suffix());
+ EXPECT_EQ("327-47", TestPersistentID(47, 327).as_object_name_suffix());
+ EXPECT_EQ("42-327-47", TestPersistentID(47, 327, 42).as_object_name_suffix());
+
+ EXPECT_EQ("7-6-5-4-3-2-1-0", TestPersistentID(0, 1, 2, 3, 4, 5, 6, 7).as_object_name_suffix());
+
+ EXPECT_EQ("0-0-0", TestPersistentID(0, 0, 0).as_object_name_suffix());
+ EXPECT_EQ("0-0", TestPersistentID(0, 0).as_object_name_suffix());
+ EXPECT_EQ("-3--2--1", TestPersistentID(-1, -2, -3).as_object_name_suffix());
+}
+
+} // namespace io
+} // namespace blender
diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py
index 5f8113729c3..66545dc85c7 100644
--- a/tests/python/alembic_tests.py
+++ b/tests/python/alembic_tests.py
@@ -243,6 +243,63 @@ class DupliGroupExportTest(AbstractAlembicTest):
2.0, 3.0, 0.0, 1.0]
)
+ @with_tempdir
+ def test_multiple_duplicated_hierarchies(self, tempdir: pathlib.Path):
+ abc = tempdir / "multiple-duplicated-hierarchies.abc"
+ script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1)" % abc.as_posix()
+ self.run_blender('multiple-duplicated-hierarchies.blend', script)
+
+ # This is the expected hierarchy:
+ # ABC
+ # `--Triangle
+ # |--Triangle
+ # |--Empty-1
+ # | `--Pole-1-0
+ # | |--Pole
+ # | `--Block-1-1
+ # | `--Block
+ # |--Empty
+ # | `--Pole-0
+ # | |--Pole
+ # | `--Block-1
+ # | `--Block
+ # |--Empty-2
+ # | `--Pole-2-0
+ # | |--Pole
+ # | `--Block-2-1
+ # | `--Block
+ # `--Empty-0
+ # `--Pole-0-0
+ # |--Pole
+ # `--Block-0-1
+ # `--Block
+
+ # Now check the resulting Alembic file.
+ xform = self.abcprop(abc, '/Triangle/Empty-1/Pole-1-0/Block-1-1/.xform')
+ self.assertEqual(1, xform['.inherits'])
+ self.assertAlmostEqualFloatArray(
+ xform['.vals'],
+ [1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 2.0, 0.0, 1.0]
+ )
+
+ # If the property can be gotten, the hierarchy is okay. No need to actually check each xform.
+ self.abcprop(abc, '/Triangle/.xform')
+ self.abcprop(abc, '/Triangle/Empty-1/.xform')
+ self.abcprop(abc, '/Triangle/Empty-1/Pole-1-0/.xform')
+ self.abcprop(abc, '/Triangle/Empty-1/Pole-1-0/Block-1-1/.xform')
+ self.abcprop(abc, '/Triangle/Empty/.xform')
+ self.abcprop(abc, '/Triangle/Empty/Pole-0/.xform')
+ self.abcprop(abc, '/Triangle/Empty/Pole-0/Block-1/.xform')
+ self.abcprop(abc, '/Triangle/Empty-2/.xform')
+ self.abcprop(abc, '/Triangle/Empty-2/Pole-2-0/.xform')
+ self.abcprop(abc, '/Triangle/Empty-2/Pole-2-0/Block-2-1/.xform')
+ self.abcprop(abc, '/Triangle/Empty-0/.xform')
+ self.abcprop(abc, '/Triangle/Empty-0/Pole-0-0/.xform')
+ self.abcprop(abc, '/Triangle/Empty-0/Pole-0-0/Block-0-1/.xform')
+
class CurveExportTest(AbstractAlembicTest):
@with_tempdir