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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.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