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:
authorHans Goudey <h.goudey@me.com>2021-06-24 06:55:01 +0300
committerHans Goudey <h.goudey@me.com>2021-06-24 07:28:13 +0300
commit379f116a2ac929883d29519b41c1e63cffe6e591 (patch)
tree41d1765abca0f0e1190a1d1d703af265dfd541b0
parent2b343c74d5e80098eee60d3127ff8117fb8633be (diff)
parentf7fbb518c8194e0a416321f5856e947d5592e131 (diff)
Merge branch 'master' into temp-geometry-nodes-curve-deform-node
-rw-r--r--CMakeLists.txt2
-rw-r--r--build_files/build_environment/cmake/tbb.cmake1
-rw-r--r--build_files/cmake/Modules/FindGflags.cmake12
-rw-r--r--build_files/cmake/Modules/FindNanoVDB.cmake2
-rw-r--r--build_files/cmake/Modules/FindOpenCOLLADA.cmake2
-rw-r--r--build_files/cmake/Modules/FindPythonLibsUnix.cmake4
-rw-r--r--build_files/cmake/Modules/Findsse2neon.cmake2
-rw-r--r--build_files/cmake/clang_array_check.py4
-rw-r--r--build_files/cmake/macros.cmake12
-rw-r--r--build_files/cmake/platform/platform_apple.cmake4
-rw-r--r--build_files/cmake/platform/platform_unix.cmake4
-rw-r--r--build_files/cmake/platform/platform_win32.cmake9
-rw-r--r--build_files/windows/autodetect_msvc.cmd3
-rw-r--r--build_files/windows/check_libraries.cmd1
-rw-r--r--build_files/windows/configure_msbuild.cmd6
-rw-r--r--build_files/windows/detect_msvc2022.cmd3
-rw-r--r--build_files/windows/parse_arguments.cmd8
-rw-r--r--doc/python_api/requirements.txt13
-rw-r--r--extern/mantaflow/preprocessed/gitinfo.h2
-rw-r--r--extern/mantaflow/preprocessed/kernel.h13
-rw-r--r--extern/mantaflow/preprocessed/plugin/flip.cpp94
-rw-r--r--extern/mantaflow/preprocessed/plugin/meshplugins.cpp8
-rw-r--r--extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp7
-rw-r--r--intern/cycles/blender/blender_light.cpp9
-rw-r--r--intern/cycles/blender/blender_python.cpp12
-rw-r--r--intern/cycles/device/device_optix.cpp25
-rw-r--r--intern/cycles/render/alembic_read.cpp29
-rw-r--r--intern/cycles/test/CMakeLists.txt2
-rw-r--r--intern/cycles/util/util_color.h14
-rw-r--r--intern/cycles/util/util_system.cpp4
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h37
-rw-r--r--intern/ghost/CMakeLists.txt12
-rw-r--r--intern/ghost/GHOST_Types.h84
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp28
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.h10
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_IXrGraphicsBinding.h4
-rw-r--r--intern/ghost/intern/GHOST_System.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp410
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h23
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp255
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h90
-rw-r--r--intern/ghost/intern/GHOST_Wintab.cpp491
-rw-r--r--intern/ghost/intern/GHOST_Wintab.h250
-rw-r--r--intern/ghost/intern/GHOST_XrAction.cpp7
-rw-r--r--intern/ghost/intern/GHOST_XrContext.cpp5
-rw-r--r--intern/ghost/intern/GHOST_XrGraphicsBinding.cpp18
-rw-r--r--intern/ghost/intern/GHOST_XrSession.h9
-rw-r--r--intern/ghost/intern/GHOST_Xr_openxr_includes.h8
-rw-r--r--intern/iksolver/intern/IK_QJacobianSolver.cpp4
-rw-r--r--intern/libmv/libmv/base/scoped_ptr.h2
-rw-r--r--intern/opencolorio/CMakeLists.txt4
m---------release/datafiles/locale0
m---------release/scripts/addons0
-rw-r--r--release/scripts/modules/addon_utils.py3
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_cli.py2
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_rtl.py4
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py5
-rw-r--r--release/scripts/modules/keyingsets_utils.py2
-rw-r--r--release/scripts/modules/rna_keymap_ui.py2
-rw-r--r--release/scripts/modules/rna_manual_reference.py113
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py21
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py4
-rw-r--r--release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py2
-rw-r--r--release/scripts/startup/bl_app_templates_system/Sculpting/__init__.py2
-rw-r--r--release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py2
-rw-r--r--release/scripts/startup/bl_operators/node.py17
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py49
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py1
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py4
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py4
-rw-r--r--release/scripts/startup/bl_ui/space_image.py7
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py11
-rw-r--r--release/scripts/startup/bl_ui/space_spreadsheet.py20
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py18
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py47
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py1
-rw-r--r--release/scripts/startup/keyingsets_builtins.py8
-rw-r--r--release/scripts/startup/nodeitems_builtins.py11
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h15
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h7
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_displist.h4
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h10
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h1
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h16
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h5
-rw-r--r--source/blender/blenkernel/BKE_mesh.h74
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh42
-rw-r--r--source/blender/blenkernel/BKE_modifier.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h7
-rw-r--r--source/blender/blenkernel/BKE_object.h7
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h2
-rw-r--r--source/blender/blenkernel/BKE_spline.hh91
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc17
-rw-r--r--source/blender/blenkernel/intern/action.c29
-rw-r--r--source/blender/blenkernel/intern/armature.c141
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c8
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c9
-rw-r--r--source/blender/blenkernel/intern/blendfile.c35
-rw-r--r--source/blender/blenkernel/intern/bpath.c6
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c46
-rw-r--r--source/blender/blenkernel/intern/cachefile.c7
-rw-r--r--source/blender/blenkernel/intern/curve_deform.c10
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc174
-rw-r--r--source/blender/blenkernel/intern/customdata.c12
-rw-r--r--source/blender/blenkernel/intern/displist.cc368
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c2
-rw-r--r--source/blender/blenkernel/intern/editmesh.c64
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c2
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c2
-rw-r--r--source/blender/blenkernel/intern/fluid.c7
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc15
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc103
-rw-r--r--source/blender/blenkernel/intern/gpencil.c31
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c88
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c64
-rw-r--r--source/blender/blenkernel/intern/image.c57
-rw-r--r--source/blender/blenkernel/intern/image_gen.c21
-rw-r--r--source/blender/blenkernel/intern/layer.c6
-rw-r--r--source/blender/blenkernel/intern/lib_id.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id_test.cc6
-rw-r--r--source/blender/blenkernel/intern/lib_override.c97
-rw-r--r--source/blender/blenkernel/intern/mesh.c71
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c18
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c666
-rw-r--r--source/blender/blenkernel/intern/mesh_fair.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c14
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c9
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c22
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c12
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc116
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c760
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c66
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc12
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.c27
-rw-r--r--source/blender/blenkernel/intern/modifier.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc9
-rw-r--r--source/blender/blenkernel/intern/object.c12
-rw-r--r--source/blender/blenkernel/intern/object_update.c47
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c9
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c10
-rw-r--r--source/blender/blenkernel/intern/particle_system.c24
-rw-r--r--source/blender/blenkernel/intern/pbvh.c2
-rw-r--r--source/blender/blenkernel/intern/report.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c5
-rw-r--r--source/blender/blenkernel/intern/screen.c43
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c12
-rw-r--r--source/blender/blenkernel/intern/sound.c4
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc184
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc91
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc96
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc22
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c8
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c3
-rw-r--r--source/blender/blenkernel/intern/unit.c8
-rw-r--r--source/blender/blenkernel/intern/volume.cc25
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h6
-rw-r--r--source/blender/blenlib/BLI_enumerable_thread_specific.hh4
-rw-r--r--source/blender/blenlib/BLI_math.h1
-rw-r--r--source/blender/blenlib/BLI_math_base.h6
-rw-r--r--source/blender/blenlib/BLI_math_geom.h7
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h3
-rw-r--r--source/blender/blenlib/BLI_math_time.h51
-rw-r--r--source/blender/blenlib/BLI_math_vector.h5
-rw-r--r--source/blender/blenlib/BLI_memarena.h3
-rw-r--r--source/blender/blenlib/BLI_memiter.h21
-rw-r--r--source/blender/blenlib/BLI_mempool.h9
-rw-r--r--source/blender/blenlib/BLI_task.h76
-rw-r--r--source/blender/blenlib/BLI_task.hh15
-rw-r--r--source/blender/blenlib/BLI_utildefines.h4
-rw-r--r--source/blender/blenlib/BLI_winstuff.h2
-rw-r--r--source/blender/blenlib/CMakeLists.txt5
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c2
-rw-r--r--source/blender/blenlib/intern/array_store.c2
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc155
-rw-r--r--source/blender/blenlib/intern/kdtree_impl.h2
-rw-r--r--source/blender/blenlib/intern/math_geom.c26
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c9
-rw-r--r--source/blender/blenlib/intern/math_rotation.c25
-rw-r--r--source/blender/blenlib/intern/math_time.c70
-rw-r--r--source/blender/blenlib/intern/math_vector.c85
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c22
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc10
-rw-r--r--source/blender/blenlib/intern/path_util.c12
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c2
-rw-r--r--source/blender/blenlib/intern/storage_apple.mm90
-rw-r--r--source/blender/blenlib/intern/task_graph.cc2
-rw-r--r--source/blender/blenlib/intern/task_iterator.c4
-rw-r--r--source/blender/blenlib/intern/task_pool.cc63
-rw-r--r--source/blender/blenlib/intern/task_range.cc12
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc10
-rw-r--r--source/blender/blenlib/intern/winstuff.c10
-rw-r--r--source/blender/blenlib/tests/BLI_delaunay_2d_test.cc372
-rw-r--r--source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_math_time_test.cc35
-rw-r--r--source/blender/blenlib/tests/BLI_stack_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_string_test.cc23
-rw-r--r--source/blender/blenlib/tests/BLI_task_test.cc6
-rw-r--r--source/blender/blenloader/BLO_read_write.h11
-rw-r--r--source/blender/blenloader/BLO_readfile.h33
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/blend_validate.c3
-rw-r--r--source/blender/blenloader/intern/readblenentry.c14
-rw-r--r--source/blender/blenloader/intern/readfile.c201
-rw-r--r--source/blender/blenloader/intern/readfile.h14
-rw-r--r--source/blender/blenloader/intern/readfile_tempload.c3
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_270.c8
-rw-r--r--source/blender/blenloader/intern/versioning_280.c20
-rw-r--r--source/blender/blenloader/intern/versioning_290.c74
-rw-r--r--source/blender/blenloader/intern/versioning_300.c171
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc50
-rw-r--r--source/blender/blenloader/intern/versioning_common.h37
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc3
-rw-r--r--source/blender/bmesh/bmesh_class.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_inline.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c303
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c12
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c259
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.c43
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.c227
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c4
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c2
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c6
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c5
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c2
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c3
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c2
-rw-r--r--source/blender/compositor/COM_defines.h18
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc316
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h77
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.cc17
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.h30
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc6
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h4
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cc3
-rw-r--r--source/blender/compositor/nodes/COM_AntiAliasingNode.h4
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cc2
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cc68
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.cc18
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cc34
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.h19
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cc7
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cc11
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.h5
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cc11
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.h4
-rw-r--r--source/blender/datatoc/datatoc_icon.c49
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc16
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc30
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.h4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc6
-rw-r--r--source/blender/draw/CMakeLists.txt3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c28
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c2
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h98
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc835
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_extractors.c476
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_private.h321
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c357
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c278
-rw-r--r--source/blender/draw/intern/draw_hair.c106
-rw-r--r--source/blender/draw/intern/draw_hair_private.h13
-rw-r--r--source/blender/draw/intern/draw_manager.c2
-rw-r--r--source/blender/draw/intern/draw_manager_data.c2
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c6
-rw-r--r--source/blender/draw/intern/draw_shader.c122
-rw-r--r--source/blender/draw/intern/draw_shader.h47
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc66
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc16
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc57
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc20
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc20
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc43
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc100
-rw-r--r--source/blender/draw/tests/shaders_test.cc23
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c20
-rw-r--r--source/blender/editors/animation/anim_deps.c13
-rw-r--r--source/blender/editors/animation/keyframes_general.c2
-rw-r--r--source/blender/editors/armature/armature_add.c26
-rw-r--r--source/blender/editors/armature/armature_intern.h8
-rw-r--r--source/blender/editors/armature/armature_skinning.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c39
-rw-r--r--source/blender/editors/armature/pose_slide.c980
-rw-r--r--source/blender/editors/armature/pose_transform.c37
-rw-r--r--source/blender/editors/armature/pose_utils.c22
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/curve/editcurve_paint.c22
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c6
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_utils.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c2
-rw-r--r--source/blender/editors/include/ED_info.h4
-rw-r--r--source/blender/editors/include/ED_mesh.h12
-rw-r--r--source/blender/editors/include/ED_node.h5
-rw-r--r--source/blender/editors/include/ED_object.h12
-rw-r--r--source/blender/editors/include/ED_particle.h7
-rw-r--r--source/blender/editors/include/ED_screen.h4
-rw-r--r--source/blender/editors/include/ED_sequencer.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h43
-rw-r--r--source/blender/editors/include/UI_interface.h11
-rw-r--r--source/blender/editors/include/UI_view2d.h75
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface.c11
-rw-r--r--source/blender/editors/interface/interface_context_menu.c1
-rw-r--r--source/blender/editors/interface/interface_handlers.c10
-rw-r--r--source/blender/editors/interface/interface_ops.c4
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_region_search.c36
-rw-r--r--source/blender/editors/interface/interface_widgets.c35
-rw-r--r--source/blender/editors/interface/view2d.c3
-rw-r--r--source/blender/editors/interface/view2d_edge_pan.c345
-rw-r--r--source/blender/editors/interface/view2d_ops.c160
-rw-r--r--source/blender/editors/mask/mask_shapekey.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add.c7
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c7
-rw-r--r--source/blender/editors/mesh/editmesh_automerge.c14
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c16
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c9
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c68
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_screw.c7
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c7
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c14
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c24
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c11
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c9
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c4
-rw-r--r--source/blender/editors/mesh/editmesh_path.c21
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c42
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c27
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c7
-rw-r--r--source/blender/editors/mesh/editmesh_select.c23
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c35
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c479
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c64
-rw-r--r--source/blender/editors/mesh/mesh_intern.h6
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c2
-rw-r--r--source/blender/editors/mesh/meshtools.c2
-rw-r--r--source/blender/editors/object/object_add.c175
-rw-r--r--source/blender/editors/object/object_bake_api.c2
-rw-r--r--source/blender/editors/object/object_constraint.c11
-rw-r--r--source/blender/editors/object/object_data_transform.c8
-rw-r--r--source/blender/editors/object/object_edit.c4
-rw-r--r--source/blender/editors/object/object_hook.c3
-rw-r--r--source/blender/editors/object/object_modes.c10
-rw-r--r--source/blender/editors/object/object_relations.c3
-rw-r--r--source/blender/editors/object/object_remesh.c9
-rw-r--r--source/blender/editors/object/object_shader_fx.c133
-rw-r--r--source/blender/editors/object/object_transform.c17
-rw-r--r--source/blender/editors/physics/particle_edit.c98
-rw-r--r--source/blender/editors/physics/physics_fluid.c6
-rw-r--r--source/blender/editors/render/render_internal.c6
-rw-r--r--source/blender/editors/render/render_opengl.c2
-rw-r--r--source/blender/editors/render/render_view.c1
-rw-r--r--source/blender/editors/scene/scene_edit.c2
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c36
-rw-r--r--source/blender/editors/screen/screen_ops.c88
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_action/action_select.c18
-rw-r--r--source/blender/editors/space_action/space_action.c2
-rw-r--r--source/blender/editors/space_clip/clip_editor.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c10
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c138
-rw-r--r--source/blender/editors/space_file/file_draw.c33
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c39
-rw-r--r--source/blender/editors/space_file/filelist.c5
-rw-r--r--source/blender/editors/space_file/filesel.c1
-rw-r--r--source/blender/editors/space_file/space_file.c1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c4
-rw-r--r--source/blender/editors/space_graph/graph_select.c62
-rw-r--r--source/blender/editors/space_graph/space_graph.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c5
-rw-r--r--source/blender/editors/space_image/image_undo.c5
-rw-r--r--source/blender/editors/space_info/info_draw.c4
-rw-r--r--source/blender/editors/space_info/info_stats.c149
-rw-r--r--source/blender/editors/space_node/node_add.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc38
-rw-r--r--source/blender/editors/space_node/node_edit.cc2
-rw-r--r--source/blender/editors/space_node/node_intern.h4
-rw-r--r--source/blender/editors/space_node/node_relationships.cc11
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c12
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c64
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c61
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc92
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc13
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.hh3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh23
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh9
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc130
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc75
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc366
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh35
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc347
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.hh21
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c106
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c26
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h2
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c510
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c366
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c7
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c6
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c6
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c3
-rw-r--r--source/blender/editors/transform/transform_convert_node.c66
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c513
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c2
-rw-r--r--source/blender/editors/transform/transform_mode.c35
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c2
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c5
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c43
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c145
-rw-r--r--source/blender/editors/transform/transform_ops.c7
-rw-r--r--source/blender/editors/transform/transform_snap.c2
-rw-r--r--source/blender/editors/undo/ed_undo.c6
-rw-r--r--source/blender/editors/undo/memfile_undo.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c16
-rw-r--r--source/blender/editors/uvedit/uvedit_path.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_rip.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c2
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh2
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_lineart.h4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c109
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h23
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c14
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c91
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c43
-rw-r--r--source/blender/gpu/GPU_index_buffer.h13
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc20
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl6
-rw-r--r--source/blender/gpu/tests/gpu_index_buffer_test.cc4
-rw-r--r--source/blender/imbuf/IMB_imbuf.h14
-rw-r--r--source/blender/imbuf/intern/IMB_indexer.h11
-rw-r--r--source/blender/imbuf/intern/anim_movie.c118
-rw-r--r--source/blender/imbuf/intern/colormanagement.c7
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp5
-rw-r--r--source/blender/imbuf/intern/divers.c9
-rw-r--r--source/blender/imbuf/intern/imageprocess.c278
-rw-r--r--source/blender/imbuf/intern/indexer.c101
-rw-r--r--source/blender/imbuf/intern/rectop.c9
-rw-r--r--source/blender/imbuf/intern/thumbs.c6
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c3
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc45
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc41
-rw-r--r--source/blender/io/collada/BCMath.cpp5
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc4
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc4
-rw-r--r--source/blender/makesdna/DNA_action_types.h9
-rw-r--r--source/blender/makesdna/DNA_armature_types.h38
-rw-r--r--source/blender/makesdna/DNA_color_types.h34
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h2
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h19
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h1
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h4
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h25
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h12
-rw-r--r--source/blender/makesdna/DNA_space_types.h70
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h6
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c5
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h12
-rw-r--r--source/blender/makesdna/intern/makesdna.c4
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c6
-rw-r--r--source/blender/makesrna/intern/rna_armature.c114
-rw-r--r--source/blender/makesrna/intern/rna_curve.c2
-rw-r--r--source/blender/makesrna/intern/rna_define.c4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c4
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c8
-rw-r--r--source/blender/makesrna/intern/rna_image.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c166
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c97
-rw-r--r--source/blender/makesrna/intern/rna_object.c7
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_pose.c4
-rw-r--r--source/blender/makesrna/intern/rna_render.c9
-rw-r--r--source/blender/makesrna/intern/rna_scene.c20
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_screen.c4
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c26
-rw-r--r--source/blender/makesrna/intern/rna_space.c188
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rwxr-xr-xsource/blender/makesrna/rna_cleanup/rna_cleaner.py2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c4
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc290
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c2
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c28
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c2
-rw-r--r--source/blender/modifiers/intern/MOD_volume_to_mesh.cc4
-rw-r--r--source/blender/nodes/CMakeLists.txt7
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh14
-rw-r--r--source/blender/nodes/NOD_geometry.h5
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh34
-rw-r--r--source/blender/nodes/NOD_static_types.h5
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc82
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc132
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc407
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc157
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc390
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc201
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc321
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc77
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc10
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc6
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc101
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mixRgb.c)71
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c8
-rw-r--r--source/blender/python/generic/idprop_py_api.c14
-rw-r--r--source/blender/python/generic/idprop_py_api.h4
-rw-r--r--source/blender/python/generic/imbuf_py_api.c19
-rw-r--r--source/blender/python/generic/py_capi_utils.c4
-rw-r--r--source/blender/python/intern/bpy.c2
-rw-r--r--source/blender/python/intern/bpy_app.c15
-rw-r--r--source/blender/python/intern/bpy_interface.c8
-rw-r--r--source/blender/python/intern/bpy_library_load.c3
-rw-r--r--source/blender/python/intern/bpy_operator.c6
-rw-r--r--source/blender/python/intern/bpy_props.c4
-rw-r--r--source/blender/python/intern/bpy_rna.c14
-rw-r--r--source/blender/python/intern/bpy_rna_operator.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c2
-rw-r--r--source/blender/render/RE_engine.h1
-rw-r--r--source/blender/render/intern/bake.c16
-rw-r--r--source/blender/render/intern/pipeline.c69
-rw-r--r--source/blender/sequencer/CMakeLists.txt1
-rw-r--r--source/blender/sequencer/SEQ_edit.h2
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h11
-rw-r--r--source/blender/sequencer/SEQ_time.h1
-rw-r--r--source/blender/sequencer/SEQ_transform.h4
-rw-r--r--source/blender/sequencer/SEQ_utils.h4
-rw-r--r--source/blender/sequencer/intern/render.c227
-rw-r--r--source/blender/sequencer/intern/sequence_lookup.c161
-rw-r--r--source/blender/sequencer/intern/sequencer.c3
-rw-r--r--source/blender/sequencer/intern/strip_add.c36
-rw-r--r--source/blender/sequencer/intern/strip_edit.c9
-rw-r--r--source/blender/sequencer/intern/strip_time.c6
-rw-r--r--source/blender/sequencer/intern/strip_transform.c85
-rw-r--r--source/blender/sequencer/intern/utils.c9
-rw-r--r--source/blender/windowmanager/WM_api.h14
-rw-r--r--source/blender/windowmanager/WM_types.h1
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c7
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c19
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c5
-rw-r--r--source/blender/windowmanager/intern/wm_files.c134
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c56
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c4
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c2
-rw-r--r--source/blender/windowmanager/intern/wm_window.c9
-rw-r--r--source/creator/CMakeLists.txt8
-rw-r--r--source/creator/creator_args.c3
-rw-r--r--tests/gtests/CMakeLists.txt2
-rw-r--r--tests/python/batch_import.py2
-rw-r--r--tests/python/bl_run_operators.py4
-rw-r--r--tests/python/bl_test.py13
644 files changed, 17904 insertions, 8226 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f315fa87236..297e32bd67e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -836,7 +836,7 @@ if(WITH_PYTHON)
# because UNIX will search for the old Python paths which may not exist.
# giving errors about missing paths before this case is met.
if(DEFINED PYTHON_VERSION AND "${PYTHON_VERSION}" VERSION_LESS "3.9")
- message(FATAL_ERROR "At least Python 3.9 is required to build")
+ message(FATAL_ERROR "At least Python 3.9 is required to build, but found Python ${PYTHON_VERSION}")
endif()
file(GLOB RESULT "${CMAKE_SOURCE_DIR}/release/scripts/addons")
diff --git a/build_files/build_environment/cmake/tbb.cmake b/build_files/build_environment/cmake/tbb.cmake
index 005616a9f8d..c08ecebc069 100644
--- a/build_files/build_environment/cmake/tbb.cmake
+++ b/build_files/build_environment/cmake/tbb.cmake
@@ -79,6 +79,7 @@ if(WIN32)
# Normal collection of build artifacts
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${HARVEST_TARGET}/tbb/lib/tbb_debug.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbb_debug.dll ${HARVEST_TARGET}/tbb/bin/tbb_debug.dll
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_debug.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_debug.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy_debug.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy_debug.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc_debug.dll ${HARVEST_TARGET}/tbb/bin/tbbmalloc_debug.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc_proxy_debug.dll ${HARVEST_TARGET}/tbb/bin/tbbmalloc_proxy_debug.dll
diff --git a/build_files/cmake/Modules/FindGflags.cmake b/build_files/cmake/Modules/FindGflags.cmake
index 71a05b423ed..e6da056925f 100644
--- a/build_files/cmake/Modules/FindGflags.cmake
+++ b/build_files/cmake/Modules/FindGflags.cmake
@@ -472,8 +472,7 @@ if(NOT GFLAGS_FOUND)
gflags_report_not_found(
"Could not find gflags include directory, set GFLAGS_INCLUDE_DIR "
"to directory containing gflags/gflags.h")
- endif(NOT GFLAGS_INCLUDE_DIR OR
- NOT EXISTS ${GFLAGS_INCLUDE_DIR})
+ endif()
find_library(GFLAGS_LIBRARY NAMES gflags
PATHS ${GFLAGS_LIBRARY_DIR_HINTS}
@@ -484,8 +483,7 @@ if(NOT GFLAGS_FOUND)
gflags_report_not_found(
"Could not find gflags library, set GFLAGS_LIBRARY "
"to full path to libgflags.")
- endif(NOT GFLAGS_LIBRARY OR
- NOT EXISTS ${GFLAGS_LIBRARY})
+ endif()
# gflags typically requires a threading library (which is OS dependent), note
# that this defines the CMAKE_THREAD_LIBS_INIT variable. If we are able to
@@ -560,8 +558,7 @@ if(NOT GFLAGS_FOUND)
gflags_report_not_found(
"Caller defined GFLAGS_INCLUDE_DIR:"
" ${GFLAGS_INCLUDE_DIR} does not contain gflags/gflags.h header.")
- endif(GFLAGS_INCLUDE_DIR AND
- NOT EXISTS ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h)
+ endif()
# TODO: This regex for gflags library is pretty primitive, we use lowercase
# for comparison to handle Windows using CamelCase library names, could
# this check be better?
@@ -571,8 +568,7 @@ if(NOT GFLAGS_FOUND)
gflags_report_not_found(
"Caller defined GFLAGS_LIBRARY: "
"${GFLAGS_LIBRARY} does not match gflags.")
- endif(GFLAGS_LIBRARY AND
- NOT "${LOWERCASE_GFLAGS_LIBRARY}" MATCHES ".*gflags[^/]*")
+ endif()
gflags_reset_find_library_prefix()
diff --git a/build_files/cmake/Modules/FindNanoVDB.cmake b/build_files/cmake/Modules/FindNanoVDB.cmake
index 95d76fb39af..e830f770c03 100644
--- a/build_files/cmake/Modules/FindNanoVDB.cmake
+++ b/build_files/cmake/Modules/FindNanoVDB.cmake
@@ -40,7 +40,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(NanoVDB DEFAULT_MSG
IF(NANOVDB_FOUND)
SET(NANOVDB_INCLUDE_DIRS ${NANOVDB_INCLUDE_DIR})
-ENDIF(NANOVDB_FOUND)
+ENDIF()
MARK_AS_ADVANCED(
NANOVDB_INCLUDE_DIR
diff --git a/build_files/cmake/Modules/FindOpenCOLLADA.cmake b/build_files/cmake/Modules/FindOpenCOLLADA.cmake
index 00898923fbd..4e83fd04f38 100644
--- a/build_files/cmake/Modules/FindOpenCOLLADA.cmake
+++ b/build_files/cmake/Modules/FindOpenCOLLADA.cmake
@@ -46,7 +46,7 @@ SET(_opencollada_FIND_COMPONENTS
)
# Fedora openCOLLADA package links these statically
-# note that order is important here ot it wont link
+# note that order is important here or it won't link
SET(_opencollada_FIND_STATIC_COMPONENTS
buffer
ftoa
diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
index 78f8e03807f..a6fb463432b 100644
--- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake
+++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
@@ -44,7 +44,7 @@ SET(PYTHON_LINKFLAGS "-Xlinker -export-dynamic" CACHE STRING "Linker flags for p
MARK_AS_ADVANCED(PYTHON_LINKFLAGS)
-# if the user passes these defines as args, we dont want to overwrite
+# if the user passes these defines as args, we don't want to overwrite
SET(_IS_INC_DEF OFF)
SET(_IS_INC_CONF_DEF OFF)
SET(_IS_LIB_DEF OFF)
@@ -143,7 +143,7 @@ IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_
SET(_PYTHON_ABI_FLAGS "${_CURRENT_ABI_FLAGS}")
break()
ELSE()
- # ensure we dont find values from 2 different ABI versions
+ # ensure we don't find values from 2 different ABI versions
IF(NOT _IS_INC_DEF)
UNSET(PYTHON_INCLUDE_DIR CACHE)
ENDIF()
diff --git a/build_files/cmake/Modules/Findsse2neon.cmake b/build_files/cmake/Modules/Findsse2neon.cmake
index 2159dfac114..5c163326251 100644
--- a/build_files/cmake/Modules/Findsse2neon.cmake
+++ b/build_files/cmake/Modules/Findsse2neon.cmake
@@ -40,7 +40,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(sse2neon DEFAULT_MSG
IF(SSE2NEON_FOUND)
SET(SSE2NEON_INCLUDE_DIRS ${SSE2NEON_INCLUDE_DIR})
-ENDIF(SSE2NEON_FOUND)
+ENDIF()
MARK_AS_ADVANCED(
SSE2NEON_INCLUDE_DIR
diff --git a/build_files/cmake/clang_array_check.py b/build_files/cmake/clang_array_check.py
index 57311623cda..09ff4f413db 100644
--- a/build_files/cmake/clang_array_check.py
+++ b/build_files/cmake/clang_array_check.py
@@ -305,7 +305,7 @@ def file_check_arg_sizes(tu):
for i, node_child in enumerate(children):
children = list(node_child.get_children())
- # skip if we dont have an index...
+ # skip if we don't have an index...
size_def = args_size_definition.get(i, -1)
if size_def == -1:
@@ -354,7 +354,7 @@ def file_check_arg_sizes(tu):
filepath # always the same but useful when running threaded
))
- # we dont really care what we are looking at, just scan entire file for
+ # we don't really care what we are looking at, just scan entire file for
# function calls.
def recursive_func_call_check(node):
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 5ae5ed7c29e..8ad3f77c7d3 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -694,7 +694,7 @@ macro(message_first_run)
endmacro()
# when we have warnings as errors applied globally this
-# needs to be removed for some external libs which we dont maintain.
+# needs to be removed for some external libs which we don't maintain.
# utility macro
macro(remove_cc_flag
@@ -794,7 +794,7 @@ macro(remove_extra_strict_flags)
endmacro()
# note, we can only append flags on a single file so we need to negate the options.
-# at the moment we cant shut up ffmpeg deprecations, so use this, but will
+# at the moment we can't shut up ffmpeg deprecations, so use this, but will
# probably add more removals here.
macro(remove_strict_c_flags_file
filenames)
@@ -963,14 +963,6 @@ macro(blender_project_hack_post)
unset(_reset_standard_cflags_rel)
unset(_reset_standard_cxxflags_rel)
- # ------------------------------------------------------------------
- # workaround for omission in cmake 2.8.4's GNU.cmake, fixed in 2.8.5
- if(CMAKE_COMPILER_IS_GNUCC)
- if(NOT DARWIN)
- set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ")
- endif()
- endif()
-
endmacro()
# pair of macros to allow libraries to be specify files to install, but to
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index fe9dd6a58de..90188751fc0 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -388,6 +388,10 @@ endif()
if(WITH_TBB)
find_package(TBB)
+ if(NOT TBB_FOUND)
+ message(WARNING "TBB not found, disabling WITH_TBB")
+ set(WITH_TBB OFF)
+ endif()
endif()
if(WITH_POTRACE)
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index fcfde5a07ba..7f62399ac4f 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -457,6 +457,10 @@ endif()
if(WITH_TBB)
find_package_wrapper(TBB)
+ if(NOT TBB_FOUND)
+ message(WARNING "TBB not found, disabling WITH_TBB")
+ set(WITH_TBB OFF)
+ endif()
endif()
if(WITH_XR_OPENXR)
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 99a2cb7966f..a0e91199c72 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -261,8 +261,10 @@ if(NOT DEFINED LIBDIR)
else()
message(FATAL_ERROR "32 bit compiler detected, blender no longer provides pre-build libraries for 32 bit windows, please set the LIBDIR cmake variable to your own library folder")
endif()
- # Can be 1910..1912
- if(MSVC_VERSION GREATER 1919)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30130)
+ message(STATUS "Visual Studio 2022 detected.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
+ elseif(MSVC_VERSION GREATER 1919)
message(STATUS "Visual Studio 2019 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
elseif(MSVC_VERSION GREATER 1909)
@@ -548,7 +550,6 @@ if(WITH_OPENIMAGEIO)
set(OPENIMAGEIO_LIBRARIES ${OIIO_OPTIMIZED} ${OIIO_DEBUG})
set(OPENIMAGEIO_DEFINITIONS "-DUSE_TBB=0")
- set(OPENCOLORIO_DEFINITIONS "-DDOpenColorIO_SKIP_IMPORTS")
set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe")
add_definitions(-DOIIO_STATIC_DEFINE)
add_definitions(-DOIIO_NO_SSE=1)
@@ -594,7 +595,7 @@ if(WITH_OPENCOLORIO)
debug ${OPENCOLORIO_LIBPATH}/libexpatdMD.lib
debug ${OPENCOLORIO_LIBPATH}/pystring_d.lib
)
- set(OPENCOLORIO_DEFINITIONS)
+ set(OPENCOLORIO_DEFINITIONS "-DOpenColorIO_SKIP_IMPORTS")
endif()
if(WITH_OPENVDB)
diff --git a/build_files/windows/autodetect_msvc.cmd b/build_files/windows/autodetect_msvc.cmd
index 85b3c095d1f..6cee4765b93 100644
--- a/build_files/windows/autodetect_msvc.cmd
+++ b/build_files/windows/autodetect_msvc.cmd
@@ -6,6 +6,9 @@ if %ERRORLEVEL% EQU 0 goto DetectionComplete
call "%~dp0\detect_msvc2019.cmd"
if %ERRORLEVEL% EQU 0 goto DetectionComplete
+call "%~dp0\detect_msvc2022.cmd"
+if %ERRORLEVEL% EQU 0 goto DetectionComplete
+
echo Compiler Detection failed. Use verbose switch for more information.
exit /b 1
diff --git a/build_files/windows/check_libraries.cmd b/build_files/windows/check_libraries.cmd
index 8e43cda9eb7..c495ee6eee9 100644
--- a/build_files/windows/check_libraries.cmd
+++ b/build_files/windows/check_libraries.cmd
@@ -1,5 +1,6 @@
if "%BUILD_VS_YEAR%"=="2017" set BUILD_VS_LIBDIRPOST=vc15
if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
+if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST%
set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%"
diff --git a/build_files/windows/configure_msbuild.cmd b/build_files/windows/configure_msbuild.cmd
index be69f99a8e8..a9267e8cfbb 100644
--- a/build_files/windows/configure_msbuild.cmd
+++ b/build_files/windows/configure_msbuild.cmd
@@ -19,10 +19,10 @@ if "%WITH_PYDEBUG%"=="1" (
set PYDEBUG_CMAKE_ARGS=-DWINDOWS_PYTHON_DEBUG=On
)
-if "%BUILD_VS_YEAR%"=="2019" (
- set BUILD_PLATFORM_SELECT=-A %MSBUILD_PLATFORM%
-) else (
+if "%BUILD_VS_YEAR%"=="2017" (
set BUILD_GENERATOR_POST=%WINDOWS_ARCH%
+) else (
+ set BUILD_PLATFORM_SELECT=-A %MSBUILD_PLATFORM%
)
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%BUILD_GENERATOR_POST%" %BUILD_PLATFORM_SELECT% %TESTS_CMAKE_ARGS% %CLANG_CMAKE_ARGS% %ASAN_CMAKE_ARGS% %PYDEBUG_CMAKE_ARGS%
diff --git a/build_files/windows/detect_msvc2022.cmd b/build_files/windows/detect_msvc2022.cmd
new file mode 100644
index 00000000000..f30210f4e38
--- /dev/null
+++ b/build_files/windows/detect_msvc2022.cmd
@@ -0,0 +1,3 @@
+set BUILD_VS_VER=17
+set BUILD_VS_YEAR=2022
+call "%~dp0\detect_msvc_vswhere.cmd"
diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd
index 54dc41ece87..000b98c992e 100644
--- a/build_files/windows/parse_arguments.cmd
+++ b/build_files/windows/parse_arguments.cmd
@@ -66,6 +66,14 @@ if NOT "%1" == "" (
) else if "%1" == "2019b" (
set BUILD_VS_YEAR=2019
set VSWHERE_ARGS=-products Microsoft.VisualStudio.Product.BuildTools
+ ) else if "%1" == "2022" (
+ set BUILD_VS_YEAR=2022
+ ) else if "%1" == "2022pre" (
+ set BUILD_VS_YEAR=2022
+ set VSWHERE_ARGS=-prerelease
+ ) else if "%1" == "2022b" (
+ set BUILD_VS_YEAR=2022
+ set VSWHERE_ARGS=-products Microsoft.VisualStudio.Product.BuildTools
) else if "%1" == "packagename" (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2"
shift /1
diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt
index 7040fd190f3..a854d2a267b 100644
--- a/doc/python_api/requirements.txt
+++ b/doc/python_api/requirements.txt
@@ -1,2 +1,13 @@
-Sphinx==3.5.3
+sphinx==3.5.4
+
+# Sphinx dependencies that are important
+Jinja2==2.11.3
+Pygments==2.9.0
+docutils==0.16
+snowballstemmer==2.1.0
+babel==2.9.1
+requests==2.25.1
+
+# Only needed to match the theme used for the official documentation.
+# Without this theme, the default theme will be used.
sphinx_rtd_theme==0.5.2
diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h
index 03fd0112095..6bc92278a33 100644
--- a/extern/mantaflow/preprocessed/gitinfo.h
+++ b/extern/mantaflow/preprocessed/gitinfo.h
@@ -1,3 +1,3 @@
-#define MANTA_GIT_VERSION "commit 9c505cd22e289b98c9aa717efba8ef3201c7e458"
+#define MANTA_GIT_VERSION "commit 8fbebe02459b7f72575872c20961f7cb757db408"
diff --git a/extern/mantaflow/preprocessed/kernel.h b/extern/mantaflow/preprocessed/kernel.h
index 90e30cd21e1..dbcc2342a11 100644
--- a/extern/mantaflow/preprocessed/kernel.h
+++ b/extern/mantaflow/preprocessed/kernel.h
@@ -71,6 +71,19 @@ class ParticleBase;
for (int j = bnd; j < (grid).getSizeY() - bnd; ++j) \
for (int i = bnd; i < (grid).getSizeX() - bnd; ++i)
+#define FOR_NEIGHBORS_BND(grid, radius, bnd) \
+ for (int zj = ((grid).is3D() ? std::max(bnd, k - radius) : 0); \
+ zj <= ((grid).is3D() ? std::min(k + radius, (grid).getSizeZ() - 1 - bnd) : 0); \
+ zj++) \
+ for (int yj = std::max(bnd, j - radius); \
+ yj <= std::min(j + radius, (grid).getSizeY() - 1 - bnd); \
+ yj++) \
+ for (int xj = std::max(bnd, i - radius); \
+ xj <= std::min(i + radius, (grid).getSizeX() - 1 - bnd); \
+ xj++)
+
+#define FOR_NEIGHBORS(grid, radius) FOR_NEIGHBORS_BND(grid, radius, 0)
+
//! Basic data structure for kernel data, initialized based on kernel type (e.g. single, idx, etc).
struct KernelBase {
int maxX, maxY, maxZ, minZ, maxT, minT;
diff --git a/extern/mantaflow/preprocessed/plugin/flip.cpp b/extern/mantaflow/preprocessed/plugin/flip.cpp
index d6fd3437959..8757958d4b0 100644
--- a/extern/mantaflow/preprocessed/plugin/flip.cpp
+++ b/extern/mantaflow/preprocessed/plugin/flip.cpp
@@ -822,33 +822,29 @@ struct ComputeUnionLevelsetPindex : public KernelBase {
{
const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
Real phiv = radius * 1.0; // outside
+ const int r = int(radius) + 1;
- int r = int(radius) + 1;
- int rZ = phi.is3D() ? r : 0;
- for (int zj = k - rZ; zj <= k + rZ; zj++)
- for (int yj = j - r; yj <= j + r; yj++)
- for (int xj = i - r; xj <= i + r; xj++) {
- if (!phi.isInBounds(Vec3i(xj, yj, zj)))
- continue;
+ FOR_NEIGHBORS(phi, r)
+ {
- // note, for the particle indices in indexSys the access is periodic (ie, dont skip for
- // eg inBounds(sx,10,10)
- IndexInt isysIdxS = index.index(xj, yj, zj);
- IndexInt pStart = index(isysIdxS), pEnd = 0;
- if (phi.isInBounds(isysIdxS + 1))
- pEnd = index(isysIdxS + 1);
- else
- pEnd = indexSys.size();
-
- // now loop over particles in cell
- for (IndexInt p = pStart; p < pEnd; ++p) {
- const int psrc = indexSys[p].sourceIndex;
- if (ptype && ((*ptype)[psrc] & exclude))
- continue;
- const Vec3 pos = parts[psrc].pos;
- phiv = std::min(phiv, fabs(norm(gridPos - pos)) - radius);
- }
- }
+ // note, for the particle indices in indexSys the access is periodic (ie, dont skip for eg
+ // inBounds(sx,10,10)
+ IndexInt isysIdxS = index.index(xj, yj, zj);
+ IndexInt pStart = index(isysIdxS), pEnd = 0;
+ if (phi.isInBounds(isysIdxS + 1))
+ pEnd = index(isysIdxS + 1);
+ else
+ pEnd = indexSys.size();
+
+ // now loop over particles in cell
+ for (IndexInt p = pStart; p < pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ if (ptype && ((*ptype)[psrc] & exclude))
+ continue;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min(phiv, fabs(norm(gridPos - pos)) - radius);
+ }
+ }
phi(i, j, k) = phiv;
}
inline const Grid<int> &getArg0()
@@ -1026,39 +1022,35 @@ struct ComputeAveragedLevelsetWeight : public KernelBase {
// loop over neighborhood, similar to ComputeUnionLevelsetPindex
const Real sradiusInv = 1. / (4. * radius * radius);
- int r = int(1. * radius) + 1;
- int rZ = phi.is3D() ? r : 0;
+ const int r = int(radius) + 1;
// accumulators
Real wacc = 0.;
Vec3 pacc = Vec3(0.);
Real racc = 0.;
- for (int zj = k - rZ; zj <= k + rZ; zj++)
- for (int yj = j - r; yj <= j + r; yj++)
- for (int xj = i - r; xj <= i + r; xj++) {
- if (!phi.isInBounds(Vec3i(xj, yj, zj)))
- continue;
+ FOR_NEIGHBORS(phi, r)
+ {
- IndexInt isysIdxS = index.index(xj, yj, zj);
- IndexInt pStart = index(isysIdxS), pEnd = 0;
- if (phi.isInBounds(isysIdxS + 1))
- pEnd = index(isysIdxS + 1);
- else
- pEnd = indexSys.size();
- for (IndexInt p = pStart; p < pEnd; ++p) {
- IndexInt psrc = indexSys[p].sourceIndex;
- if (ptype && ((*ptype)[psrc] & exclude))
- continue;
+ IndexInt isysIdxS = index.index(xj, yj, zj);
+ IndexInt pStart = index(isysIdxS), pEnd = 0;
+ if (phi.isInBounds(isysIdxS + 1))
+ pEnd = index(isysIdxS + 1);
+ else
+ pEnd = indexSys.size();
+ for (IndexInt p = pStart; p < pEnd; ++p) {
+ IndexInt psrc = indexSys[p].sourceIndex;
+ if (ptype && ((*ptype)[psrc] & exclude))
+ continue;
- Vec3 pos = parts[psrc].pos;
- Real s = normSquare(gridPos - pos) * sradiusInv;
- // Real w = std::max(0., cubed(1.-s) );
- Real w = std::max(0., (1. - s)); // a bit smoother
- wacc += w;
- racc += radius * w;
- pacc += pos * w;
- }
- }
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos - pos) * sradiusInv;
+ // Real w = std::max(0., cubed(1.-s) );
+ Real w = std::max(0., (1. - s)); // a bit smoother
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
if (wacc > VECTOR_EPSILON) {
racc /= wacc;
diff --git a/extern/mantaflow/preprocessed/plugin/meshplugins.cpp b/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
index cf315429d65..043660db20b 100644
--- a/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
+++ b/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
@@ -234,10 +234,10 @@ void subdivideMesh(
normalize(ne2);
// Real thisArea = sqrMag(cross(-e2,e0));
- // small angle approximation says sin(x) = arcsin(x) = x,
- // arccos(x) = pi/2 - arcsin(x),
- // cos(x) = dot(A,B),
- // so angle is approximately 1 - dot(A,B).
+ // small angle approximation says sin(x) = arcsin(x) = x,
+ // arccos(x) = pi/2 - arcsin(x),
+ // cos(x) = dot(A,B),
+ // so angle is approximately 1 - dot(A,B).
Real angle[3];
angle[0] = 1.0 - dot(ne0, -ne2);
angle[1] = 1.0 - dot(ne1, -ne0);
diff --git a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
index 2f876376f53..7a1d8224d94 100644
--- a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
+++ b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
@@ -2287,10 +2287,9 @@ struct knFlipComputePotentialTrappedAir : public KernelBase {
const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
const Vec3 xij = xi - xj;
const Vec3 vij = vi - vj;
- Real h = !pot.is3D() ?
- 1.414 * radius :
- 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due
- // to squared resp. cubic neighbor area
+ Real h = !pot.is3D() ? 1.414 * radius :
+ 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius
+ // for h, due to squared resp. cubic neighbor area
vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) *
(1 - norm(xij) / h);
}
diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp
index 283ed7d0adc..50cd9e3db5c 100644
--- a/intern/cycles/blender/blender_light.cpp
+++ b/intern/cycles/blender/blender_light.cpp
@@ -34,12 +34,17 @@ void BlenderSync::sync_light(BL::Object &b_parent,
bool *use_portal)
{
/* test if we need to sync */
- Light *light;
ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
BL::Light b_light(b_ob.data());
+ Light *light = light_map.find(key);
+
+ /* Check if the transform was modified, in case a linked collection is moved we do not get a
+ * specific depsgraph update (T88515). This also mimics the behavior for Objects. */
+ const bool tfm_updated = (light && light->get_tfm() != tfm);
+
/* Update if either object or light data changed. */
- if (!light_map.add_or_update(&light, b_ob, b_parent, key)) {
+ if (!light_map.add_or_update(&light, b_ob, b_parent, key) && !tfm_updated) {
Shader *shader;
if (!shader_map.add_or_update(&shader, b_light)) {
if (light->get_is_portal())
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 785ca6b4e01..c58d2eb6e04 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -289,11 +289,10 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *args)
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
- /* Allow Blender to execute other Python scripts, and isolate TBB tasks so we
- * don't get deadlocks with Blender threads accessing shared data like images. */
+ /* Allow Blender to execute other Python scripts. */
python_thread_state_save(&session->python_thread_state);
- tbb::this_task_arena::isolate([&] { session->render(b_depsgraph); });
+ session->render(b_depsgraph);
python_thread_state_restore(&session->python_thread_state);
@@ -330,8 +329,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
- tbb::this_task_arena::isolate(
- [&] { session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height); });
+ session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height);
python_thread_state_restore(&session->python_thread_state);
@@ -377,7 +375,7 @@ static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
- tbb::this_task_arena::isolate([&] { session->reset_session(b_data, b_depsgraph); });
+ session->reset_session(b_data, b_depsgraph);
python_thread_state_restore(&session->python_thread_state);
@@ -399,7 +397,7 @@ static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
- tbb::this_task_arena::isolate([&] { session->synchronize(b_depsgraph); });
+ session->synchronize(b_depsgraph);
python_thread_state_restore(&session->python_thread_state);
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index b008dfa376f..392fec4d57b 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -1196,16 +1196,18 @@ class OptiXDevice : public CUDADevice {
const CUDAContextScope scope(cuContext);
+ const bool use_fast_trace_bvh = (bvh->params.bvh_type == SceneParams::BVH_STATIC);
+
// Compute memory usage
OptixAccelBufferSizes sizes = {};
OptixAccelBuildOptions options = {};
options.operation = operation;
- if (background) {
- // Prefer best performance and lowest memory consumption in background
+ if (use_fast_trace_bvh) {
+ VLOG(2) << "Using fast to trace OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE | OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
}
else {
- // Prefer fast updates in viewport
+ VLOG(2) << "Using fast to update OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_BUILD | OPTIX_BUILD_FLAG_ALLOW_UPDATE;
}
@@ -1253,15 +1255,16 @@ class OptiXDevice : public CUDADevice {
out_data.device_pointer,
sizes.outputSizeInBytes,
&out_handle,
- background ? &compacted_size_prop : NULL,
- background ? 1 : 0));
+ use_fast_trace_bvh ? &compacted_size_prop : NULL,
+ use_fast_trace_bvh ? 1 : 0));
bvh->traversable_handle = static_cast<uint64_t>(out_handle);
// Wait for all operations to finish
check_result_cuda_ret(cuStreamSynchronize(NULL));
- // Compact acceleration structure to save memory (do not do this in viewport for faster builds)
- if (background) {
+ // Compact acceleration structure to save memory (only if using fast trace as the
+ // OPTIX_BUILD_FLAG_ALLOW_COMPACTION flag is only set in this case).
+ if (use_fast_trace_bvh) {
uint64_t compacted_size = sizes.outputSizeInBytes;
check_result_cuda_ret(
cuMemcpyDtoH(&compacted_size, compacted_size_prop.result, sizeof(compacted_size)));
@@ -1306,6 +1309,8 @@ class OptiXDevice : public CUDADevice {
return;
}
+ const bool use_fast_trace_bvh = (bvh->params.bvh_type == SceneParams::BVH_STATIC);
+
free_bvh_memory_delayed();
BVHOptiX *const bvh_optix = static_cast<BVHOptiX *>(bvh);
@@ -1315,10 +1320,10 @@ class OptiXDevice : public CUDADevice {
if (!bvh->params.top_level) {
assert(bvh->objects.size() == 1 && bvh->geometry.size() == 1);
- // Refit is only possible in viewport for now (because AS is built with
- // OPTIX_BUILD_FLAG_ALLOW_UPDATE only there, see above)
OptixBuildOperation operation = OPTIX_BUILD_OPERATION_BUILD;
- if (refit && !background) {
+ /* Refit is only possible when using fast to trace BVH (because AS is built with
+ * OPTIX_BUILD_FLAG_ALLOW_UPDATE only there, see above). */
+ if (refit && !use_fast_trace_bvh) {
assert(bvh_optix->traversable_handle != 0);
operation = OPTIX_BUILD_OPERATION_UPDATE;
}
diff --git a/intern/cycles/render/alembic_read.cpp b/intern/cycles/render/alembic_read.cpp
index 33ce3502879..c53ec668938 100644
--- a/intern/cycles/render/alembic_read.cpp
+++ b/intern/cycles/render/alembic_read.cpp
@@ -736,13 +736,14 @@ static void process_uvs(CachedData &cache,
const IV2fGeomParam::Sample &sample,
double time)
{
- if (scope != kFacevaryingScope) {
+ if (scope != kFacevaryingScope && scope != kVaryingScope && scope != kVertexScope) {
return;
}
const array<int> *uv_loops = cache.uv_loops.data_for_time_no_check(time).get_data_or_null();
- if (!uv_loops) {
+ /* It's ok to not have loop indices, as long as the scope is not face-varying. */
+ if (!uv_loops && scope == kFacevaryingScope) {
return;
}
@@ -766,9 +767,27 @@ static void process_uvs(CachedData &cache,
const uint32_t *indices = sample.getIndices()->get();
const V2f *values = sample.getVals()->get();
- for (const int uv_loop_index : *uv_loops) {
- const uint32_t index = indices[uv_loop_index];
- *data_float2++ = make_float2(values[index][0], values[index][1]);
+ if (scope == kFacevaryingScope) {
+ for (const int uv_loop_index : *uv_loops) {
+ const uint32_t index = indices[uv_loop_index];
+ *data_float2++ = make_float2(values[index][0], values[index][1]);
+ }
+ }
+ else if (scope == kVaryingScope || scope == kVertexScope) {
+ if (triangles) {
+ for (size_t i = 0; i < triangles->size(); i++) {
+ const int3 t = (*triangles)[i];
+ *data_float2++ = make_float2(values[t.x][0], values[t.x][1]);
+ *data_float2++ = make_float2(values[t.y][0], values[t.y][1]);
+ *data_float2++ = make_float2(values[t.z][0], values[t.z][1]);
+ }
+ }
+ else if (corners) {
+ for (size_t i = 0; i < corners->size(); i++) {
+ const int c = (*corners)[i];
+ *data_float2++ = make_float2(values[c][0], values[c][1]);
+ }
+ }
}
attribute.data.add_data(data, time);
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt
index 51cc47fa704..65a692acd03 100644
--- a/intern/cycles/test/CMakeLists.txt
+++ b/intern/cycles/test/CMakeLists.txt
@@ -15,7 +15,7 @@
if(WITH_GTESTS)
Include(GTestTesting)
- # Otherwise we get warnings here that we cant fix in external projects
+ # Otherwise we get warnings here that we can't fix in external projects
remove_strict_flags()
endif()
diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h
index 203c0b289f6..40c2c431aca 100644
--- a/intern/cycles/util/util_color.h
+++ b/intern/cycles/util/util_color.h
@@ -223,12 +223,14 @@ ccl_device_inline ssef fastpow24(const ssef &arg)
ssef x = fastpow<0x3F4CCCCD, 0x4F55A7FB>(arg); // error max = 0.17 avg = 0.0018 |avg| = 0.05
ssef arg2 = arg * arg;
ssef arg4 = arg2 * arg2;
- x = improve_5throot_solution(x,
- arg4); /* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
- x = improve_5throot_solution(x,
- arg4); /* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
- x = improve_5throot_solution(x,
- arg4); /* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
+
+ /* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
+ x = improve_5throot_solution(x, arg4);
+ /* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
+ x = improve_5throot_solution(x, arg4);
+ /* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
+ x = improve_5throot_solution(x, arg4);
+
return x * (x * x);
}
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 03bc5aea1dd..b010881058b 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -282,8 +282,8 @@ static CPUCapabilities &system_cpu_capabilities()
/* actual opcode for xgetbv */
__asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr_feature_mask), "=d"(edx) : "c"(0));
# elif defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
- xcr_feature_mask = (uint32_t)_xgetbv(
- _XCR_XFEATURE_ENABLED_MASK); /* min VS2010 SP1 compiler is required */
+ /* Minimum VS2010 SP1 compiler is required. */
+ xcr_feature_mask = (uint32_t)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
# else
xcr_feature_mask = 0;
# endif
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index 0c22cf82688..17e2a7dc05b 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -93,40 +93,21 @@ void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
#endif
FFMPEG_INLINE
-void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
+int64_t timestamp_from_pts_or_dts(int64_t pts, int64_t dts)
{
- int i;
-
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
-
- st->cur_dts = av_rescale(timestamp,
- st->time_base.den * (int64_t)ref_st->time_base.num,
- st->time_base.num * (int64_t)ref_st->time_base.den);
+ /* Some videos do not have any pts values, use dts instead in those cases if
+ * possible. Usually when this happens dts can act as pts because as all frames
+ * should then be presented in their decoded in order. IE pts == dts. */
+ if (pts == AV_NOPTS_VALUE) {
+ return dts;
}
+ return pts;
}
FFMPEG_INLINE
-void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
-{
- my_update_cur_dts(s, ref_st, timestamp);
-}
-
-FFMPEG_INLINE
-int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame *picture)
+int64_t av_get_pts_from_frame(AVFrame *picture)
{
- int64_t pts;
- pts = picture->pts;
-
- if (pts == AV_NOPTS_VALUE) {
- pts = picture->pkt_dts;
- }
- if (pts == AV_NOPTS_VALUE) {
- pts = 0;
- }
-
- (void)avctx;
- return pts;
+ return timestamp_from_pts_or_dts(picture->pts, picture->pkt_dts);
}
/* -------------------------------------------------------------------- */
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 1b5cdb3cda0..1815a46591a 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -370,6 +370,7 @@ elseif(WIN32)
intern/GHOST_DropTargetWin32.cpp
intern/GHOST_SystemWin32.cpp
intern/GHOST_WindowWin32.cpp
+ intern/GHOST_Wintab.cpp
intern/GHOST_ContextD3D.h
intern/GHOST_DisplayManagerWin32.h
@@ -377,6 +378,7 @@ elseif(WIN32)
intern/GHOST_SystemWin32.h
intern/GHOST_TaskbarWin32.h
intern/GHOST_WindowWin32.h
+ intern/GHOST_Wintab.h
)
if(NOT WITH_GL_EGL)
@@ -481,10 +483,12 @@ if(WITH_XR_OPENXR)
shlwapi
)
elseif(UNIX AND NOT APPLE)
- list(APPEND XR_PLATFORM_DEFINES
- -DXR_OS_LINUX
- -DXR_USE_PLATFORM_XLIB
- )
+ list(APPEND XR_PLATFORM_DEFINES -DXR_OS_LINUX)
+ if (WITH_GL_EGL)
+ list(APPEND XR_PLATFORM_DEFINES -DXR_USE_PLATFORM_EGL)
+ else()
+ list(APPEND XR_PLATFORM_DEFINES -DXR_USE_PLATFORM_XLIB)
+ endif()
endif()
add_definitions(-DWITH_XR_OPENXR ${XR_PLATFORM_DEFINES})
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 3a8d0fbfecf..7efbd00c2eb 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -105,7 +105,9 @@ typedef enum {
typedef enum {
GHOST_kTabletAutomatic = 0,
- GHOST_kTabletNative,
+ /* Show as Windows Ink to users to match "Use Windows Ink" in tablet utilities,
+ * but we use the dependent Windows Pointer API. */
+ GHOST_kTabletWinPointer,
GHOST_kTabletWintab,
} GHOST_TTabletAPI;
@@ -168,7 +170,7 @@ typedef enum {
GHOST_kButtonMaskRight,
GHOST_kButtonMaskButton4,
GHOST_kButtonMaskButton5,
- /* Trackballs and programmable buttons */
+ /* Trackballs and programmable buttons. */
GHOST_kButtonMaskButton6,
GHOST_kButtonMaskButton7,
GHOST_kButtonNumMasks
@@ -177,15 +179,15 @@ typedef enum {
typedef enum {
GHOST_kEventUnknown = 0,
- GHOST_kEventCursorMove, /// Mouse move event
- GHOST_kEventButtonDown, /// Mouse button event
- GHOST_kEventButtonUp, /// Mouse button event
- GHOST_kEventWheel, /// Mouse wheel event
- GHOST_kEventTrackpad, /// Trackpad event
+ GHOST_kEventCursorMove, /* Mouse move event. */
+ GHOST_kEventButtonDown, /* Mouse button event. */
+ GHOST_kEventButtonUp, /* Mouse button event. */
+ GHOST_kEventWheel, /* Mouse wheel event. */
+ GHOST_kEventTrackpad, /* Trackpad event. */
#ifdef WITH_INPUT_NDOF
- GHOST_kEventNDOFMotion, /// N degree of freedom device motion event
- GHOST_kEventNDOFButton, /// N degree of freedom device button event
+ GHOST_kEventNDOFMotion, /* N degree of freedom device motion event. */
+ GHOST_kEventNDOFButton, /* N degree of freedom device button event. */
#endif
GHOST_kEventKeyDown,
@@ -207,8 +209,8 @@ typedef enum {
GHOST_kEventDraggingExited,
GHOST_kEventDraggingDropDone,
- GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup
- GHOST_kEventNativeResolutionChange, // Needed for Cocoa when window moves to other display
+ GHOST_kEventOpenMainFile, /* Needed for Cocoa to open double-clicked .blend file at startup. */
+ GHOST_kEventNativeResolutionChange, /* Needed for Cocoa when window moves to other display. */
GHOST_kEventTimer,
@@ -281,7 +283,7 @@ typedef enum {
GHOST_kKeyPeriod = '.',
GHOST_kKeySlash = '/',
- // Number keys
+ /* Number keys. */
GHOST_kKey0 = '0',
GHOST_kKey1,
GHOST_kKey2,
@@ -296,7 +298,7 @@ typedef enum {
GHOST_kKeySemicolon = ';',
GHOST_kKeyEqual = '=',
- // Character keys
+ /* Character keys. */
GHOST_kKeyA = 'A',
GHOST_kKeyB,
GHOST_kKeyC,
@@ -335,9 +337,9 @@ typedef enum {
GHOST_kKeyRightControl,
GHOST_kKeyLeftAlt,
GHOST_kKeyRightAlt,
- GHOST_kKeyOS, // Command key on Apple, Windows key(s) on Windows
- GHOST_kKeyGrLess, // German PC only!
- GHOST_kKeyApp, /* Also known as menu key. */
+ GHOST_kKeyOS, /* Command key on Apple, Windows key(s) on Windows. */
+ GHOST_kKeyGrLess, /* German PC only! */
+ GHOST_kKeyApp, /* Also known as menu key. */
GHOST_kKeyCapsLock,
GHOST_kKeyNumLock,
@@ -358,7 +360,7 @@ typedef enum {
GHOST_kKeyUpPage,
GHOST_kKeyDownPage,
- // Numpad keys
+ /* Numpad keys. */
GHOST_kKeyNumpad0,
GHOST_kKeyNumpad1,
GHOST_kKeyNumpad2,
@@ -376,7 +378,7 @@ typedef enum {
GHOST_kKeyNumpadAsterisk,
GHOST_kKeyNumpadSlash,
- // Function keys
+ /* Function keys. */
GHOST_kKeyF1,
GHOST_kKeyF2,
GHOST_kKeyF3,
@@ -402,7 +404,7 @@ typedef enum {
GHOST_kKeyF23,
GHOST_kKeyF24,
- // Multimedia keypad buttons
+ /* Multimedia keypad buttons. */
GHOST_kKeyMediaPlay,
GHOST_kKeyMediaStop,
GHOST_kKeyMediaFirst,
@@ -479,9 +481,9 @@ typedef struct {
typedef enum {
GHOST_kDragnDropTypeUnknown = 0,
- GHOST_kDragnDropTypeFilenames, /*Array of strings representing file names (full path) */
- GHOST_kDragnDropTypeString, /* Unformatted text UTF-8 string */
- GHOST_kDragnDropTypeBitmap /*Bitmap image data */
+ GHOST_kDragnDropTypeFilenames, /* Array of strings representing file names (full path). */
+ GHOST_kDragnDropTypeString, /* Unformatted text UTF-8 string. */
+ GHOST_kDragnDropTypeBitmap /* Bitmap image data. */
} GHOST_TDragnDropTypes;
typedef struct {
@@ -527,18 +529,23 @@ typedef enum {
#ifdef WITH_INPUT_NDOF
typedef struct {
/** N-degree of freedom device data v3 [GSoC 2010] */
- // Each component normally ranges from -1 to +1, but can exceed that.
- // These use blender standard view coordinates, with positive rotations being CCW about the axis.
- float tx, ty, tz; // translation
- float rx, ry, rz; // rotation:
- // axis = (rx,ry,rz).normalized
- // amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg]
- float dt; // time since previous NDOF Motion event
- GHOST_TProgress progress; // Starting, InProgress or Finishing (for modal handlers)
+ /* Each component normally ranges from -1 to +1, but can exceed that.
+ * These use blender standard view coordinates,
+ * with positive rotations being CCW about the axis. */
+ /* translation: */
+ float tx, ty, tz;
+ /* rotation:
+ * - `axis = (rx,ry,rz).normalized`
+ * - `amount = (rx,ry,rz).magnitude` [in revolutions, 1.0 = 360 deg]. */
+ float rx, ry, rz;
+ /** Time since previous NDOF Motion event */
+ float dt;
+ /** Starting, #GHOST_kInProgress or #GHOST_kFinishing (for modal handlers) */
+ GHOST_TProgress progress;
} GHOST_TEventNDOFMotionData;
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
-// good for mouse or other buttons too, hmmm?
+/* Good for mouse or other buttons too, hmmm? */
typedef struct {
GHOST_TButtonAction action;
@@ -561,7 +568,7 @@ typedef struct {
*/
/** The ascii code for the key event ('\0' if none). */
char ascii;
- /** The unicode character. if the length is 6, not NULL terminated if all 6 are set */
+ /** The unicode character. if the length is 6, not NULL terminated if all 6 are set. */
char utf8_buf[6];
/** Generated by auto-repeat. */
@@ -594,7 +601,8 @@ typedef void *GHOST_TEmbedderWindowID;
#endif // _WIN32
#ifndef _WIN32
-// I can't use "Window" from "<X11/Xlib.h>" because it conflits with Window defined in winlay.h
+/* I can't use "Window" from `X11/Xlib.h`
+ * because it conflicts with Window defined in `winlay.h`. */
typedef int GHOST_TEmbedderWindowID;
#endif // _WIN32
@@ -642,8 +650,10 @@ typedef void *(*GHOST_XrGraphicsContextBindFn)(void);
typedef void (*GHOST_XrGraphicsContextUnbindFn)(GHOST_ContextHandle graphics_context);
typedef void (*GHOST_XrDrawViewFn)(const struct GHOST_XrDrawViewInfo *draw_view, void *customdata);
-/* An array of GHOST_TXrGraphicsBinding items defining the candidate bindings to use. The first
- * available candidate will be chosen, so order defines priority. */
+/**
+ * An array of #GHOST_TXrGraphicsBinding items defining the candidate bindings to use.
+ * The first available candidate will be chosen, so order defines priority.
+ */
typedef const GHOST_TXrGraphicsBinding *GHOST_XrGraphicsBindingCandidates;
typedef struct {
@@ -684,7 +694,7 @@ typedef struct GHOST_XrDrawViewInfo {
float angle_up, angle_down;
} fov;
- /** Set if the buffer should be submitted with a srgb transfer applied. */
+ /** Set if the buffer should be submitted with a SRGB transfer applied. */
char expects_srgb_buffer;
} GHOST_XrDrawViewInfo;
@@ -734,7 +744,7 @@ typedef struct GHOST_XrActionSpaceInfo {
typedef struct GHOST_XrActionBindingInfo {
const char *action_name;
GHOST_TUns32 count_interaction_paths;
- /** Interaction path: User (subaction) path + component path. */
+ /** Interaction path: User (sub-action) path + component path. */
const char **interaction_paths;
} GHOST_XrActionBindingInfo;
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index bac7057d953..770ead5962e 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -149,6 +149,9 @@ static bool egl_chk(bool result, const char *file = NULL, int line = 0, const ch
static_cast<unsigned int>(error),
code ? code : "<Unknown>",
msg ? msg : "<Unknown>");
+ (void)(file);
+ (void)(line);
+ (void)(text);
#endif
}
@@ -285,6 +288,21 @@ GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut)
return GHOST_kSuccess;
}
+EGLDisplay GHOST_ContextEGL::getDisplay() const
+{
+ return m_display;
+}
+
+EGLConfig GHOST_ContextEGL::getConfig() const
+{
+ return m_config;
+}
+
+EGLContext GHOST_ContextEGL::getContext() const
+{
+ return m_context;
+}
+
GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
{
if (m_display) {
@@ -456,9 +474,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
attrib_list.push_back(EGL_NONE);
- EGLConfig config;
-
- if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &config, 1, &num_config)))
+ if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config)))
goto error;
// A common error is to assume that ChooseConfig worked because it returned EGL_TRUE
@@ -466,7 +482,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
goto error;
if (m_nativeWindow != 0) {
- m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL);
+ m_surface = ::eglCreateWindowSurface(m_display, m_config, m_nativeWindow, NULL);
}
else {
static const EGLint pb_attrib_list[] = {
@@ -476,7 +492,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
1,
EGL_NONE,
};
- m_surface = ::eglCreatePbufferSurface(m_display, config, pb_attrib_list);
+ m_surface = ::eglCreatePbufferSurface(m_display, m_config, pb_attrib_list);
}
if (!EGL_CHK(m_surface != EGL_NO_SURFACE))
@@ -577,7 +593,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
attrib_list.push_back(EGL_NONE);
- m_context = ::eglCreateContext(m_display, config, m_sharedContext, &(attrib_list[0]));
+ m_context = ::eglCreateContext(m_display, m_config, m_sharedContext, &(attrib_list[0]));
if (!EGL_CHK(m_context != EGL_NO_CONTEXT))
goto error;
diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h
index f828271d88d..170647177c2 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.h
+++ b/intern/ghost/intern/GHOST_ContextEGL.h
@@ -36,6 +36,9 @@
#endif
class GHOST_ContextEGL : public GHOST_Context {
+ /* XR code needs low level graphics data to send to OpenXR. */
+ friend class GHOST_XrGraphicsBindingOpenGL;
+
public:
/**
* Constructor.
@@ -100,6 +103,12 @@ class GHOST_ContextEGL : public GHOST_Context {
*/
GHOST_TSuccess getSwapInterval(int &intervalOut);
+ EGLDisplay getDisplay() const;
+
+ EGLConfig getConfig() const;
+
+ EGLContext getContext() const;
+
private:
bool initContextEGLEW();
@@ -117,6 +126,7 @@ class GHOST_ContextEGL : public GHOST_Context {
EGLContext m_context;
EGLSurface m_surface;
EGLDisplay m_display;
+ EGLConfig m_config;
EGLint m_swap_interval;
diff --git a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
index b836f256b27..11134ad1054 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
@@ -160,7 +160,7 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
else {
/* this is a problem for the BGE player :S, perhaps SDL2 will resolve at some point.
* we really need SDL_SetDisplayModeForDisplay() to become an API func! - campbell */
- printf("no windows available, cant fullscreen\n");
+ printf("no windows available, can't fullscreen\n");
/* do not fail, we will try again later when the window is created - wander */
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
index e9e688b76ab..5508d34e96c 100644
--- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
+++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
@@ -31,7 +31,11 @@ class GHOST_IXrGraphicsBinding {
public:
union {
#if defined(WITH_GHOST_X11)
+# if defined(WITH_GL_EGL)
+ XrGraphicsBindingEGLMNDX egl;
+# else
XrGraphicsBindingOpenGLXlibKHR glx;
+# endif
#elif defined(WIN32)
XrGraphicsBindingOpenGLWin32KHR wgl;
XrGraphicsBindingD3D11KHR d3d11;
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 2a7123b293e..9915520691f 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -239,7 +239,7 @@ class GHOST_System : public GHOST_ISystem {
* Set which tablet API to use. Only affects Windows, other platforms have a single API.
* \param api: Enum indicating which API to use.
*/
- void setTabletAPI(GHOST_TTabletAPI api);
+ virtual void setTabletAPI(GHOST_TTabletAPI api) override;
GHOST_TTabletAPI getTabletAPI(void);
#ifdef WITH_INPUT_NDOF
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 8862d0457f2..eccef18bee2 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -376,7 +376,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
- // cant use setCursorPosition because the mouse may have no focus!
+ // can't use setCursorPosition because the mouse may have no focus!
if (x_new != x_root || y_new != y_root) {
if (1) { //xme.time > m_last_warp) {
/* when wrapping we don't need to add an event because the
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index c3a243cc22c..a70e5b91674 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -139,7 +139,6 @@ static void initRawInput()
#undef DEVICE_COUNT
}
-typedef HRESULT(API *GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
typedef BOOL(API *GHOST_WIN32_EnableNonClientDpiScaling)(HWND);
GHOST_SystemWin32::GHOST_SystemWin32()
@@ -867,15 +866,151 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- if (type == GHOST_kEventButtonDown) {
- window->updateMouseCapture(MousePressed);
+ GHOST_TabletData td = window->getTabletData();
+
+ /* Move mouse to button event position. */
+ if (window->getTabletData().Active != GHOST_kTabletModeNone) {
+ /* Tablet should be handling in between mouse moves, only move to event position. */
+ DWORD msgPos = ::GetMessagePos();
+ int msgPosX = GET_X_LPARAM(msgPos);
+ int msgPosY = GET_Y_LPARAM(msgPos);
+ system->pushEvent(new GHOST_EventCursor(
+ ::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td));
}
- else if (type == GHOST_kEventButtonUp) {
- window->updateMouseCapture(MouseReleased);
+
+ window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased);
+ return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td);
+}
+
+void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
+{
+ GHOST_Wintab *wt = window->getWintab();
+ if (!wt) {
+ return;
}
- return new GHOST_EventButton(
- system->getMilliSeconds(), type, window, mask, window->getTabletData());
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
+
+ std::vector<GHOST_WintabInfoWin32> wintabInfo;
+ wt->getInput(wintabInfo);
+
+ /* Wintab provided coordinates are untrusted until a Wintab and Win32 button down event match.
+ * This is checked on every button down event, and revoked if there is a mismatch. This can
+ * happen when Wintab incorrectly scales cursor position or is in mouse mode.
+ *
+ * If Wintab was never trusted while processing this Win32 event, a fallback Ghost cursor move
+ * event is created at the position of the Win32 WT_PACKET event. */
+ bool mouseMoveHandled;
+ bool useWintabPos;
+ mouseMoveHandled = useWintabPos = wt->trustCoordinates();
+
+ for (GHOST_WintabInfoWin32 &info : wintabInfo) {
+ switch (info.type) {
+ case GHOST_kEventCursorMove: {
+ if (!useWintabPos) {
+ continue;
+ }
+
+ wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y);
+ system->pushEvent(new GHOST_EventCursor(
+ info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
+
+ break;
+ }
+ case GHOST_kEventButtonDown: {
+ UINT message;
+ switch (info.button) {
+ case GHOST_kButtonMaskLeft:
+ message = WM_LBUTTONDOWN;
+ break;
+ case GHOST_kButtonMaskRight:
+ message = WM_RBUTTONDOWN;
+ break;
+ case GHOST_kButtonMaskMiddle:
+ message = WM_MBUTTONDOWN;
+ break;
+ default:
+ continue;
+ }
+
+ /* Wintab buttons are modal, but the API does not inform us what mode a pressed button is
+ * in. Only issue button events if we can steal an equivalent Win32 button event from the
+ * event queue. */
+ MSG msg;
+ if (PeekMessage(&msg, window->getHWND(), message, message, PM_NOYIELD) &&
+ msg.message != WM_QUIT) {
+
+ /* Test for Win32/Wintab button down match. */
+ useWintabPos = wt->testCoordinates(msg.pt.x, msg.pt.y, info.x, info.y);
+ if (!useWintabPos) {
+ continue;
+ }
+
+ /* Steal the Win32 event which was previously peeked. */
+ PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD);
+
+ /* Move cursor to button location, to prevent incorrect cursor position when
+ * transitioning from unsynchronized Win32 to Wintab cursor control. */
+ wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y);
+ system->pushEvent(new GHOST_EventCursor(
+ info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
+
+ window->updateMouseCapture(MousePressed);
+ system->pushEvent(
+ new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
+
+ mouseMoveHandled = true;
+ break;
+ }
+ }
+ case GHOST_kEventButtonUp: {
+ if (!useWintabPos) {
+ continue;
+ }
+
+ UINT message;
+ switch (info.button) {
+ case GHOST_kButtonMaskLeft:
+ message = WM_LBUTTONUP;
+ break;
+ case GHOST_kButtonMaskRight:
+ message = WM_RBUTTONUP;
+ break;
+ case GHOST_kButtonMaskMiddle:
+ message = WM_MBUTTONUP;
+ break;
+ default:
+ continue;
+ }
+
+ /* Wintab buttons are modal, but the API does not inform us what mode a pressed button is
+ * in. Only issue button events if we can steal an equivalent Win32 button event from the
+ * event queue. */
+ MSG msg;
+ if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) &&
+ msg.message != WM_QUIT) {
+
+ window->updateMouseCapture(MouseReleased);
+ system->pushEvent(
+ new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* Fallback cursor movement if Wintab position were never trusted while processing this event. */
+ if (!mouseMoveHandled) {
+ DWORD pos = GetMessagePos();
+ int x = GET_X_LPARAM(pos);
+ int y = GET_Y_LPARAM(pos);
+
+ /* TODO supply tablet data */
+ system->pushEvent(new GHOST_EventCursor(
+ system->getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, GHOST_TABLET_DATA_NONE));
+ }
}
void GHOST_SystemWin32::processPointerEvent(
@@ -883,7 +1018,7 @@ void GHOST_SystemWin32::processPointerEvent(
{
/* Pointer events might fire when changing windows for a device which is set to use Wintab, even
* when when Wintab is left enabled but set to the bottom of Wintab overlap order. */
- if (!window->useTabletAPI(GHOST_kTabletNative)) {
+ if (!window->usingTabletAPI(GHOST_kTabletWinPointer)) {
return;
}
@@ -894,20 +1029,21 @@ void GHOST_SystemWin32::processPointerEvent(
return;
}
- if (!pointerInfo[0].isPrimary) {
- eventHandled = true;
- return; // For multi-touch displays we ignore these events
- }
-
switch (type) {
- case WM_POINTERENTER:
- window->m_tabletInRange = true;
- system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time,
- GHOST_kEventCursorMove,
- window,
- pointerInfo[0].pixelLocation.x,
- pointerInfo[0].pixelLocation.y,
- pointerInfo[0].tabletData));
+ case WM_POINTERUPDATE:
+ /* Coalesced pointer events are reverse chronological order, reorder chronologically.
+ * Only contiguous move events are coalesced. */
+ for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) {
+ system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time,
+ GHOST_kEventCursorMove,
+ window,
+ pointerInfo[i].pixelLocation.x,
+ pointerInfo[i].pixelLocation.y,
+ pointerInfo[i].tabletData));
+ }
+
+ /* Leave event unhandled so that system cursor is moved. */
+
break;
case WM_POINTERDOWN:
/* Move cursor to point of contact because GHOST_EventButton does not include position. */
@@ -923,18 +1059,10 @@ void GHOST_SystemWin32::processPointerEvent(
pointerInfo[0].buttonMask,
pointerInfo[0].tabletData));
window->updateMouseCapture(MousePressed);
- break;
- case WM_POINTERUPDATE:
- /* Coalesced pointer events are reverse chronological order, reorder chronologically.
- * Only contiguous move events are coalesced. */
- for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) {
- system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time,
- GHOST_kEventCursorMove,
- window,
- pointerInfo[i].pixelLocation.x,
- pointerInfo[i].pixelLocation.y,
- pointerInfo[i].tabletData));
- }
+
+ /* Mark event handled so that mouse button events are not generated. */
+ eventHandled = true;
+
break;
case WM_POINTERUP:
system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
@@ -943,16 +1071,14 @@ void GHOST_SystemWin32::processPointerEvent(
pointerInfo[0].buttonMask,
pointerInfo[0].tabletData));
window->updateMouseCapture(MouseReleased);
- break;
- case WM_POINTERLEAVE:
- window->m_tabletInRange = false;
+
+ /* Mark event handled so that mouse button events are not generated. */
+ eventHandled = true;
+
break;
default:
break;
}
-
- eventHandled = true;
- system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y);
}
GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
@@ -960,18 +1086,14 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
GHOST_TInt32 x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- if (window->m_tabletInRange) {
- if (window->useTabletAPI(GHOST_kTabletNative)) {
- /* Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet
- * input aren't normally generated when using WM_POINTER events, but manually moving the
- * system cursor as we do in WM_POINTER handling does. */
- return NULL;
- }
+ if (window->getTabletData().Active != GHOST_kTabletModeNone) {
+ /* While pen devices are in range, cursor movement is handled by tablet input processing. */
+ return NULL;
}
system->getCursorPosition(x_screen, y_screen);
- if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) {
+ if (window->getCursorGrabModeIsWarp()) {
GHOST_TInt32 x_new = x_screen;
GHOST_TInt32 y_new = y_screen;
GHOST_TInt32 x_accum, y_accum;
@@ -983,7 +1105,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
}
/* Could also clamp to screen bounds wrap with a window outside the view will fail atm.
- * Use offset of 8 in case the window is at screen bounds. */
+ * Use inset in case the window is at screen bounds. */
bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
@@ -999,7 +1121,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
window,
x_screen + x_accum,
y_screen + y_accum,
- window->getTabletData());
+ GHOST_TABLET_DATA_NONE);
}
}
else {
@@ -1008,7 +1130,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
window,
x_screen,
y_screen,
- window->getTabletData());
+ GHOST_TABLET_DATA_NONE);
}
return NULL;
}
@@ -1118,6 +1240,23 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
return event;
}
+GHOST_Event *GHOST_SystemWin32::processWindowSizeEvent(GHOST_WindowWin32 *window)
+{
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
+ GHOST_Event *sizeEvent = new GHOST_Event(
+ system->getMilliSeconds(), GHOST_kEventWindowSize, window);
+
+ /* We get WM_SIZE before we fully init. Do not dispatch before we are continuously resizing. */
+ if (window->m_inLiveResize) {
+ system->pushEvent(sizeEvent);
+ system->dispatchEvents();
+ return NULL;
+ }
+ else {
+ return sizeEvent;
+ }
+}
+
GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type,
GHOST_WindowWin32 *window)
{
@@ -1125,7 +1264,6 @@ GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type,
if (type == GHOST_kEventWindowActivate) {
system->getWindowManager()->setActiveWindow(window);
- window->bringTabletContextToFront();
}
return new GHOST_Event(system->getMilliSeconds(), type, window);
@@ -1153,6 +1291,31 @@ GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data));
}
+void GHOST_SystemWin32::setTabletAPI(GHOST_TTabletAPI api)
+{
+ GHOST_System::setTabletAPI(api);
+
+ /* If API is set to WinPointer (Windows Ink), unload Wintab so that trouble drivers don't disable
+ * Windows Ink. Load Wintab when API is Automatic because decision logic relies on knowing
+ * whether a Wintab device is present. */
+ const bool loadWintab = GHOST_kTabletWinPointer != api;
+ GHOST_WindowManager *wm = getWindowManager();
+
+ for (GHOST_IWindow *win : wm->getWindows()) {
+ GHOST_WindowWin32 *windowWin32 = (GHOST_WindowWin32 *)win;
+ if (loadWintab) {
+ windowWin32->loadWintab(GHOST_kWindowStateMinimized != windowWin32->getState());
+
+ if (windowWin32->usingTabletAPI(GHOST_kTabletWintab)) {
+ windowWin32->resetPointerPenInfo();
+ }
+ }
+ else {
+ windowWin32->closeWintab();
+ }
+ }
+}
+
void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax)
{
minmax->ptMinTrackSize.x = 320;
@@ -1387,33 +1550,100 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
case SC_KEYMENU:
eventHandled = true;
break;
- case SC_RESTORE:
+ case SC_RESTORE: {
::ShowWindow(hwnd, SW_RESTORE);
window->setState(window->getState());
+
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->enable();
+ }
+
eventHandled = true;
break;
+ }
+ case SC_MAXIMIZE: {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->enable();
+ }
+ /* Don't report event as handled so that default handling occurs. */
+ break;
+ }
+ case SC_MINIMIZE: {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->disable();
+ }
+ /* Don't report event as handled so that default handling occurs. */
+ break;
+ }
}
break;
////////////////////////////////////////////////////////////////////////
// Wintab events, processed
////////////////////////////////////////////////////////////////////////
- case WT_PACKET:
- window->processWin32TabletEvent(wParam, lParam);
+ case WT_CSRCHANGE: {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->updateCursorInfo();
+ }
+ eventHandled = true;
+ break;
+ }
+ case WT_PROXIMITY: {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ bool inRange = LOWORD(lParam);
+ if (inRange) {
+ /* Some devices don't emit WT_CSRCHANGE events, so update cursor info here. */
+ wt->updateCursorInfo();
+ }
+ else {
+ wt->leaveRange();
+ }
+ }
+ eventHandled = true;
break;
- case WT_CSRCHANGE:
- case WT_PROXIMITY:
- window->processWin32TabletInitEvent();
+ }
+ case WT_INFOCHANGE: {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->processInfoChange(lParam);
+
+ if (window->usingTabletAPI(GHOST_kTabletWintab)) {
+ window->resetPointerPenInfo();
+ }
+ }
+ eventHandled = true;
+ break;
+ }
+ case WT_PACKET:
+ processWintabEvent(window);
+ eventHandled = true;
break;
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
////////////////////////////////////////////////////////////////////////
- case WM_POINTERENTER:
- case WM_POINTERDOWN:
case WM_POINTERUPDATE:
+ case WM_POINTERDOWN:
case WM_POINTERUP:
- case WM_POINTERLEAVE:
processPointerEvent(msg, window, wParam, lParam, eventHandled);
break;
+ case WM_POINTERLEAVE: {
+ GHOST_TUns32 pointerId = GET_POINTERID_WPARAM(wParam);
+ POINTER_INFO pointerInfo;
+ if (!GetPointerInfo(pointerId, &pointerInfo)) {
+ break;
+ }
+
+ /* Reset pointer pen info if pen device has left tracking range. */
+ if (pointerInfo.pointerType == PT_PEN && !IS_POINTER_INRANGE_WPARAM(wParam)) {
+ window->resetPointerPenInfo();
+ eventHandled = true;
+ }
+ break;
+ }
////////////////////////////////////////////////////////////////////////
// Mouse events, processed
////////////////////////////////////////////////////////////////////////
@@ -1452,7 +1682,20 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_MOUSEMOVE:
+ if (!window->m_mousePresent) {
+ TRACKMOUSEEVENT tme = {sizeof(tme)};
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ TrackMouseEvent(&tme);
+ window->m_mousePresent = true;
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->gainFocus();
+ }
+ }
+
event = processCursorEvent(window);
+
break;
case WM_MOUSEWHEEL: {
/* The WM_MOUSEWHEEL message is sent to the focus window
@@ -1487,7 +1730,17 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
window->loadCursor(true, GHOST_kStandardCursorDefault);
}
break;
-
+ case WM_MOUSELEAVE: {
+ window->m_mousePresent = false;
+ if (window->getTabletData().Active == GHOST_kTabletModeNone) {
+ processCursorEvent(window);
+ }
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->loseFocus();
+ }
+ break;
+ }
////////////////////////////////////////////////////////////////////////
// Mouse events, ignored
////////////////////////////////////////////////////////////////////////
@@ -1535,7 +1788,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* will not be dispatched to OUR active window if we minimize one of OUR windows. */
if (LOWORD(wParam) == WA_INACTIVE)
window->lostMouseCapture();
- window->processWin32TabletActivateEvent(GET_WM_ACTIVATE_STATE(wParam, lParam));
+
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
@@ -1577,6 +1830,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
/* Let DefWindowProc handle it. */
break;
case WM_SIZING:
+ event = processWindowSizeEvent(window);
+ break;
case WM_SIZE:
/* The WM_SIZE message is sent to a window after its size has changed.
* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
@@ -1584,15 +1839,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* to perform any move or size change processing during the WM_WINDOWPOSCHANGED
* message without calling DefWindowProc.
*/
- /* we get first WM_SIZE before we fully init.
- * So, do not dispatch before we continuously resizing. */
- if (window->m_inLiveResize) {
- system->pushEvent(processWindowEvent(GHOST_kEventWindowSize, window));
- system->dispatchEvents();
- }
- else {
- event = processWindowEvent(GHOST_kEventWindowSize, window);
- }
+ event = processWindowSizeEvent(window);
break;
case WM_CAPTURECHANGED:
window->lostMouseCapture();
@@ -1643,6 +1890,21 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
+ case WM_DISPLAYCHANGE: {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->remapCoordinates();
+ }
+ break;
+ }
+ case WM_KILLFOCUS:
+ /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard
+ * focus. We want to prevent this if a window is still active and it loses focus to
+ * nowhere. */
+ if (!wParam && hwnd == ::GetActiveWindow()) {
+ ::SetFocus(hwnd);
+ }
+ break;
////////////////////////////////////////////////////////////////////////
// Window events, ignored
////////////////////////////////////////////////////////////////////////
@@ -1679,12 +1941,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* object associated with the window.
*/
break;
- case WM_KILLFOCUS:
- /* The WM_KILLFOCUS message is sent to a window immediately before it loses the
- * keyboard focus. We want to prevent this if a window is still active and it loses
- * focus to nowhere. */
- if (!wParam && hwnd == ::GetActiveWindow())
- ::SetFocus(hwnd);
case WM_SHOWWINDOW:
/* The WM_SHOWWINDOW message is sent to a window when the window is
* about to be hidden or shown. */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 51c0c984710..7dd61421d4c 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -265,6 +265,16 @@ class GHOST_SystemWin32 : public GHOST_System {
int mouseY,
void *data);
+ /***************************************************************************************
+ ** Modify tablet API
+ ***************************************************************************************/
+
+ /**
+ * Set which tablet API to use.
+ * \param api: Enum indicating which API to use.
+ */
+ void setTabletAPI(GHOST_TTabletAPI api) override;
+
protected:
/**
* Initializes the system.
@@ -309,6 +319,12 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TButtonMask mask);
/**
+ * Creates tablet events from Wintab events.
+ * \param window: The window receiving the event (the active window).
+ */
+ static void processWintabEvent(GHOST_WindowWin32 *window);
+
+ /**
* Creates tablet events from pointer events.
* \param type: The type of pointer event.
* \param window: The window receiving the event (the active window).
@@ -352,6 +368,13 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TKey processSpecialKey(short vKey, short scanCode) const;
/**
+ * Creates a window size event.
+ * \param window: The window receiving the event (the active window).
+ * \return The event created.
+ */
+ static GHOST_Event *processWindowSizeEvent(GHOST_WindowWin32 *window);
+
+ /**
* Creates a window event.
* \param type: The type of event to create.
* \param window: The window receiving the event (the active window).
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index df7e8ba59df..34b44fde48a 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -2563,7 +2563,7 @@ static bool is_filler_char(char c)
return isspace(c) || c == '_' || c == '-' || c == ';' || c == ':';
}
-/* These C functions are copied from Wine 3.12's wintab.c */
+/* These C functions are copied from Wine 3.12's `wintab.c` */
static bool match_token(const char *haystack, const char *needle)
{
const char *h, *n;
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index dcb1ab8c78c..ff0c506feb7 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -556,7 +556,7 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
return cursor;
}
-/* TODO, this is currently never freed but it wont leak either. */
+/* TODO, this is currently never freed but it won't leak either. */
static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
{
if (sdl_std_cursor_array[0] == NULL) {
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index eeafe333633..33c79daf11d 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -21,8 +21,6 @@
* \ingroup GHOST
*/
-#define _USE_MATH_DEFINES
-
#include "GHOST_WindowWin32.h"
#include "GHOST_ContextD3D.h"
#include "GHOST_ContextNone.h"
@@ -72,7 +70,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
bool is_debug,
bool dialog)
: GHOST_Window(width, height, state, wantStereoVisual, false),
- m_tabletInRange(false),
+ m_mousePresent(false),
m_inLiveResize(false),
m_system(system),
m_hDC(0),
@@ -82,6 +80,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_nPressedButtons(0),
m_customCursor(0),
m_wantAlphaBackground(alphaBackground),
+ m_wintab(NULL),
+ m_lastPointerTabletData(GHOST_TABLET_DATA_NONE),
m_normal_state(GHOST_kWindowStateNormal),
m_user32(NULL),
m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : HWND_DESKTOP),
@@ -90,10 +90,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
RECT win_rect = {left, top, (long)(left + width), (long)(top + height)};
- // Initialize tablet variables
- memset(&m_wintab, 0, sizeof(m_wintab));
- m_tabletData = GHOST_TABLET_DATA_NONE;
-
DWORD style = parentwindow ?
WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX :
WS_OVERLAPPEDWINDOW;
@@ -218,65 +214,10 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
// Initialize Wintab
- m_wintab.handle = ::LoadLibrary("Wintab32.dll");
- if (m_wintab.handle && m_system->getTabletAPI() != GHOST_kTabletNative) {
- // Get API functions
- m_wintab.info = (GHOST_WIN32_WTInfo)::GetProcAddress(m_wintab.handle, "WTInfoA");
- m_wintab.open = (GHOST_WIN32_WTOpen)::GetProcAddress(m_wintab.handle, "WTOpenA");
- m_wintab.close = (GHOST_WIN32_WTClose)::GetProcAddress(m_wintab.handle, "WTClose");
- m_wintab.packet = (GHOST_WIN32_WTPacket)::GetProcAddress(m_wintab.handle, "WTPacket");
- m_wintab.enable = (GHOST_WIN32_WTEnable)::GetProcAddress(m_wintab.handle, "WTEnable");
- m_wintab.overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(m_wintab.handle, "WTOverlap");
-
- // Let's see if we can initialize tablet here.
- // Check if WinTab available by getting system context info.
- LOGCONTEXT lc = {0};
- lc.lcOptions |= CXO_SYSTEM;
- if (m_wintab.open && m_wintab.info && m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) {
- // Now init the tablet
- /* The maximum tablet size, pressure and orientation (tilt) */
- AXIS TabletX, TabletY, Pressure, Orientation[3];
-
- // Open a Wintab context
-
- // Open the context
- lc.lcPktData = PACKETDATA;
- lc.lcPktMode = PACKETMODE;
- lc.lcOptions |= CXO_MESSAGES;
- lc.lcMoveMask = PACKETDATA;
-
- /* Set the entire tablet as active */
- m_wintab.info(WTI_DEVICES, DVC_X, &TabletX);
- m_wintab.info(WTI_DEVICES, DVC_Y, &TabletY);
-
- /* get the max pressure, to divide into a float */
- BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
- if (pressureSupport)
- m_wintab.maxPressure = Pressure.axMax;
- else
- m_wintab.maxPressure = 0;
-
- /* get the max tilt axes, to divide into floats */
- BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
- if (tiltSupport) {
- /* does the tablet support azimuth ([0]) and altitude ([1]) */
- if (Orientation[0].axResolution && Orientation[1].axResolution) {
- /* all this assumes the minimum is 0 */
- m_wintab.maxAzimuth = Orientation[0].axMax;
- m_wintab.maxAltitude = Orientation[1].axMax;
- }
- else { /* No so don't do tilt stuff. */
- m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
- }
- }
-
- // The Wintab spec says we must open the context disabled if we are using cursor masks.
- m_wintab.tablet = m_wintab.open(m_hWnd, &lc, FALSE);
- if (m_wintab.enable && m_wintab.tablet) {
- m_wintab.enable(m_wintab.tablet, TRUE);
- }
- }
+ if (system->getTabletAPI() != GHOST_kTabletWinPointer) {
+ loadWintab(GHOST_kWindowStateMinimized != state);
}
+
CoCreateInstance(
CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
}
@@ -289,14 +230,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
m_Bar = NULL;
}
- if (m_wintab.handle) {
- if (m_wintab.close && m_wintab.tablet) {
- m_wintab.close(m_wintab.tablet);
- }
-
- FreeLibrary(m_wintab.handle);
- memset(&m_wintab, 0, sizeof(m_wintab));
- }
+ closeWintab();
if (m_user32) {
FreeLibrary(m_user32);
@@ -913,20 +847,16 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha
GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM lParam)
{
- if (!useTabletAPI(GHOST_kTabletNative)) {
- return GHOST_kFailure;
- }
-
GHOST_TInt32 pointerId = GET_POINTERID_WPARAM(wParam);
GHOST_TInt32 isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
- GHOST_TUns32 outCount;
+ GHOST_TUns32 outCount = 0;
- if (!(GetPointerInfoHistory(pointerId, &outCount, NULL))) {
+ if (!(GetPointerPenInfoHistory(pointerId, &outCount, NULL))) {
return GHOST_kFailure;
}
- auto pointerPenInfo = std::vector<POINTER_PEN_INFO>(outCount);
+ std::vector<POINTER_PEN_INFO> pointerPenInfo(outCount);
outPointerInfo.resize(outCount);
if (!(GetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
@@ -988,148 +918,77 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
}
}
+ if (!outPointerInfo.empty()) {
+ m_lastPointerTabletData = outPointerInfo.back().tabletData;
+ }
+
return GHOST_kSuccess;
}
-void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state)
+void GHOST_WindowWin32::resetPointerPenInfo()
{
- if (!useTabletAPI(GHOST_kTabletWintab)) {
- return;
- }
-
- if (m_wintab.enable && m_wintab.tablet) {
- m_wintab.enable(m_wintab.tablet, state);
-
- if (m_wintab.overlap && state) {
- m_wintab.overlap(m_wintab.tablet, TRUE);
- }
- }
+ m_lastPointerTabletData = GHOST_TABLET_DATA_NONE;
}
-bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const
+GHOST_Wintab *GHOST_WindowWin32::getWintab() const
{
- if (m_system->getTabletAPI() == api) {
- return true;
- }
- else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) {
- if (m_wintab.tablet)
- return api == GHOST_kTabletWintab;
- else
- return api == GHOST_kTabletNative;
- }
- else {
- return false;
- }
+ return m_wintab;
}
-void GHOST_WindowWin32::processWin32TabletInitEvent()
+void GHOST_WindowWin32::loadWintab(bool enable)
{
- if (!useTabletAPI(GHOST_kTabletWintab)) {
- return;
- }
-
- // Let's see if we can initialize tablet here
- if (m_wintab.info && m_wintab.tablet) {
- AXIS Pressure, Orientation[3]; /* The maximum tablet size */
-
- BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
- if (pressureSupport)
- m_wintab.maxPressure = Pressure.axMax;
- else
- m_wintab.maxPressure = 0;
-
- BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
- if (tiltSupport) {
- /* does the tablet support azimuth ([0]) and altitude ([1]) */
- if (Orientation[0].axResolution && Orientation[1].axResolution) {
- m_wintab.maxAzimuth = Orientation[0].axMax;
- m_wintab.maxAltitude = Orientation[1].axMax;
- }
- else { /* No so don't do tilt stuff. */
- m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
+ if (!m_wintab) {
+ if (m_wintab = GHOST_Wintab::loadWintab(m_hWnd)) {
+ if (enable) {
+ m_wintab->enable();
+
+ /* Focus Wintab if cursor is inside this window. This ensures Wintab is enabled when the
+ * tablet is used to change the Tablet API. */
+ GHOST_TInt32 x, y;
+ if (m_system->getCursorPosition(x, y)) {
+ GHOST_Rect rect;
+ getClientBounds(rect);
+
+ if (rect.isInside(x, y)) {
+ m_wintab->gainFocus();
+ }
+ }
}
}
}
+}
- m_tabletData.Active = GHOST_kTabletModeNone;
+void GHOST_WindowWin32::closeWintab()
+{
+ delete m_wintab;
+ m_wintab = NULL;
}
-void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
+bool GHOST_WindowWin32::usingTabletAPI(GHOST_TTabletAPI api) const
{
- if (!useTabletAPI(GHOST_kTabletWintab)) {
- return;
+ if (m_system->getTabletAPI() == api) {
+ return true;
}
-
- if (m_wintab.packet && m_wintab.tablet) {
- PACKET pkt;
- if (m_wintab.packet((HCTX)lParam, wParam, &pkt)) {
- switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
- case 0:
- m_tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */
- break;
- case 1:
- m_tabletData.Active = GHOST_kTabletModeStylus; /* stylus */
- break;
- case 2:
- m_tabletData.Active = GHOST_kTabletModeEraser; /* eraser */
- break;
- }
-
- if (m_wintab.maxPressure > 0) {
- m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
- }
- else {
- m_tabletData.Pressure = 1.0f;
- }
-
- if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) {
- ORIENTATION ort = pkt.pkOrientation;
- float vecLen;
- float altRad, azmRad; /* in radians */
-
- /*
- * from the wintab spec:
- * orAzimuth Specifies the clockwise rotation of the
- * cursor about the z axis through a full circular range.
- *
- * orAltitude Specifies the angle with the x-y plane
- * through a signed, semicircular range. Positive values
- * specify an angle upward toward the positive z axis;
- * negative values specify an angle downward toward the negative z axis.
- *
- * wintab.h defines .orAltitude as a UINT but documents .orAltitude
- * as positive for upward angles and negative for downward angles.
- * WACOM uses negative altitude values to show that the pen is inverted;
- * therefore we cast .orAltitude as an (int) and then use the absolute value.
- */
-
- /* convert raw fixed point data to radians */
- altRad = (float)((fabs((float)ort.orAltitude) / (float)m_wintab.maxAltitude) * M_PI / 2.0);
- azmRad = (float)(((float)ort.orAzimuth / (float)m_wintab.maxAzimuth) * M_PI * 2.0);
-
- /* find length of the stylus' projected vector on the XY plane */
- vecLen = cos(altRad);
-
- /* from there calculate X and Y components based on azimuth */
- m_tabletData.Xtilt = sin(azmRad) * vecLen;
- m_tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
- }
- else {
- m_tabletData.Xtilt = 0.0f;
- m_tabletData.Ytilt = 0.0f;
- }
+ else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) {
+ if (m_wintab && m_wintab->devicesPresent()) {
+ return api == GHOST_kTabletWintab;
+ }
+ else {
+ return api == GHOST_kTabletWinPointer;
}
}
+ else {
+ return false;
+ }
}
-void GHOST_WindowWin32::bringTabletContextToFront()
+GHOST_TabletData GHOST_WindowWin32::getTabletData()
{
- if (!useTabletAPI(GHOST_kTabletWintab)) {
- return;
+ if (usingTabletAPI(GHOST_kTabletWintab)) {
+ return m_wintab ? m_wintab->getLastTabletData() : GHOST_TABLET_DATA_NONE;
}
-
- if (m_wintab.overlap && m_wintab.tablet) {
- m_wintab.overlap(m_wintab.tablet, TRUE);
+ else {
+ return m_lastPointerTabletData;
}
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index a13bd876667..f28ba266ed1 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -30,34 +30,18 @@
#include "GHOST_TaskbarWin32.h"
#include "GHOST_Window.h"
+#include "GHOST_Wintab.h"
#ifdef WITH_INPUT_IME
# include "GHOST_ImeWin32.h"
#endif
#include <vector>
-#include <wintab.h>
-// PACKETDATA and PACKETMODE modify structs in pktdef.h, so make sure they come first
-#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
-#define PACKETMODE PK_BUTTONS
-#include <pktdef.h>
-
class GHOST_SystemWin32;
class GHOST_DropTargetWin32;
-// typedefs for WinTab functions to allow dynamic loading
-typedef UINT(API *GHOST_WIN32_WTInfo)(UINT, UINT, LPVOID);
-typedef HCTX(API *GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL);
-typedef BOOL(API *GHOST_WIN32_WTClose)(HCTX);
-typedef BOOL(API *GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID);
-typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL);
-typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL);
-
// typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions
typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND);
-#ifndef USER_DEFAULT_SCREEN_DPI
-# define USER_DEFAULT_SCREEN_DPI 96
-#endif // USER_DEFAULT_SCREEN_DPI
struct GHOST_PointerInfoWin32 {
GHOST_TInt32 pointerId;
@@ -65,7 +49,6 @@ struct GHOST_PointerInfoWin32 {
GHOST_TButtonMask buttonMask;
POINT pixelLocation;
GHOST_TUns64 time;
-
GHOST_TabletData tabletData;
};
@@ -259,16 +242,11 @@ class GHOST_WindowWin32 : public GHOST_Window {
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
- const GHOST_TabletData &getTabletData()
- {
- return m_tabletData;
- }
-
/**
* Query whether given tablet API should be used.
* \param api: Tablet API to test.
*/
- bool useTabletAPI(GHOST_TTabletAPI api) const;
+ bool usingTabletAPI(GHOST_TTabletAPI api) const;
/**
* Translate WM_POINTER events into GHOST_PointerInfoWin32 structs.
@@ -281,10 +259,34 @@ class GHOST_WindowWin32 : public GHOST_Window {
WPARAM wParam,
LPARAM lParam);
- void processWin32TabletActivateEvent(WORD state);
- void processWin32TabletInitEvent();
- void processWin32TabletEvent(WPARAM wParam, LPARAM lParam);
- void bringTabletContextToFront();
+ /**
+ * Resets pointer pen tablet state.
+ */
+ void resetPointerPenInfo();
+
+ /**
+ * Retrieves pointer to Wintab if Wintab is the set Tablet API.
+ * \return Pointer to Wintab member.
+ */
+ GHOST_Wintab *getWintab() const;
+
+ /**
+ * Loads Wintab context for the window.
+ * \param enable: True if Wintab should be enabled after loading. Wintab should not be enabled if
+ * the window is minimized.
+ */
+ void loadWintab(bool enable);
+
+ /**
+ * Closes Wintab for the window.
+ */
+ void closeWintab();
+
+ /**
+ * Get the most recent Windows Pointer tablet data.
+ * \return Most recent pointer tablet data.
+ */
+ GHOST_TabletData getTabletData();
GHOST_TSuccess beginFullScreen() const
{
@@ -298,10 +300,10 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TUns16 getDPIHint() override;
- /** Whether a tablet stylus is being tracked. */
- bool m_tabletInRange;
+ /** True if the mouse is either over or captured by the window. */
+ bool m_mousePresent;
- /** if the window currently resizing */
+ /** True if the window currently resizing. */
bool m_inLiveResize;
#ifdef WITH_INPUT_IME
@@ -385,27 +387,11 @@ class GHOST_WindowWin32 : public GHOST_Window {
static const wchar_t *s_windowClassName;
static const int s_maxTitleLength;
- /** Tablet data for GHOST */
- GHOST_TabletData m_tabletData;
-
- /* Wintab API */
- struct {
- /** `WinTab.dll` handle. */
- HMODULE handle = NULL;
-
- /** API functions */
- GHOST_WIN32_WTInfo info;
- GHOST_WIN32_WTOpen open;
- GHOST_WIN32_WTClose close;
- GHOST_WIN32_WTPacket packet;
- GHOST_WIN32_WTEnable enable;
- GHOST_WIN32_WTOverlap overlap;
-
- /** Stores the Tablet context if detected Tablet features using `WinTab.dll` */
- HCTX tablet;
- LONG maxPressure;
- LONG maxAzimuth, maxAltitude;
- } m_wintab;
+ /** Pointer to Wintab manager if Wintab is loaded. */
+ GHOST_Wintab *m_wintab;
+
+ /** Most recent tablet data. */
+ GHOST_TabletData m_lastPointerTabletData;
GHOST_TWindowState m_normal_state;
diff --git a/intern/ghost/intern/GHOST_Wintab.cpp b/intern/ghost/intern/GHOST_Wintab.cpp
new file mode 100644
index 00000000000..cf0309b1521
--- /dev/null
+++ b/intern/ghost/intern/GHOST_Wintab.cpp
@@ -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 GHOST
+ */
+
+#define _USE_MATH_DEFINES
+
+#include "GHOST_Wintab.h"
+
+GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
+{
+ /* Load Wintab library if available. */
+
+ auto handle = unique_hmodule(::LoadLibrary("Wintab32.dll"), &::FreeLibrary);
+ if (!handle) {
+ return nullptr;
+ }
+
+ /* Get Wintab functions. */
+
+ auto info = (GHOST_WIN32_WTInfo)::GetProcAddress(handle.get(), "WTInfoA");
+ if (!info) {
+ return nullptr;
+ }
+
+ auto open = (GHOST_WIN32_WTOpen)::GetProcAddress(handle.get(), "WTOpenA");
+ if (!open) {
+ return nullptr;
+ }
+
+ auto get = (GHOST_WIN32_WTGet)::GetProcAddress(handle.get(), "WTGetA");
+ if (!get) {
+ return nullptr;
+ }
+
+ auto set = (GHOST_WIN32_WTSet)::GetProcAddress(handle.get(), "WTSetA");
+ if (!set) {
+ return nullptr;
+ }
+
+ auto close = (GHOST_WIN32_WTClose)::GetProcAddress(handle.get(), "WTClose");
+ if (!close) {
+ return nullptr;
+ }
+
+ auto packetsGet = (GHOST_WIN32_WTPacketsGet)::GetProcAddress(handle.get(), "WTPacketsGet");
+ if (!packetsGet) {
+ return nullptr;
+ }
+
+ auto queueSizeGet = (GHOST_WIN32_WTQueueSizeGet)::GetProcAddress(handle.get(), "WTQueueSizeGet");
+ if (!queueSizeGet) {
+ return nullptr;
+ }
+
+ auto queueSizeSet = (GHOST_WIN32_WTQueueSizeSet)::GetProcAddress(handle.get(), "WTQueueSizeSet");
+ if (!queueSizeSet) {
+ return nullptr;
+ }
+
+ auto enable = (GHOST_WIN32_WTEnable)::GetProcAddress(handle.get(), "WTEnable");
+ if (!enable) {
+ return nullptr;
+ }
+
+ auto overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(handle.get(), "WTOverlap");
+ if (!overlap) {
+ return nullptr;
+ }
+
+ /* Build Wintab context. */
+
+ LOGCONTEXT lc = {0};
+ if (!info(WTI_DEFSYSCTX, 0, &lc)) {
+ return nullptr;
+ }
+
+ Coord tablet, system;
+ extractCoordinates(lc, tablet, system);
+ modifyContext(lc);
+
+ /* The Wintab spec says we must open the context disabled if we are using cursor masks. */
+ auto hctx = unique_hctx(open(hwnd, &lc, FALSE), close);
+ if (!hctx) {
+ return nullptr;
+ }
+
+ /* Wintab provides no way to determine the maximum queue size aside from checking if attempts
+ * to change the queue size are successful. */
+ const int maxQueue = 500;
+ int queueSize = queueSizeGet(hctx.get());
+
+ while (queueSize < maxQueue) {
+ int testSize = min(queueSize + 16, maxQueue);
+ if (queueSizeSet(hctx.get(), testSize)) {
+ queueSize = testSize;
+ }
+ else {
+ /* From Windows Wintab Documentation for WTQueueSizeSet:
+ * "If the return value is zero, the context has no queue because the function deletes the
+ * original queue before attempting to create a new one. The application must continue
+ * calling the function with a smaller queue size until the function returns a non - zero
+ * value."
+ *
+ * In our case we start with a known valid queue size and in the event of failure roll
+ * back to the last valid queue size. The Wintab spec dates back to 16 bit Windows, thus
+ * assumes memory recently deallocated may not be available, which is no longer a practical
+ * concern. */
+ if (!queueSizeSet(hctx.get(), queueSize)) {
+ /* If a previously valid queue size is no longer valid, there is likely something wrong in
+ * the Wintab implementation and we should not use it. */
+ return nullptr;
+ }
+ break;
+ }
+ }
+
+ return new GHOST_Wintab(hwnd,
+ std::move(handle),
+ info,
+ get,
+ set,
+ packetsGet,
+ enable,
+ overlap,
+ std::move(hctx),
+ tablet,
+ system,
+ queueSize);
+}
+
+void GHOST_Wintab::modifyContext(LOGCONTEXT &lc)
+{
+ lc.lcPktData = PACKETDATA;
+ lc.lcPktMode = PACKETMODE;
+ lc.lcMoveMask = PACKETDATA;
+ lc.lcOptions |= CXO_CSRMESSAGES | CXO_MESSAGES;
+
+ /* Tablet scaling is handled manually because some drivers don't handle HIDPI or multi-display
+ * correctly; reset tablet scale factors to un-scaled tablet coordinates. */
+ lc.lcOutOrgX = lc.lcInOrgX;
+ lc.lcOutOrgY = lc.lcInOrgY;
+ lc.lcOutExtX = lc.lcInExtX;
+ lc.lcOutExtY = lc.lcInExtY;
+}
+
+void GHOST_Wintab::extractCoordinates(LOGCONTEXT &lc, Coord &tablet, Coord &system)
+{
+ tablet.x.org = lc.lcInOrgX;
+ tablet.x.ext = lc.lcInExtX;
+ tablet.y.org = lc.lcInOrgY;
+ tablet.y.ext = lc.lcInExtY;
+
+ system.x.org = lc.lcSysOrgX;
+ system.x.ext = lc.lcSysExtX;
+ system.y.org = lc.lcSysOrgY;
+ /* Wintab maps y origin to the tablet's bottom; invert y to match Windows y origin mapping to the
+ * screen top. */
+ system.y.ext = -lc.lcSysExtY;
+}
+
+GHOST_Wintab::GHOST_Wintab(HWND hwnd,
+ unique_hmodule handle,
+ GHOST_WIN32_WTInfo info,
+ GHOST_WIN32_WTGet get,
+ GHOST_WIN32_WTSet set,
+ GHOST_WIN32_WTPacketsGet packetsGet,
+ GHOST_WIN32_WTEnable enable,
+ GHOST_WIN32_WTOverlap overlap,
+ unique_hctx hctx,
+ Coord tablet,
+ Coord system,
+ int queueSize)
+ : m_handle{std::move(handle)},
+ m_fpInfo{info},
+ m_fpGet{get},
+ m_fpSet{set},
+ m_fpPacketsGet{packetsGet},
+ m_fpEnable{enable},
+ m_fpOverlap{overlap},
+ m_context{std::move(hctx)},
+ m_tabletCoord{tablet},
+ m_systemCoord{system},
+ m_pkts{queueSize}
+{
+ m_fpInfo(WTI_INTERFACE, IFC_NDEVICES, &m_numDevices);
+ updateCursorInfo();
+}
+
+void GHOST_Wintab::enable()
+{
+ m_fpEnable(m_context.get(), true);
+ m_enabled = true;
+}
+
+void GHOST_Wintab::disable()
+{
+ if (m_focused) {
+ loseFocus();
+ }
+ m_fpEnable(m_context.get(), false);
+ m_enabled = false;
+}
+
+void GHOST_Wintab::gainFocus()
+{
+ m_fpOverlap(m_context.get(), true);
+ m_focused = true;
+}
+
+void GHOST_Wintab::loseFocus()
+{
+ if (m_lastTabletData.Active != GHOST_kTabletModeNone) {
+ leaveRange();
+ }
+
+ /* Mouse mode of tablet or display layout may change when Wintab or Window is inactive. Don't
+ * trust for mouse movement until re-verified. */
+ m_coordTrusted = false;
+
+ m_fpOverlap(m_context.get(), false);
+ m_focused = false;
+}
+
+void GHOST_Wintab::leaveRange()
+{
+ /* Button state can't be tracked while out of range, reset it. */
+ m_buttons = 0;
+ /* Set to none to indicate tablet is inactive. */
+ m_lastTabletData = GHOST_TABLET_DATA_NONE;
+ /* Clear the packet queue. */
+ m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
+}
+
+void GHOST_Wintab::remapCoordinates()
+{
+ LOGCONTEXT lc = {0};
+
+ if (m_fpInfo(WTI_DEFSYSCTX, 0, &lc)) {
+ extractCoordinates(lc, m_tabletCoord, m_systemCoord);
+ modifyContext(lc);
+
+ m_fpSet(m_context.get(), &lc);
+ }
+}
+
+void GHOST_Wintab::updateCursorInfo()
+{
+ AXIS Pressure, Orientation[3];
+
+ BOOL pressureSupport = m_fpInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
+ m_maxPressure = pressureSupport ? Pressure.axMax : 0;
+
+ BOOL tiltSupport = m_fpInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
+ /* Check if tablet supports azimuth [0] and altitude [1], encoded in axResolution. */
+ if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) {
+ m_maxAzimuth = Orientation[0].axMax;
+ m_maxAltitude = Orientation[1].axMax;
+ }
+ else {
+ m_maxAzimuth = m_maxAltitude = 0;
+ }
+}
+
+void GHOST_Wintab::processInfoChange(LPARAM lParam)
+{
+ /* Update number of connected Wintab digitizers. */
+ if (LOWORD(lParam) == WTI_INTERFACE && HIWORD(lParam) == IFC_NDEVICES) {
+ m_fpInfo(WTI_INTERFACE, IFC_NDEVICES, &m_numDevices);
+ }
+}
+
+bool GHOST_Wintab::devicesPresent()
+{
+ return m_numDevices > 0;
+}
+
+GHOST_TabletData GHOST_Wintab::getLastTabletData()
+{
+ return m_lastTabletData;
+}
+
+void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
+{
+ const int numPackets = m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
+ outWintabInfo.resize(numPackets);
+ size_t outExtent = 0;
+
+ for (int i = 0; i < numPackets; i++) {
+ PACKET pkt = m_pkts[i];
+ GHOST_WintabInfoWin32 &out = outWintabInfo[i + outExtent];
+
+ out.tabletData = GHOST_TABLET_DATA_NONE;
+ /* % 3 for multiple devices ("DualTrack"). */
+ switch (pkt.pkCursor % 3) {
+ case 0:
+ /* Puck - processed as mouse. */
+ out.tabletData.Active = GHOST_kTabletModeNone;
+ break;
+ case 1:
+ out.tabletData.Active = GHOST_kTabletModeStylus;
+ break;
+ case 2:
+ out.tabletData.Active = GHOST_kTabletModeEraser;
+ break;
+ }
+
+ out.x = pkt.pkX;
+ out.y = pkt.pkY;
+
+ if (m_maxPressure > 0) {
+ out.tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
+ }
+
+ if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
+ ORIENTATION ort = pkt.pkOrientation;
+ float vecLen;
+ float altRad, azmRad; /* In radians. */
+
+ /*
+ * From the wintab spec:
+ * orAzimuth: Specifies the clockwise rotation of the cursor about the z axis through a
+ * full circular range.
+ * orAltitude: Specifies the angle with the x-y plane through a signed, semicircular range.
+ * Positive values specify an angle upward toward the positive z axis; negative values
+ * specify an angle downward toward the negative z axis.
+ *
+ * wintab.h defines orAltitude as a UINT but documents orAltitude as positive for upward
+ * angles and negative for downward angles. WACOM uses negative altitude values to show that
+ * the pen is inverted; therefore we cast orAltitude as an (int) and then use the absolute
+ * value.
+ */
+
+ /* Convert raw fixed point data to radians. */
+ altRad = (float)((fabs((float)ort.orAltitude) / (float)m_maxAltitude) * M_PI / 2.0);
+ azmRad = (float)(((float)ort.orAzimuth / (float)m_maxAzimuth) * M_PI * 2.0);
+
+ /* Find length of the stylus' projected vector on the XY plane. */
+ vecLen = cos(altRad);
+
+ /* From there calculate X and Y components based on azimuth. */
+ out.tabletData.Xtilt = sin(azmRad) * vecLen;
+ out.tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
+ }
+
+ out.time = pkt.pkTime;
+
+ /* Some Wintab libraries don't handle relative button input, so we track button presses
+ * manually. */
+ out.button = GHOST_kButtonMaskNone;
+ out.type = GHOST_kEventCursorMove;
+
+ DWORD buttonsChanged = m_buttons ^ pkt.pkButtons;
+ WORD buttonIndex = 0;
+ GHOST_WintabInfoWin32 buttonRef = out;
+ int buttons = 0;
+
+ while (buttonsChanged) {
+ if (buttonsChanged & 1) {
+ /* Find the index for the changed button from the button map. */
+ GHOST_TButtonMask button = mapWintabToGhostButton(pkt.pkCursor, buttonIndex);
+
+ if (button != GHOST_kButtonMaskNone) {
+ /* Extend output if multiple buttons are pressed. We don't extend input until we confirm
+ * a Wintab buttons maps to a system button. */
+ if (buttons > 0) {
+ outWintabInfo.resize(outWintabInfo.size() + 1);
+ outExtent++;
+ GHOST_WintabInfoWin32 &out = outWintabInfo[i + outExtent];
+ out = buttonRef;
+ }
+ buttons++;
+
+ out.button = button;
+ if (buttonsChanged & pkt.pkButtons) {
+ out.type = GHOST_kEventButtonDown;
+ }
+ else {
+ out.type = GHOST_kEventButtonUp;
+ }
+ }
+
+ m_buttons ^= 1 << buttonIndex;
+ }
+
+ buttonsChanged >>= 1;
+ buttonIndex++;
+ }
+ }
+
+ if (!outWintabInfo.empty()) {
+ m_lastTabletData = outWintabInfo.back().tabletData;
+ }
+}
+
+GHOST_TButtonMask GHOST_Wintab::mapWintabToGhostButton(UINT cursor, WORD physicalButton)
+{
+ const WORD numButtons = 32;
+ BYTE logicalButtons[numButtons] = {0};
+ BYTE systemButtons[numButtons] = {0};
+
+ if (!m_fpInfo(WTI_CURSORS + cursor, CSR_BUTTONMAP, &logicalButtons) ||
+ !m_fpInfo(WTI_CURSORS + cursor, CSR_SYSBTNMAP, &systemButtons)) {
+ return GHOST_kButtonMaskNone;
+ }
+
+ if (physicalButton >= numButtons) {
+ return GHOST_kButtonMaskNone;
+ }
+
+ BYTE lb = logicalButtons[physicalButton];
+
+ if (lb >= numButtons) {
+ return GHOST_kButtonMaskNone;
+ }
+
+ switch (systemButtons[lb]) {
+ case SBN_LCLICK:
+ return GHOST_kButtonMaskLeft;
+ case SBN_RCLICK:
+ return GHOST_kButtonMaskRight;
+ case SBN_MCLICK:
+ return GHOST_kButtonMaskMiddle;
+ default:
+ return GHOST_kButtonMaskNone;
+ }
+}
+
+void GHOST_Wintab::mapWintabToSysCoordinates(int x_in, int y_in, int &x_out, int &y_out)
+{
+ /* Maps from range [in.org, in.org + abs(in.ext)] to [out.org, out.org + abs(out.ext)], in
+ * reverse if in.ext and out.ext have differing sign. */
+ auto remap = [](int inPoint, Range in, Range out) -> int {
+ int absInExt = abs(in.ext);
+ int absOutExt = abs(out.ext);
+
+ /* Translate input from range [in.org, in.org + absInExt] to [0, absInExt] */
+ int inMagnitude = inPoint - in.org;
+
+ /* If signs of extents differ, reverse input over range. */
+ if ((in.ext < 0) != (out.ext < 0)) {
+ inMagnitude = absInExt - inMagnitude;
+ }
+
+ /* Scale from [0, absInExt] to [0, absOutExt]. */
+ int outMagnitude = inMagnitude * absOutExt / absInExt;
+
+ /* Translate from range [0, absOutExt] to [out.org, out.org + absOutExt]. */
+ int outPoint = outMagnitude + out.org;
+
+ return outPoint;
+ };
+
+ x_out = remap(x_in, m_tabletCoord.x, m_systemCoord.x);
+ y_out = remap(y_in, m_tabletCoord.y, m_systemCoord.y);
+}
+
+bool GHOST_Wintab::trustCoordinates()
+{
+ return m_coordTrusted;
+}
+
+bool GHOST_Wintab::testCoordinates(int sysX, int sysY, int wtX, int wtY)
+{
+ mapWintabToSysCoordinates(wtX, wtY, wtX, wtY);
+
+ /* Allow off by one pixel tolerance in case of rounding error. */
+ if (abs(sysX - wtX) <= 1 && abs(sysY - wtY) <= 1) {
+ m_coordTrusted = true;
+ return true;
+ }
+ else {
+ m_coordTrusted = false;
+ return false;
+ }
+}
diff --git a/intern/ghost/intern/GHOST_Wintab.h b/intern/ghost/intern/GHOST_Wintab.h
new file mode 100644
index 00000000000..75017aa67d9
--- /dev/null
+++ b/intern/ghost/intern/GHOST_Wintab.h
@@ -0,0 +1,250 @@
+/*
+ * 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 GHOST
+ * Declaration of GHOST_WintabWin32 class.
+ */
+
+/* Wacom's Wintab documentation is periodically offline, moved, and increasingly hidden away. You
+ * can find a (painstakingly) archived copy of the documentation at
+ * https://web.archive.org/web/20201122230125/https://developer-docs-legacy.wacom.com/display/DevDocs/Windows+Wintab+Documentation
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <wtypes.h>
+
+#include "GHOST_Types.h"
+
+#include <wintab.h>
+/* PACKETDATA and PACKETMODE modify structs in pktdef.h, so make sure they come first. */
+#define PACKETDATA \
+ (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_X | PK_Y | PK_TIME)
+#define PACKETMODE 0
+#include <pktdef.h>
+
+/* Typedefs for Wintab functions to allow dynamic loading. */
+typedef UINT(API *GHOST_WIN32_WTInfo)(UINT, UINT, LPVOID);
+typedef BOOL(API *GHOST_WIN32_WTGet)(HCTX, LPLOGCONTEXTA);
+typedef BOOL(API *GHOST_WIN32_WTSet)(HCTX, LPLOGCONTEXTA);
+typedef HCTX(API *GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL);
+typedef BOOL(API *GHOST_WIN32_WTClose)(HCTX);
+typedef int(API *GHOST_WIN32_WTPacketsGet)(HCTX, int, LPVOID);
+typedef int(API *GHOST_WIN32_WTQueueSizeGet)(HCTX);
+typedef BOOL(API *GHOST_WIN32_WTQueueSizeSet)(HCTX, int);
+typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL);
+typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL);
+
+/* Typedefs for Wintab and Windows resource management. */
+typedef std::unique_ptr<std::remove_pointer_t<HMODULE>, decltype(&::FreeLibrary)> unique_hmodule;
+typedef std::unique_ptr<std::remove_pointer_t<HCTX>, GHOST_WIN32_WTClose> unique_hctx;
+
+struct GHOST_WintabInfoWin32 {
+ GHOST_TInt32 x, y;
+ GHOST_TEventType type;
+ GHOST_TButtonMask button;
+ GHOST_TUns64 time;
+ GHOST_TabletData tabletData;
+};
+
+class GHOST_Wintab {
+ public:
+ /**
+ * Loads Wintab if available.
+ * \param hwnd: Window to attach Wintab context to.
+ */
+ static GHOST_Wintab *loadWintab(HWND hwnd);
+
+ /**
+ * Enables Wintab context.
+ */
+ void enable();
+
+ /**
+ * Disables the Wintab context and unwinds Wintab state.
+ */
+ void disable();
+
+ /**
+ * Brings Wintab context to the top of the overlap order.
+ */
+ void gainFocus();
+
+ /**
+ * Puts Wintab context at bottom of overlap order and unwinds Wintab state.
+ */
+ void loseFocus();
+
+ /**
+ * Clean up when Wintab leaves tracking range.
+ */
+ void leaveRange();
+
+ /**
+ * Handle Wintab coordinate changes when DisplayChange events occur.
+ */
+ void remapCoordinates();
+
+ /**
+ * Maps Wintab to Win32 display coordinates.
+ * \param x_in: The tablet x coordinate.
+ * \param y_in: The tablet y coordinate.
+ * \param x_out: Output for the Win32 mapped x coordinate.
+ * \param y_out: Output for the Win32 mapped y coordinate.
+ */
+ void mapWintabToSysCoordinates(int x_in, int y_in, int &x_out, int &y_out);
+
+ /**
+ * Updates cached Wintab properties for current cursor.
+ */
+ void updateCursorInfo();
+
+ /**
+ * Handle Wintab info changes such as change in number of connected tablets.
+ * \param lParam: LPARAM of the event.
+ */
+ void processInfoChange(LPARAM lParam);
+
+ /**
+ * Whether Wintab devices are present.
+ * \return True if Wintab devices are present.
+ */
+ bool devicesPresent();
+
+ /**
+ * Translate Wintab packets into GHOST_WintabInfoWin32 structs.
+ * \param outWintabInfo: Storage to return resulting GHOST_WintabInfoWin32 data.
+ */
+ void getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
+
+ /**
+ * Whether Wintab coordinates should be trusted.
+ * \return True if Wintab coordinates should be trusted.
+ */
+ bool trustCoordinates();
+
+ /**
+ * Tests whether Wintab coordinates can be trusted by comparing Win32 and Wintab reported cursor
+ * position.
+ * \param sysX: System cursor x position.
+ * \param sysY: System cursor y position.
+ * \param wtX: Wintab cursor x position.
+ * \param wtY: Wintab cursor y position.
+ * \return True if Win32 and Wintab cursor positions match within tolerance.
+ *
+ * Note: Only test coordinates on button press, not release. This prevents issues when async
+ * mismatch causes mouse movement to replay and snap back, which is only an issue while drawing.
+ */
+ bool testCoordinates(int sysX, int sysY, int wtX, int wtY);
+
+ /**
+ * Retrieve the most recent tablet data, or none if pen is not in range.
+ * \return Most recent tablet data, or none if pen is not in range.
+ */
+ GHOST_TabletData getLastTabletData();
+
+ private:
+ /** Wintab DLL handle. */
+ unique_hmodule m_handle;
+ /** Wintab API functions. */
+ GHOST_WIN32_WTInfo m_fpInfo = nullptr;
+ GHOST_WIN32_WTGet m_fpGet = nullptr;
+ GHOST_WIN32_WTSet m_fpSet = nullptr;
+ GHOST_WIN32_WTPacketsGet m_fpPacketsGet = nullptr;
+ GHOST_WIN32_WTEnable m_fpEnable = nullptr;
+ GHOST_WIN32_WTOverlap m_fpOverlap = nullptr;
+
+ /** Stores the Wintab tablet context. */
+ unique_hctx m_context;
+ /** Whether the context is enabled. */
+ bool m_enabled = false;
+ /** Whether the context has focus and is at the top of overlap order. */
+ bool m_focused = false;
+
+ /** Pressed button map. */
+ GHOST_TUns8 m_buttons = 0;
+
+ /** Range of a coordinate space. */
+ struct Range {
+ /** Origin of range. */
+ int org = 0;
+ /** Extent of range. */
+ int ext = 1;
+ };
+
+ /** 2D Coordinate space. */
+ struct Coord {
+ /** Range of x. */
+ Range x = {};
+ /** Range of y. */
+ Range y = {};
+ };
+ /** Whether Wintab coordinates are trusted. */
+ bool m_coordTrusted = false;
+ /** Tablet input range. */
+ Coord m_tabletCoord = {};
+ /** System output range. */
+ Coord m_systemCoord = {};
+
+ int m_maxPressure = 0;
+ int m_maxAzimuth = 0;
+ int m_maxAltitude = 0;
+
+ /** Number of connected Wintab devices. */
+ UINT m_numDevices = 0;
+ /** Reusable buffer to read in Wintab packets. */
+ std::vector<PACKET> m_pkts;
+ /** Most recently received tablet data, or none if pen is not in range. */
+ GHOST_TabletData m_lastTabletData = GHOST_TABLET_DATA_NONE;
+
+ GHOST_Wintab(HWND hwnd,
+ unique_hmodule handle,
+ GHOST_WIN32_WTInfo info,
+ GHOST_WIN32_WTGet get,
+ GHOST_WIN32_WTSet set,
+ GHOST_WIN32_WTPacketsGet packetsGet,
+ GHOST_WIN32_WTEnable enable,
+ GHOST_WIN32_WTOverlap overlap,
+ unique_hctx hctx,
+ Coord tablet,
+ Coord system,
+ int queueSize);
+
+ /**
+ * Convert Wintab system mapped (mouse) buttons into Ghost button mask.
+ * \param cursor: The Wintab cursor associated to the button.
+ * \param physicalButton: The physical button ID to inspect.
+ * \return The system mapped button.
+ */
+ GHOST_TButtonMask mapWintabToGhostButton(UINT cursor, WORD physicalButton);
+
+ /**
+ * Applies common modifications to Wintab context.
+ * \param lc: Wintab context to modify.
+ */
+ static void modifyContext(LOGCONTEXT &lc);
+
+ /**
+ * Extracts tablet and system coordinates from Wintab context.
+ * \param lc: Wintab context to extract coordinates from.
+ * \param tablet: Tablet coordinates.
+ * \param system: System coordinates.
+ */
+ static void extractCoordinates(LOGCONTEXT &lc, Coord &tablet, Coord &system);
+};
diff --git a/intern/ghost/intern/GHOST_XrAction.cpp b/intern/ghost/intern/GHOST_XrAction.cpp
index 172ac40c84f..b10e001df47 100644
--- a/intern/ghost/intern/GHOST_XrAction.cpp
+++ b/intern/ghost/intern/GHOST_XrAction.cpp
@@ -392,9 +392,10 @@ GHOST_XrActionSet::GHOST_XrActionSet(XrInstance instance, const GHOST_XrActionSe
{
XrActionSetCreateInfo action_set_info{XR_TYPE_ACTION_SET_CREATE_INFO};
strcpy(action_set_info.actionSetName, info.name);
- strcpy(action_set_info.localizedActionSetName,
- info.name); /* Just use same name for localized. This can be changed in the future if
- necessary. */
+
+ /* Just use same name for localized. This can be changed in the future if necessary. */
+ strcpy(action_set_info.localizedActionSetName, info.name);
+
action_set_info.priority = 0; /* Use same (default) priority for all action sets. */
CHECK_XR(xrCreateActionSet(instance, &action_set_info, &m_action_set),
diff --git a/intern/ghost/intern/GHOST_XrContext.cpp b/intern/ghost/intern/GHOST_XrContext.cpp
index daad0b8190a..f057e679d56 100644
--- a/intern/ghost/intern/GHOST_XrContext.cpp
+++ b/intern/ghost/intern/GHOST_XrContext.cpp
@@ -420,6 +420,11 @@ void GHOST_XrContext::getExtensionsToEnable(
r_ext_names.push_back(gpu_binding);
}
+#if defined(WITH_GL_EGL)
+ assert(openxr_extension_is_available(m_oxr->extensions, XR_MNDX_EGL_ENABLE_EXTENSION_NAME));
+ r_ext_names.push_back(XR_MNDX_EGL_ENABLE_EXTENSION_NAME);
+#endif
+
for (const std::string_view &ext : try_ext) {
if (openxr_extension_is_available(m_oxr->extensions, ext)) {
r_ext_names.push_back(ext.data());
diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
index 30a2a238ccd..aeaa6e6b9e0 100644
--- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
+++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
@@ -22,7 +22,9 @@
#include <list>
#include <sstream>
-#if defined(WITH_GHOST_X11)
+#if defined(WITH_GL_EGL)
+# include "GHOST_ContextEGL.h"
+#elif defined(WITH_GHOST_X11)
# include "GHOST_ContextGLX.h"
#elif defined(WIN32)
# include "GHOST_ContextD3D.h"
@@ -66,7 +68,9 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
XrSystemId system_id,
std::string *r_requirement_info) const override
{
-#if defined(WITH_GHOST_X11)
+#if defined(WITH_GL_EGL)
+ GHOST_ContextEGL &ctx_gl = static_cast<GHOST_ContextEGL &>(ghost_ctx);
+#elif defined(WITH_GHOST_X11)
GHOST_ContextGLX &ctx_gl = static_cast<GHOST_ContextGLX &>(ghost_ctx);
#else
GHOST_ContextWGL &ctx_gl = static_cast<GHOST_ContextWGL &>(ghost_ctx);
@@ -106,6 +110,15 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
void initFromGhostContext(GHOST_Context &ghost_ctx) override
{
#if defined(WITH_GHOST_X11)
+# if defined(WITH_GL_EGL)
+ GHOST_ContextEGL &ctx_egl = static_cast<GHOST_ContextEGL &>(ghost_ctx);
+
+ oxr_binding.egl.type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX;
+ oxr_binding.egl.getProcAddress = eglGetProcAddress;
+ oxr_binding.egl.display = ctx_egl.getDisplay();
+ oxr_binding.egl.config = ctx_egl.getConfig();
+ oxr_binding.egl.context = ctx_egl.getContext();
+# else
GHOST_ContextGLX &ctx_glx = static_cast<GHOST_ContextGLX &>(ghost_ctx);
XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx.m_display, ctx_glx.m_fbconfig);
@@ -117,6 +130,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
oxr_binding.glx.visualid = visual_info->visualid;
XFree(visual_info);
+# endif
#elif defined(WIN32)
GHOST_ContextWGL &ctx_wgl = static_cast<GHOST_ContextWGL &>(ghost_ctx);
diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h
index d09c78e1ea7..a2d3cf2e385 100644
--- a/intern/ghost/intern/GHOST_XrSession.h
+++ b/intern/ghost/intern/GHOST_XrSession.h
@@ -74,10 +74,11 @@ class GHOST_XrSession {
const GHOST_XrActionProfileInfo *infos);
bool attachActionSets();
- /** Action functions to be called post-session start. */
- bool syncActions(
- const char *action_set_name = nullptr); /* If action_set_name is nullptr, all attached
- * action sets will be synced. */
+ /**
+ * Action functions to be called post-session start.
+ * \param action_set_name: When `nullptr`, all attached action sets will be synced.
+ */
+ bool syncActions(const char *action_set_name = nullptr);
bool applyHapticAction(const char *action_set_name,
const char *action_name,
const GHOST_TInt64 &duration,
diff --git a/intern/ghost/intern/GHOST_Xr_openxr_includes.h b/intern/ghost/intern/GHOST_Xr_openxr_includes.h
index d1deaeb0d1a..d6d7cad866c 100644
--- a/intern/ghost/intern/GHOST_Xr_openxr_includes.h
+++ b/intern/ghost/intern/GHOST_Xr_openxr_includes.h
@@ -42,7 +42,13 @@
# include <d3d12.h>
#endif
#ifdef WITH_GHOST_X11
-# include <GL/glxew.h>
+# ifdef WITH_GL_EGL
+/* TODO: Why do we have to create this typedef manually? */
+typedef void (*(*PFNEGLGETPROCADDRESSPROC)(const char *procname))(void);
+# include <GL/eglew.h>
+# else
+# include <GL/glxew.h>
+# endif
#endif
#include <openxr/openxr.h>
diff --git a/intern/iksolver/intern/IK_QJacobianSolver.cpp b/intern/iksolver/intern/IK_QJacobianSolver.cpp
index 6c2c0bacf48..b8ad0b2c09c 100644
--- a/intern/iksolver/intern/IK_QJacobianSolver.cpp
+++ b/intern/iksolver/intern/IK_QJacobianSolver.cpp
@@ -89,7 +89,7 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *> &tasks)
if (num_dof == 0)
return false;
- // compute task id's and assing weights to task
+ // compute task ids and assign weights to task
int primary_size = 0, primary = 0;
int secondary_size = 0, secondary = 0;
double primary_weight = 0.0, secondary_weight = 0.0;
@@ -237,7 +237,7 @@ void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTa
bool IK_QJacobianSolver::UpdateAngles(double &norm)
{
- // assing each segment a unique id for the jacobian
+ // assign each segment a unique id for the jacobian
std::vector<IK_QSegment *>::iterator seg;
IK_QSegment *qseg, *minseg = NULL;
double minabsdelta = 1e10, absdelta;
diff --git a/intern/libmv/libmv/base/scoped_ptr.h b/intern/libmv/libmv/base/scoped_ptr.h
index 9bfcfe1d615..45b5722034c 100644
--- a/intern/libmv/libmv/base/scoped_ptr.h
+++ b/intern/libmv/libmv/base/scoped_ptr.h
@@ -77,7 +77,7 @@ class scoped_array {
void reset(T* new_array) {
if (sizeof(T)) {
- delete array_;
+ delete[] array_;
}
array_ = new_array;
}
diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt
index d2336692d22..0b46ae471d2 100644
--- a/intern/opencolorio/CMakeLists.txt
+++ b/intern/opencolorio/CMakeLists.txt
@@ -48,6 +48,7 @@ if(WITH_OPENCOLORIO)
)
add_definitions(${GL_DEFINITIONS})
+ add_definitions(${OPENCOLORIO_DEFINITIONS})
list(APPEND INC_SYS
${OPENCOLORIO_INCLUDE_DIRS}
@@ -67,9 +68,6 @@ if(WITH_OPENCOLORIO)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
)
- add_definitions(
- -DOpenColorIO_STATIC
- )
list(APPEND LIB
${BOOST_LIBRARIES}
)
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 5ab29b1331d2103dae634b987f121c4599459d7
+Subproject ab283053ab455f76f5620b59b823e73bd9f601c
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject cdabac54c4fe7c6f8df125814442762aa539172
+Subproject ec07ed4c2e0495bea7fbe0b546d25e35211506a
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 239dd1cf79b..73b978d7d2d 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -358,7 +358,8 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
except Exception as ex:
# if the addon doesn't exist, don't print full traceback
if type(ex) is ImportError and ex.name == module_name:
- print("addon not found:", repr(module_name))
+ print("addon not loaded:", repr(module_name))
+ print("cause:", str(ex))
else:
handle_error(ex)
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index b17c9eeebc5..f63b6990cdd 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -1572,7 +1572,7 @@ class I18n:
if not os.path.isfile(dst):
print("WARNING: trying to write as python code into {}, which is not a file! Aborting.".format(dst))
return
- prev, txt, nxt, has_trans = self._parser_check_file(dst)
+ prev, txt, nxt, _has_trans = self._parser_check_file(dst)
if prev is None and nxt is None:
print("WARNING: Looks like given python file {} has no auto-generated translations yet, will be added "
"at the end of the file, you can move that section later if needed...".format(dst))
diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py
index 76dd8a740c5..d3750d5e9a4 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_cli.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py
@@ -71,7 +71,7 @@ def rtl_process_po(args, settings):
po.write(kind="PO", dest=args.dst)
-def language_menu(args, settings):
+def language_menu(_args, settings):
# 'DEFAULT' and en_US are always valid, fully-translated "languages"!
stats = {"DEFAULT": 1.0, "en_US": 1.0}
diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
index 8da1417c468..4b874efa2da 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
@@ -84,10 +84,10 @@ def protect_format_seq(msg):
# LRM = "\u200E"
# RLM = "\u200F"
LRE = "\u202A"
- RLE = "\u202B"
+# RLE = "\u202B"
PDF = "\u202C"
LRO = "\u202D"
- RLO = "\u202E"
+# RLO = "\u202E"
# uctrl = {LRE, RLE, PDF, LRO, RLO}
# Most likely incomplete, but seems to cover current needs.
format_codes = set("tslfd")
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index 0868b772a2b..dd19bb8f975 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -156,10 +156,9 @@ def bake_action_iter(
# Note: BBONE_PROPS is a list so we can preserve the ordering
BBONE_PROPS = [
'bbone_curveinx', 'bbone_curveoutx',
- 'bbone_curveiny', 'bbone_curveouty',
+ 'bbone_curveinz', 'bbone_curveoutz',
'bbone_rollin', 'bbone_rollout',
- 'bbone_scaleinx', 'bbone_scaleoutx',
- 'bbone_scaleiny', 'bbone_scaleouty',
+ 'bbone_scalein', 'bbone_scaleout',
'bbone_easein', 'bbone_easeout'
]
diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index b7a15bbbc19..de0b1435803 100644
--- a/release/scripts/modules/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -240,7 +240,7 @@ def RKS_GEN_custom_props(_ksi, _context, ks, data):
prop_path = '["%s"]' % bpy.utils.escape_identifier(cprop_name)
try:
rna_property = data.path_resolve(prop_path, False)
- except ValueError as ex:
+ except ValueError:
# This happens when a custom property is set to None. In that case it cannot
# be converted to an FCurve-compatible value, so we can't keyframe it anyway.
continue
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index 365d6c0087f..b42539ac44a 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -271,7 +271,7 @@ def draw_filtered(display_keymaps, filter_type, filter_text, layout):
# keymap items must match against all.
kmi_test_type = []
- # initialize? - so if a if a kmi has a MOD assigned it wont show up.
+ # initialize? - so if a kmi has a MOD assigned it won't show up.
# for kv in key_mod.values():
# kmi_test_dict[kv] = {False}
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index 552f7eeb4f3..57fcd6f9752 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -15,16 +15,21 @@ if language == 'DEFAULT':
language = os.getenv('LANG', '').split('.')[0]
LANG = {
+"ar_EG": "ar",
"de_DE": "de",
-"ru_RU": "ru",
-"uk_UA": "uk",
"es": "es",
+"fi_FI": "fi",
"fr_FR": "fr",
+"id_ID": "id",
"it_IT": "it",
"ja_JP": "ja",
"ko_KR": "ko",
"pt_PT": "pt",
"pt_BR": "pt",
+"ru_RU": "ru",
+"sk_SK": "sk",
+"sr_RS": "sr",
+"uk_UA": "uk",
"vi_VN": "vi",
"zh_CN": "zh-hans",
"zh_TW": "zh-hant",
@@ -58,6 +63,7 @@ url_manual_mapping = (
("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"),
("bpy.types.fluiddomainsettings.vector_scale_with_magnitude*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-scale-with-magnitude"),
+ ("bpy.types.movietrackingstabilization.use_2d_stabilization*", "movie_clip/tracking/clip/sidebar/stabilization/panel.html#bpy-types-movietrackingstabilization-use-2d-stabilization"),
("bpy.types.spacespreadsheet.display_context_path_collapsed*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-display-context-path-collapsed"),
("bpy.types.fluiddomainsettings.use_collision_border_front*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-front"),
("bpy.types.fluiddomainsettings.use_collision_border_right*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-right"),
@@ -169,6 +175,7 @@ url_manual_mapping = (
("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/parameter_editor/line_style/modifiers/thickness/calligraphy.html#bpy-types-linestylethicknessmodifier-calligraphy"),
("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"),
("bpy.types.rigidbodyconstraint.breaking_threshold*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-breaking-threshold"),
+ ("bpy.types.spaceclipeditor.use_manual_calibration*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-manual-calibration"),
("bpy.types.spacedopesheeteditor.show_pose_markers*", "animation/markers.html#bpy-types-spacedopesheeteditor-show-pose-markers"),
("bpy.types.spaceoutliner.use_filter_object_camera*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-camera"),
("bpy.types.spaceoutliner.use_filter_object_others*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-others"),
@@ -180,6 +187,7 @@ url_manual_mapping = (
("bpy.types.view3doverlay.sculpt_mode_mask_opacity*", "sculpt_paint/sculpting/editing/mask.html#bpy-types-view3doverlay-sculpt-mode-mask-opacity"),
("bpy.ops.outliner.collection_indirect_only_clear*", "render/layers/introduction.html#bpy-ops-outliner-collection-indirect-only-clear"),
("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-max-subdivisions"),
+ ("bpy.types.editbone.bbone_handle_use_scale_start*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-use-scale-start"),
("bpy.types.fluiddomainsettings.cache_data_format*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-data-format"),
("bpy.types.fluiddomainsettings.cache_frame_start*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-frame-start"),
("bpy.types.fluiddomainsettings.cache_mesh_format*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-mesh-format"),
@@ -200,6 +208,7 @@ url_manual_mapping = (
("bpy.types.materialgpencilstyle.use_fill_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-fill-holdout"),
("bpy.types.particlesettings.use_parent_particles*", "physics/particles/emitter/render.html#bpy-types-particlesettings-use-parent-particles"),
("bpy.types.rigidbodyconstraint.solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-solver-iterations"),
+ ("bpy.types.spaceclipeditor.use_grayscale_preview*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-grayscale-preview"),
("bpy.types.spaceoutliner.use_filter_lib_override*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-lib-override"),
("bpy.types.spaceoutliner.use_filter_object_empty*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-empty"),
("bpy.types.spaceoutliner.use_filter_object_light*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-light"),
@@ -213,11 +222,13 @@ url_manual_mapping = (
("bpy.ops.armature.rigify_apply_selection_colors*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-apply-selection-colors"),
("bpy.types.brushgpencilsettings.fill_layer_mode*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-layer-mode"),
("bpy.types.cyclesrendersettings.use_camera_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-camera-cull"),
+ ("bpy.types.editbone.bbone_handle_use_ease_start*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-use-ease-start"),
("bpy.types.fluiddomainsettings.color_ramp_field*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-color-ramp-field"),
("bpy.types.fluiddomainsettings.guide_vel_factor*", "physics/fluid/type/domain/guides.html#bpy-types-fluiddomainsettings-guide-vel-factor"),
("bpy.types.fluideffectorsettings.use_plane_init*", "physics/fluid/type/effector.html#bpy-types-fluideffectorsettings-use-plane-init"),
("bpy.types.greasepencil.curve_edit_corner_angle*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-corner-angle"),
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
+ ("bpy.types.movieclipuser.use_render_undistorted*", "editors/clip/display/clip_display.html#bpy-types-movieclipuser-use-render-undistorted"),
("bpy.types.movietrackingcamera.distortion_model*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-distortion-model"),
("bpy.types.rendersettings.resolution_percentage*", "render/output/properties/dimensions.html#bpy-types-rendersettings-resolution-percentage"),
("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
@@ -236,6 +247,7 @@ url_manual_mapping = (
("bpy.types.brushgpencilsettings.fill_threshold*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-threshold"),
("bpy.types.clothsettings.vertex_group_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-pressure"),
("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-displacement"),
+ ("bpy.types.editbone.bbone_handle_use_scale_end*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-use-scale-end"),
("bpy.types.fluiddomainsettings.adapt_threshold*", "physics/fluid/type/domain/gas/adaptive_domain.html#bpy-types-fluiddomainsettings-adapt-threshold"),
("bpy.types.fluiddomainsettings.cache_directory*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-directory"),
("bpy.types.fluiddomainsettings.cache_frame_end*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-frame-end"),
@@ -272,6 +284,8 @@ url_manual_mapping = (
("bpy.types.clothsettings.internal_compression*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-compression"),
("bpy.types.cyclesrendersettings.dicing_camera*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-dicing-camera"),
("bpy.types.cyclesrendersettings.texture_limit*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-texture-limit"),
+ ("bpy.types.editbone.bbone_custom_handle_start*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-custom-handle-start"),
+ ("bpy.types.editbone.bbone_handle_use_ease_end*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-use-ease-end"),
("bpy.types.fluiddomainsettings.additional_res*", "physics/fluid/type/domain/gas/adaptive_domain.html#bpy-types-fluiddomainsettings-additional-res"),
("bpy.types.fluiddomainsettings.dissolve_speed*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-dissolve-speed"),
("bpy.types.fluiddomainsettings.effector_group*", "physics/fluid/type/domain/collections.html#bpy-types-fluiddomainsettings-effector-group"),
@@ -294,6 +308,7 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_sampling*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/sampling.html#bpy-types-linestylegeometrymodifier-sampling"),
("bpy.types.nodesocketinterface*.default_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-default-value"),
("bpy.types.rendersettings.use_persistent_data*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-use-persistent-data"),
+ ("bpy.types.spaceclipeditor.show_green_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-green-channel"),
("bpy.types.spaceoutliner.show_restrict_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-restrict-column"),
("bpy.types.spacespreadsheet.object_eval_state*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-object-eval-state"),
("bpy.types.toolsettings.transform_pivot_point*", "editors/3dview/controls/pivot_point/index.html#bpy-types-toolsettings-transform-pivot-point"),
@@ -314,6 +329,7 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.velocity_factor*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-velocity-factor"),
("bpy.types.fluidflowsettings.velocity_normal*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-velocity-normal"),
("bpy.types.geometrynodealignrotationtovector*", "modeling/geometry_nodes/point/align_rotation_to_vector.html#bpy-types-geometrynodealignrotationtovector"),
+ ("bpy.types.geometrynodeattributevectorrotate*", "modeling/geometry_nodes/attribute/attribute_vector_rotate.html#bpy-types-geometrynodeattributevectorrotate"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"),
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-crease-override"),
@@ -322,6 +338,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.use_file_extension*", "render/output/properties/output.html#bpy-types-rendersettings-use-file-extension"),
("bpy.types.sculpt.constant_detail_resolution*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-sculpt-constant-detail-resolution"),
("bpy.types.spaceclipeditor.annotation_source*", "movie_clip/tracking/clip/sidebar/annotation.html#bpy-types-spaceclipeditor-annotation-source"),
+ ("bpy.types.spaceclipeditor.show_blue_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-blue-channel"),
("bpy.types.spaceoutliner.use_filter_children*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-children"),
("bpy.types.spaceoutliner.use_filter_complete*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-complete"),
("bpy.types.spacesequenceeditor.show_metadata*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show-metadata"),
@@ -340,6 +357,8 @@ url_manual_mapping = (
("bpy.types.curve.bevel_factor_mapping_start*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-factor-mapping-start"),
("bpy.types.cyclesobjectsettings.dicing_rate*", "render/cycles/object_settings/adaptive_subdiv.html#bpy-types-cyclesobjectsettings-dicing-rate"),
("bpy.types.cyclesrendersettings.use_fast_gi*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-use-fast-gi"),
+ ("bpy.types.editbone.bbone_custom_handle_end*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-custom-handle-end"),
+ ("bpy.types.editbone.bbone_handle_type_start*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-type-start"),
("bpy.types.fluiddomainsettings.adapt_margin*", "physics/fluid/type/domain/gas/adaptive_domain.html#bpy-types-fluiddomainsettings-adapt-margin"),
("bpy.types.fluiddomainsettings.burning_rate*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-burning-rate"),
("bpy.types.fluiddomainsettings.guide_parent*", "physics/fluid/type/domain/guides.html#bpy-types-fluiddomainsettings-guide-parent"),
@@ -360,6 +379,8 @@ url_manual_mapping = (
("bpy.types.posebone.use_ik_rotation_control*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-use-ik-rotation-control"),
("bpy.types.rendersettings.use_bake_multires*", "render/cycles/baking.html#bpy-types-rendersettings-use-bake-multires"),
("bpy.types.scenegpencil.antialias_threshold*", "render/cycles/render_settings/grease_pencil.html#bpy-types-scenegpencil-antialias-threshold"),
+ ("bpy.types.spaceclipeditor.show_red_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-red-channel"),
+ ("bpy.types.spaceclipeditor.use_mute_footage*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-mute-footage"),
("bpy.types.spacesequenceeditor.overlay_type*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-overlay-type"),
("bpy.types.spacesequenceeditor.show_fcurves*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-fcurves"),
("bpy.types.spaceuveditor.sticky_select_mode*", "editors/uv/selecting.html#bpy-types-spaceuveditor-sticky-select-mode"),
@@ -436,6 +457,8 @@ url_manual_mapping = (
("bpy.types.colormanagedviewsettings.gamma*", "render/color_management.html#bpy-types-colormanagedviewsettings-gamma"),
("bpy.types.compositornodeplanetrackdeform*", "compositing/types/distort/plane_track_deform.html#bpy-types-compositornodeplanetrackdeform"),
("bpy.types.curve.bevel_factor_mapping_end*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-factor-mapping-end"),
+ ("bpy.types.editbone.bbone_handle_type_end*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-type-end"),
+ ("bpy.types.editbone.use_endroll_as_inroll*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-use-endroll-as-inroll"),
("bpy.types.fluiddomainsettings.cache_type*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-type"),
("bpy.types.fluiddomainsettings.flip_ratio*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-flip-ratio"),
("bpy.types.fluiddomainsettings.guide_beta*", "physics/fluid/type/domain/guides.html#bpy-types-fluiddomainsettings-guide-beta"),
@@ -448,6 +471,7 @@ url_manual_mapping = (
("bpy.types.geometrynodeattributecolorramp*", "modeling/geometry_nodes/attribute/attribute_color_ramp.html#bpy-types-geometrynodeattributecolorramp"),
("bpy.types.geometrynodeattributeproximity*", "modeling/geometry_nodes/attribute/attribute_proximity.html#bpy-types-geometrynodeattributeproximity"),
("bpy.types.geometrynodeattributerandomize*", "modeling/geometry_nodes/attribute/attribute_randomize.html#bpy-types-geometrynodeattributerandomize"),
+ ("bpy.types.geometrynodeseparatecomponents*", "modeling/geometry_nodes/geometry/separate_components.html#bpy-types-geometrynodeseparatecomponents"),
("bpy.types.geometrynodesubdivisionsurface*", "modeling/geometry_nodes/mesh/subdivision_surface.html#bpy-types-geometrynodesubdivisionsurface"),
("bpy.types.imageformatsettings.color_mode*", "render/output/properties/output.html#bpy-types-imageformatsettings-color-mode"),
("bpy.types.linestyle*modifier_alongstroke*", "render/freestyle/parameter_editor/line_style/modifiers/color/along_stroke.html#bpy-types-linestyle-modifier-alongstroke"),
@@ -466,6 +490,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.use_compositing*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-compositing"),
("bpy.types.rendersettings.use_placeholder*", "render/output/properties/output.html#bpy-types-rendersettings-use-placeholder"),
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
+ ("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-lock-selection"),
("bpy.types.spacedopesheeteditor.auto_snap*", "editors/dope_sheet/editing.html#bpy-types-spacedopesheeteditor-auto-snap"),
("bpy.types.spaceoutliner.show_mode_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-mode-column"),
("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"),
@@ -491,6 +516,7 @@ url_manual_mapping = (
("bpy.types.colormanagedviewsettings.look*", "render/color_management.html#bpy-types-colormanagedviewsettings-look"),
("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.editbone.use_inherit_rotation*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-inherit-rotation"),
("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.use_slice*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-use-slice"),
@@ -501,7 +527,9 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.temperature*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-temperature"),
("bpy.types.fluidflowsettings.use_texture*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-texture"),
("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
+ ("bpy.types.geometrynodeattributecurvemap*", "modeling/geometry_nodes/attribute/attribute_curve_map.html#bpy-types-geometrynodeattributecurvemap"),
("bpy.types.geometrynodeattributemaprange*", "modeling/geometry_nodes/attribute/attribute_map_range.html#bpy-types-geometrynodeattributemaprange"),
+ ("bpy.types.geometrynodeattributetransfer*", "modeling/geometry_nodes/attribute/attribute_transfer.html#bpy-types-geometrynodeattributetransfer"),
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
@@ -546,6 +574,7 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.use_mesh*", "physics/fluid/type/domain/liquid/mesh.html#bpy-types-fluiddomainsettings-use-mesh"),
("bpy.types.geometrynodeattributecompare*", "modeling/geometry_nodes/attribute/attribute_compare.html#bpy-types-geometrynodeattributecompare"),
("bpy.types.geometrynodeattributeconvert*", "modeling/geometry_nodes/attribute/attribute_convert.html#bpy-types-geometrynodeattributeconvert"),
+ ("bpy.types.geometrynodeselectbymaterial*", "modeling/geometry_nodes/material/select_by_material.html#bpy-types-geometrynodeselectbymaterial"),
("bpy.types.material.preview_render_type*", "render/materials/preview.html#bpy-types-material-preview-render-type"),
("bpy.types.materialgpencilstyle.pattern*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-pattern"),
("bpy.types.materialgpencilstyle.texture*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-texture"),
@@ -595,10 +624,12 @@ url_manual_mapping = (
("bpy.types.compositornodedistancematte*", "compositing/types/matte/distance_key.html#bpy-types-compositornodedistancematte"),
("bpy.types.compositornodesetalpha.mode*", "compositing/types/converter/set_alpha.html#bpy-types-compositornodesetalpha-mode"),
("bpy.types.dopesheet.use_filter_invert*", "editors/graph_editor/channels.html#bpy-types-dopesheet-use-filter-invert"),
+ ("bpy.types.editbone.use_local_location*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-local-location"),
("bpy.types.fluiddomainsettings.gravity*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-gravity"),
("bpy.types.fluidflowsettings.flow_type*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-flow-type"),
("bpy.types.fluidflowsettings.subframes*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-subframes"),
("bpy.types.geometrynodeattributeremove*", "modeling/geometry_nodes/attribute/attribute_remove.html#bpy-types-geometrynodeattributeremove"),
+ ("bpy.types.geometrynodematerialreplace*", "modeling/geometry_nodes/material/replace.html#bpy-types-geometrynodematerialreplace"),
("bpy.types.geometrynodepointdistribute*", "modeling/geometry_nodes/point/point_distribute.html#bpy-types-geometrynodepointdistribute"),
("bpy.types.gpencillayer.use_mask_layer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-mask-layer"),
("bpy.types.greasepencil.use_curve_edit*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-curve-edit"),
@@ -621,6 +652,7 @@ url_manual_mapping = (
("bpy.types.sequenceeditor.show_overlay*", "video_editing/preview/sidebar.html#bpy-types-sequenceeditor-show-overlay"),
("bpy.types.sequenceeditor.use_prefetch*", "video_editing/preview/sidebar.html#bpy-types-sequenceeditor-use-prefetch"),
("bpy.types.soundsequence.show_waveform*", "video_editing/sequencer/sidebar/strip.html#bpy-types-soundsequence-show-waveform"),
+ ("bpy.types.spaceclipeditor.show_stable*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-stable"),
("bpy.types.spaceoutliner.filter_invert*", "editors/outliner/interface.html#bpy-types-spaceoutliner-filter-invert"),
("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"),
@@ -647,6 +679,7 @@ url_manual_mapping = (
("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/sidebar.html#bpy-types-animdata-action-blend-type"),
("bpy.types.bakesettings.use_pass_emit*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-emit"),
+ ("bpy.types.bone.use_envelope_multiply*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-use-envelope-multiply"),
("bpy.types.brush.boundary_deform_type*", "sculpt_paint/sculpting/tools/boundary.html#bpy-types-brush-boundary-deform-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"),
@@ -662,6 +695,9 @@ url_manual_mapping = (
("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierfunctiongenerator"),
("bpy.types.geometrynodeattributeclamp*", "modeling/geometry_nodes/attribute/attribute_clamp.html#bpy-types-geometrynodeattributeclamp"),
("bpy.types.geometrynodecollectioninfo*", "modeling/geometry_nodes/input/collection_info.html#bpy-types-geometrynodecollectioninfo"),
+ ("bpy.types.geometrynodecurvesubdivide*", "modeling/geometry_nodes/curve/curve_subdivide.html#bpy-types-geometrynodecurvesubdivide"),
+ ("bpy.types.geometrynodedeletegeometry*", "modeling/geometry_nodes/geometry/delete_geometry.html#bpy-types-geometrynodedeletegeometry"),
+ ("bpy.types.geometrynodematerialassign*", "modeling/geometry_nodes/material/assign.html#bpy-types-geometrynodematerialassign"),
("bpy.types.geometrynodepointstovolume*", "modeling/geometry_nodes/volume/points_to_volume.html#bpy-types-geometrynodepointstovolume"),
("bpy.types.geometrynodepointtranslate*", "modeling/geometry_nodes/point/point_translate.html#bpy-types-geometrynodepointtranslate"),
("bpy.types.greasepencil.use_multiedit*", "grease_pencil/multiframe.html#bpy-types-greasepencil-use-multiedit"),
@@ -721,13 +757,17 @@ url_manual_mapping = (
("bpy.types.compositornodesplitviewer*", "compositing/types/output/split_viewer.html#bpy-types-compositornodesplitviewer"),
("bpy.types.curve.render_resolution_u*", "modeling/curves/properties/shape.html#bpy-types-curve-render-resolution-u"),
("bpy.types.dynamicpaintbrushsettings*", "physics/dynamic_paint/brush.html#bpy-types-dynamicpaintbrushsettings"),
+ ("bpy.types.editbone.use_scale_easing*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-use-scale-easing"),
("bpy.types.fluiddomainsettings.alpha*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-alpha"),
("bpy.types.fluidflowsettings.density*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-density"),
("bpy.types.geometrynodeattributefill*", "modeling/geometry_nodes/attribute/attribute_fill.html#bpy-types-geometrynodeattributefill"),
("bpy.types.geometrynodeattributemath*", "modeling/geometry_nodes/attribute/attribute_math.html#bpy-types-geometrynodeattributemath"),
+ ("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/curve_to_points.html#bpy-types-geometrynodecurvetopoints"),
+ ("bpy.types.geometrynodeinputmaterial*", "modeling/geometry_nodes/input/material.html#bpy-types-geometrynodeinputmaterial"),
("bpy.types.geometrynodemeshicosphere*", "modeling/geometry_nodes/mesh_primitives/icosphere.html#bpy-types-geometrynodemeshicosphere"),
("bpy.types.geometrynodepointinstance*", "modeling/geometry_nodes/point/point_instance.html#bpy-types-geometrynodepointinstance"),
("bpy.types.geometrynodepointseparate*", "modeling/geometry_nodes/point/point_separate.html#bpy-types-geometrynodepointseparate"),
+ ("bpy.types.geometrynoderesamplecurve*", "modeling/geometry_nodes/curve/resample_curve.html#bpy-types-geometrynoderesamplecurve"),
("bpy.types.light.use_custom_distance*", "render/eevee/lighting.html#bpy-types-light-use-custom-distance"),
("bpy.types.materialgpencilstyle.flip*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-flip"),
("bpy.types.materialgpencilstyle.mode*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-mode"),
@@ -746,6 +786,7 @@ url_manual_mapping = (
("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.spaceclipeditor.show_grid*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-grid"),
("bpy.types.spaceoutliner.filter_text*", "editors/outliner/interface.html#bpy-types-spaceoutliner-filter-text"),
("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"),
@@ -775,11 +816,12 @@ url_manual_mapping = (
("bpy.ops.pose.user_transforms_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-user-transforms-clear"),
("bpy.ops.poselib.browse_interactive*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-browse-interactive"),
("bpy.ops.sculpt.set_persistent_base*", "sculpt_paint/sculpting/tools/layer.html#bpy-ops-sculpt-set-persistent-base"),
- ("bpy.ops.sequencer.crossfade_sounds*", "video_editing/sequencer/strips/transitions/cross.html#bpy-ops-sequencer-crossfade-sounds"),
+ ("bpy.ops.sequencer.crossfade_sounds*", "video_editing/sequencer/strips/transitions/sound_crossfade.html#bpy-ops-sequencer-crossfade-sounds"),
("bpy.ops.sequencer.export_subtitles*", "video_editing/preview/introduction.html#bpy-ops-sequencer-export-subtitles"),
("bpy.ops.transform.edge_bevelweight*", "modeling/meshes/editing/edge/edge_data.html#bpy-ops-transform-edge-bevelweight"),
("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"),
("bpy.types.bakesettings.cage_object*", "render/cycles/baking.html#bpy-types-bakesettings-cage-object"),
+ ("bpy.types.bone.use_relative_parent*", "animation/armatures/bones/properties/relations.html#bpy-types-bone-use-relative-parent"),
("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_connected_only*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-use-connected-only"),
@@ -801,6 +843,7 @@ url_manual_mapping = (
("bpy.types.fluidmodifier.fluid_type*", "physics/fluid/type/index.html#bpy-types-fluidmodifier-fluid-type"),
("bpy.types.functionnodefloatcompare*", "modeling/geometry_nodes/utilities/float_compare.html#bpy-types-functionnodefloatcompare"),
("bpy.types.geometrynodeattributemix*", "modeling/geometry_nodes/attribute/attribute_mix.html#bpy-types-geometrynodeattributemix"),
+ ("bpy.types.geometrynodecurvereverse*", "modeling/geometry_nodes/curve/curve_reverse.html#bpy-types-geometrynodecurvereverse"),
("bpy.types.geometrynodejoingeometry*", "modeling/geometry_nodes/geometry/join_geometry.html#bpy-types-geometrynodejoingeometry"),
("bpy.types.geometrynodemeshcylinder*", "modeling/geometry_nodes/mesh_primitives/cylinder.html#bpy-types-geometrynodemeshcylinder"),
("bpy.types.geometrynodemeshuvsphere*", "modeling/geometry_nodes/mesh_primitives/uv_sphere.html#bpy-types-geometrynodemeshuvsphere"),
@@ -810,6 +853,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.movieclip.display_aspect*", "editors/clip/display/clip_display.html#bpy-types-movieclip-display-aspect"),
("bpy.types.nodesocketinterface.name*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-name"),
("bpy.types.particleinstancemodifier*", "modeling/modifiers/physics/particle_instance.html#bpy-types-particleinstancemodifier"),
("bpy.types.sequencetransform.offset*", "video_editing/sequencer/sidebar/strip.html#bpy-types-sequencetransform-offset"),
@@ -834,6 +878,8 @@ url_manual_mapping = (
("bpy.ops.curve.match_texture_space*", "modeling/meshes/uv/uv_texture_spaces.html#bpy-ops-curve-match-texture-space"),
("bpy.ops.font.text_paste_from_file*", "modeling/texts/editing.html#bpy-ops-font-text-paste-from-file"),
("bpy.ops.gpencil.frame_clean_loose*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-loose"),
+ ("bpy.ops.mask.primitive_circle_add*", "movie_clip/masking/scurve.html#bpy-ops-mask-primitive-circle-add"),
+ ("bpy.ops.mask.primitive_square_add*", "movie_clip/masking/scurve.html#bpy-ops-mask-primitive-square-add"),
("bpy.ops.mesh.primitive_circle_add*", "modeling/meshes/primitives.html#bpy-ops-mesh-primitive-circle-add"),
("bpy.ops.mesh.primitive_monkey_add*", "modeling/meshes/primitives.html#bpy-ops-mesh-primitive-monkey-add"),
("bpy.ops.mesh.select_face_by_sides*", "modeling/meshes/selecting/all_by_trait.html#bpy-ops-mesh-select-face-by-sides"),
@@ -845,8 +891,8 @@ url_manual_mapping = (
("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
("bpy.ops.scene.blenderkit_download*", "addons/3d_view/blenderkit.html#bpy-ops-scene-blenderkit-download"),
("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-set-pivot-position"),
- ("bpy.ops.sequencer.image_strip_add*", "video_editing/sequencer/strips/movie_image.html#bpy-ops-sequencer-image-strip-add"),
- ("bpy.ops.sequencer.movie_strip_add*", "video_editing/sequencer/strips/movie_image.html#bpy-ops-sequencer-movie-strip-add"),
+ ("bpy.ops.sequencer.image_strip_add*", "video_editing/sequencer/strips/image.html#bpy-ops-sequencer-image-strip-add"),
+ ("bpy.ops.sequencer.movie_strip_add*", "video_editing/sequencer/strips/movie.html#bpy-ops-sequencer-movie-strip-add"),
("bpy.ops.sequencer.reassign_inputs*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-reassign-inputs"),
("bpy.ops.sequencer.sound_strip_add*", "video_editing/sequencer/strips/sound.html#bpy-ops-sequencer-sound-strip-add"),
("bpy.ops.ui.remove_override_button*", "files/linked_libraries/library_overrides.html#bpy-ops-ui-remove-override-button"),
@@ -870,11 +916,18 @@ url_manual_mapping = (
("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.curve.use_deform_bounds*", "modeling/curves/properties/shape.html#bpy-types-curve-use-deform-bounds"),
+ ("bpy.types.editbone.bbone_curveinx*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-curveinx"),
+ ("bpy.types.editbone.bbone_curveinz*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-curveinz"),
+ ("bpy.types.editbone.bbone_scaleout*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-scaleout"),
+ ("bpy.types.editbone.bbone_segments*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-segments"),
("bpy.types.freestylemodulesettings*", "render/freestyle/python.html#bpy-types-freestylemodulesettings"),
("bpy.types.functionnodebooleanmath*", "modeling/geometry_nodes/utilities/boolean_math.html#bpy-types-functionnodebooleanmath"),
("bpy.types.functionnodeinputstring*", "modeling/geometry_nodes/input/string.html#bpy-types-functionnodeinputstring"),
("bpy.types.functionnodeinputvector*", "modeling/geometry_nodes/input/vector.html#bpy-types-functionnodeinputvector"),
("bpy.types.functionnoderandomfloat*", "modeling/geometry_nodes/input/random_float.html#bpy-types-functionnoderandomfloat"),
+ ("bpy.types.geometrynodecurvelength*", "modeling/geometry_nodes/curve/curve_length.html#bpy-types-geometrynodecurvelength"),
+ ("bpy.types.geometrynodecurvetomesh*", "modeling/geometry_nodes/curve/curve_to_mesh.html#bpy-types-geometrynodecurvetomesh"),
+ ("bpy.types.geometrynodemeshtocurve*", "modeling/geometry_nodes/curve/mesh_to_curve.html#bpy-types-geometrynodemeshtocurve"),
("bpy.types.geometrynodepointrotate*", "modeling/geometry_nodes/point/point_rotate.html#bpy-types-geometrynodepointrotate"),
("bpy.types.geometrynodetriangulate*", "modeling/geometry_nodes/mesh/triangulate.html#bpy-types-geometrynodetriangulate"),
("bpy.types.gpencillayer.blend_mode*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-blend-mode"),
@@ -938,6 +991,7 @@ url_manual_mapping = (
("bpy.ops.view3d.blenderkit_search*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-search"),
("bpy.types.armature.pose_position*", "animation/armatures/properties/skeleton.html#bpy-types-armature-pose-position"),
("bpy.types.bakesettings.use_clear*", "render/cycles/baking.html#bpy-types-bakesettings-use-clear"),
+ ("bpy.types.bone.envelope_distance*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-envelope-distance"),
("bpy.types.brightcontrastmodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-brightcontrastmodifier"),
("bpy.types.brush.cursor_color_add*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-color-add"),
("bpy.types.brush.pose_deform_type*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-pose-deform-type"),
@@ -965,6 +1019,11 @@ url_manual_mapping = (
("bpy.types.curve.bevel_resolution*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-resolution"),
("bpy.types.cyclesmaterialsettings*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings"),
("bpy.types.dopesheet.show_summary*", "editors/dope_sheet/introduction.html#bpy-types-dopesheet-show-summary"),
+ ("bpy.types.editbone.bbone_easeout*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-easeout"),
+ ("bpy.types.editbone.bbone_rollout*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollout"),
+ ("bpy.types.editbone.bbone_scalein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-scalein"),
+ ("bpy.types.editbone.inherit_scale*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-inherit-scale"),
+ ("bpy.types.geometrynodeconvexhull*", "modeling/geometry_nodes/geometry/convex_hull.html#bpy-types-geometrynodeconvexhull"),
("bpy.types.geometrynodeisviewport*", "modeling/geometry_nodes/input/is_viewport.html#bpy-types-geometrynodeisviewport"),
("bpy.types.geometrynodemeshcircle*", "modeling/geometry_nodes/mesh_primitives/circle.html#bpy-types-geometrynodemeshcircle"),
("bpy.types.geometrynodeobjectinfo*", "modeling/geometry_nodes/input/object_info.html#bpy-types-geometrynodeobjectinfo"),
@@ -1064,6 +1123,8 @@ url_manual_mapping = (
("bpy.types.dampedtrackconstraint*", "animation/constraints/tracking/damped_track.html#bpy-types-dampedtrackconstraint"),
("bpy.types.distortednoisetexture*", "render/materials/legacy_textures/types/distorted_noise.html#bpy-types-distortednoisetexture"),
("bpy.types.dopesheet.filter_text*", "editors/graph_editor/channels.html#bpy-types-dopesheet-filter-text"),
+ ("bpy.types.editbone.bbone_easein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-easein"),
+ ("bpy.types.editbone.bbone_rollin*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollin"),
("bpy.types.fluideffectorsettings*", "physics/fluid/type/effector.html#bpy-types-fluideffectorsettings"),
("bpy.types.followtrackconstraint*", "animation/constraints/motion_tracking/follow_track.html#bpy-types-followtrackconstraint"),
("bpy.types.geometrynodeedgesplit*", "modeling/geometry_nodes/mesh/edge_split.html#bpy-types-geometrynodeedgesplit"),
@@ -1121,6 +1182,7 @@ url_manual_mapping = (
("bpy.ops.spreadsheet.toggle_pin*", "editors/spreadsheet.html#bpy-ops-spreadsheet-toggle-pin"),
("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.bone.envelope_weight*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-envelope-weight"),
("bpy.types.brush.use_persistent*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-use-persistent"),
("bpy.types.buildgpencilmodifier*", "grease_pencil/modifiers/generate/build.html#bpy-types-buildgpencilmodifier"),
("bpy.types.colorbalancemodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-colorbalancemodifier"),
@@ -1139,6 +1201,7 @@ url_manual_mapping = (
("bpy.types.curve.use_path_clamp*", "modeling/curves/properties/path_animation.html#bpy-types-curve-use-path-clamp"),
("bpy.types.datatransfermodifier*", "modeling/modifiers/modify/data_transfer.html#bpy-types-datatransfermodifier"),
("bpy.types.dynamicpaintmodifier*", "physics/dynamic_paint/index.html#bpy-types-dynamicpaintmodifier"),
+ ("bpy.types.editbone.use_connect*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-connect"),
("bpy.types.ffmpegsettings.audio*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio"),
("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"),
("bpy.types.gaussianblursequence*", "video_editing/sequencer/strips/effects/blur.html#bpy-types-gaussianblursequence"),
@@ -1173,6 +1236,7 @@ url_manual_mapping = (
("bpy.types.shadernodewavelength*", "render/shader_nodes/converter/wavelength.html#bpy-types-shadernodewavelength"),
("bpy.types.shrinkwrapconstraint*", "animation/constraints/relationship/shrinkwrap.html#bpy-types-shrinkwrapconstraint"),
("bpy.types.simpledeformmodifier*", "modeling/modifiers/deform/simple_deform.html#bpy-types-simpledeformmodifier"),
+ ("bpy.types.spaceclipeditor.show*", "editors/clip/display/index.html#bpy-types-spaceclipeditor-show"),
("bpy.types.spacedopesheeteditor*", "editors/dope_sheet/index.html#bpy-types-spacedopesheeteditor"),
("bpy.types.speedcontrolsequence*", "video_editing/sequencer/strips/effects/speed_control.html#bpy-types-speedcontrolsequence"),
("bpy.types.texturenodecurvetime*", "editors/texture_node/types/input/time.html#bpy-types-texturenodecurvetime"),
@@ -1251,6 +1315,7 @@ url_manual_mapping = (
("bpy.types.cyclesworldsettings*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings"),
("bpy.types.fluiddomainsettings*", "physics/fluid/type/domain/index.html#bpy-types-fluiddomainsettings"),
("bpy.types.geometrynodeboolean*", "modeling/geometry_nodes/mesh/boolean.html#bpy-types-geometrynodeboolean"),
+ ("bpy.types.geometrynoderaycast*", "modeling/geometry_nodes/geometry/raycast.html#bpy-types-geometrynoderaycast"),
("bpy.types.hookgpencilmodifier*", "grease_pencil/modifiers/deform/hook.html#bpy-types-hookgpencilmodifier"),
("bpy.types.imageformatsettings*", "files/media/image_formats.html#bpy-types-imageformatsettings"),
("bpy.types.kinematicconstraint*", "animation/constraints/tracking/ik_solver.html#bpy-types-kinematicconstraint"),
@@ -1259,6 +1324,7 @@ url_manual_mapping = (
("bpy.types.object.display_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-type"),
("bpy.types.objectlineart.usage*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-usage"),
("bpy.types.particledupliweight*", "physics/particles/emitter/vertex_groups.html#bpy-types-particledupliweight"),
+ ("bpy.types.posebone.bone_group*", "animation/armatures/bones/properties/relations.html#bpy-types-posebone-bone-group"),
("bpy.types.poseboneconstraints*", "animation/armatures/posing/bone_constraints/index.html#bpy-types-poseboneconstraints"),
("bpy.types.rigidbodyconstraint*", "physics/rigid_body/constraints/index.html#bpy-types-rigidbodyconstraint"),
("bpy.types.rigifyarmaturelayer*", "addons/rigging/rigify/metarigs.html#bpy-types-rigifyarmaturelayer"),
@@ -1356,7 +1422,8 @@ url_manual_mapping = (
("bpy.types.curvepaintsettings*", "modeling/curves/tools/draw.html#bpy-types-curvepaintsettings"),
("bpy.types.fmodifiergenerator*", "editors/graph_editor/fcurves/sidebar/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"),
+ ("bpy.types.gammacrosssequence*", "video_editing/sequencer/strips/transitions/gamma_cross.html#bpy-types-gammacrosssequence"),
+ ("bpy.types.geometrynodeswitch*", "modeling/geometry_nodes/utilities/switch.html#bpy-types-geometrynodeswitch"),
("bpy.types.gpencilsculptguide*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide"),
("bpy.types.huecorrectmodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-huecorrectmodifier"),
("bpy.types.imagepaint.stencil*", "sculpt_paint/texture_paint/tool_settings/mask.html#bpy-types-imagepaint-stencil"),
@@ -1378,7 +1445,7 @@ url_manual_mapping = (
("bpy.types.shadernodegeometry*", "render/shader_nodes/input/geometry.html#bpy-types-shadernodegeometry"),
("bpy.types.shadernodehairinfo*", "render/shader_nodes/input/hair_info.html#bpy-types-shadernodehairinfo"),
("bpy.types.shadernodemaprange*", "render/shader_nodes/converter/map_range.html#bpy-types-shadernodemaprange"),
- ("bpy.types.shadernodergbcurve*", "render/shader_nodes/color/rgb_curves.html#bpy-types-shadernodergbcurve"),
+ ("bpy.types.shadernodergbcurve*", "modeling/geometry_nodes/color/rgb_curves.html#bpy-types-shadernodergbcurve"),
("bpy.types.shadernodeseparate*", "render/shader_nodes/converter/combine_separate.html#bpy-types-shadernodeseparate"),
("bpy.types.shadernodetexbrick*", "render/shader_nodes/textures/brick.html#bpy-types-shadernodetexbrick"),
("bpy.types.shadernodetexcoord*", "render/shader_nodes/input/texture_coordinate.html#bpy-types-shadernodetexcoord"),
@@ -1477,7 +1544,7 @@ url_manual_mapping = (
("bpy.types.mesh.use_mirror_y*", "modeling/meshes/tools/tool_settings.html#bpy-types-mesh-use-mirror-y"),
("bpy.types.mesh.use_mirror_z*", "modeling/meshes/tools/tool_settings.html#bpy-types-mesh-use-mirror-z"),
("bpy.types.meshcachemodifier*", "modeling/modifiers/modify/mesh_cache.html#bpy-types-meshcachemodifier"),
- ("bpy.types.movieclipsequence*", "video_editing/sequencer/strips/clip_mask.html#bpy-types-movieclipsequence"),
+ ("bpy.types.movieclipsequence*", "video_editing/sequencer/strips/clip.html#bpy-types-movieclipsequence"),
("bpy.types.object.dimensions*", "scene_layout/object/properties/transforms.html#bpy-types-object-dimensions"),
("bpy.types.object.pass_index*", "scene_layout/object/properties/relations.html#bpy-types-object-pass-index"),
("bpy.types.object.track_axis*", "scene_layout/object/properties/relations.html#bpy-types-object-track-axis"),
@@ -1515,6 +1582,8 @@ url_manual_mapping = (
("bpy.ops.curve.make_segment*", "modeling/curves/editing/control_points.html#bpy-ops-curve-make-segment"),
("bpy.ops.graph.euler_filter*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-euler-filter"),
("bpy.ops.marker.camera_bind*", "animation/markers.html#bpy-ops-marker-camera-bind"),
+ ("bpy.ops.mask.select_circle*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-circle"),
+ ("bpy.ops.mask.select_linked*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-linked"),
("bpy.ops.mesh.beautify_fill*", "modeling/meshes/editing/face/beautify_faces.html#bpy-ops-mesh-beautify-fill"),
("bpy.ops.mesh.colors_rotate*", "modeling/meshes/editing/face/face_data.html#bpy-ops-mesh-colors-rotate"),
("bpy.ops.mesh.edge_collapse*", "modeling/meshes/editing/mesh/delete.html#bpy-ops-mesh-edge-collapse"),
@@ -1550,6 +1619,8 @@ url_manual_mapping = (
("bpy.types.addonpreferences*", "editors/preferences/addons.html#bpy-types-addonpreferences"),
("bpy.types.arealight.spread*", "render/lights/light_object.html#bpy-types-arealight-spread"),
("bpy.types.armaturemodifier*", "modeling/modifiers/deform/armature.html#bpy-types-armaturemodifier"),
+ ("bpy.types.bone.head_radius*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-head-radius"),
+ ("bpy.types.bone.tail_radius*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-tail-radius"),
("bpy.types.brush.cloth_mass*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-mass"),
("bpy.types.brushtextureslot*", "sculpt_paint/brush/texture.html#bpy-types-brushtextureslot"),
("bpy.types.colormixsequence*", "video_editing/sequencer/strips/effects/color_mix.html#bpy-types-colormixsequence"),
@@ -1560,8 +1631,11 @@ url_manual_mapping = (
("bpy.types.decimatemodifier*", "modeling/modifiers/generate/decimate.html#bpy-types-decimatemodifier"),
("bpy.types.displacemodifier*", "modeling/modifiers/deform/displace.html#bpy-types-displacemodifier"),
("bpy.types.displaysafeareas*", "render/cameras.html#bpy-types-displaysafeareas"),
+ ("bpy.types.editbone.bbone_x*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-x"),
+ ("bpy.types.editbone.bbone_z*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-z"),
("bpy.types.fmodifierstepped*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierstepped"),
("bpy.types.freestylelineset*", "render/freestyle/parameter_editor/line_set.html#bpy-types-freestylelineset"),
+ ("bpy.types.mask.frame_start*", "movie_clip/masking/sidebar.html#bpy-types-mask-frame-start"),
("bpy.types.mesh.*customdata*", "modeling/meshes/properties/custom_data.html#bpy-types-mesh-customdata"),
("bpy.types.multicamsequence*", "video_editing/sequencer/strips/effects/multicam.html#bpy-types-multicamsequence"),
("bpy.types.multiplysequence*", "video_editing/sequencer/strips/effects/multiply.html#bpy-types-multiplysequence"),
@@ -1612,6 +1686,7 @@ url_manual_mapping = (
("bpy.ops.gpencil.reproject*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-reproject"),
("bpy.ops.graph.easing_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-easing-type"),
("bpy.ops.graph.handle_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-handle-type"),
+ ("bpy.ops.mask.parent_clear*", "movie_clip/masking/editing.html#bpy-ops-mask-parent-clear"),
("bpy.ops.mesh.bevel.vertex*", "modeling/meshes/editing/vertex/bevel_vertices.html#bpy-ops-mesh-bevel-vertex"),
("bpy.ops.mesh.delete_loose*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-delete-loose"),
("bpy.ops.mesh.face_shading*", "modeling/meshes/editing/face/shading.html#bpy-ops-mesh-face-shading"),
@@ -1640,11 +1715,14 @@ url_manual_mapping = (
("bpy.ops.wm.previews_clear*", "files/blend/previews.html#bpy-ops-wm-previews-clear"),
("bpy.types.armature.layers*", "animation/armatures/properties/skeleton.html#bpy-types-armature-layers"),
("bpy.types.armature.rigify*", "addons/rigging/rigify/basics.html#bpy-types-armature-rigify"),
+ ("bpy.types.bone.use_deform*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-use-deform"),
("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.curve.eval_time*", "modeling/curves/properties/path_animation.html#bpy-types-curve-eval-time"),
("bpy.types.curve.fill_mode*", "modeling/curves/properties/shape.html#bpy-types-curve-fill-mode"),
+ ("bpy.types.editbone.layers*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-layers"),
+ ("bpy.types.editbone.parent*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-parent"),
("bpy.types.explodemodifier*", "modeling/modifiers/physics/explode.html#bpy-types-explodemodifier"),
("bpy.types.fcurvemodifiers*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fcurvemodifiers"),
("bpy.types.floorconstraint*", "animation/constraints/relationship/floor.html#bpy-types-floorconstraint"),
@@ -1685,6 +1763,8 @@ url_manual_mapping = (
("bpy.ops.gpencil.dissolve*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-dissolve"),
("bpy.ops.graph.frame_jump*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-frame-jump"),
("bpy.ops.graph.sound_bake*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-sound-bake"),
+ ("bpy.ops.mask.select_less*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-less"),
+ ("bpy.ops.mask.select_more*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-more"),
("bpy.ops.mesh.convex_hull*", "modeling/meshes/editing/mesh/convex_hull.html#bpy-ops-mesh-convex-hull"),
("bpy.ops.mesh.edge_rotate*", "modeling/meshes/editing/edge/rotate_edge.html#bpy-ops-mesh-edge-rotate"),
("bpy.ops.mesh.unsubdivide*", "modeling/meshes/editing/edge/unsubdivide.html#bpy-ops-mesh-unsubdivide"),
@@ -1718,6 +1798,7 @@ url_manual_mapping = (
("bpy.types.curvesmodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-curvesmodifier"),
("bpy.types.ffmpegsettings*", "render/output/properties/output.html#bpy-types-ffmpegsettings"),
("bpy.types.fmodifiernoise*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifiernoise"),
+ ("bpy.types.mask.frame_end*", "movie_clip/masking/sidebar.html#bpy-types-mask-frame-end"),
("bpy.types.material.paint*", "sculpt_paint/texture_paint/index.html#bpy-types-material-paint"),
("bpy.types.mirrormodifier*", "modeling/modifiers/generate/mirror.html#bpy-types-mirrormodifier"),
("bpy.types.movieclipproxy*", "editors/clip/sidebar.html#bpy-types-movieclipproxy"),
@@ -1757,6 +1838,9 @@ url_manual_mapping = (
("bpy.ops.fluid.free_mesh*", "physics/fluid/type/domain/liquid/mesh.html#bpy-ops-fluid-free-mesh"),
("bpy.ops.font.select_all*", "modeling/texts/selecting.html#bpy-ops-font-select-all"),
("bpy.ops.gpencil.convert*", "grease_pencil/modes/object/convert_to_geometry.html#bpy-ops-gpencil-convert"),
+ ("bpy.ops.mask.parent_set*", "movie_clip/masking/editing.html#bpy-ops-mask-parent-set"),
+ ("bpy.ops.mask.select_all*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-all"),
+ ("bpy.ops.mask.select_box*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-box"),
("bpy.ops.mesh.customdata*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata"),
("bpy.ops.mesh.edge_split*", "modeling/meshes/editing/mesh/split.html#bpy-ops-mesh-edge-split"),
("bpy.ops.mesh.fill_holes*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-fill-holes"),
@@ -1800,11 +1884,15 @@ url_manual_mapping = (
("bpy.types.crosssequence*", "video_editing/sequencer/strips/transitions/cross.html#bpy-types-crosssequence"),
("bpy.types.curve.extrude*", "modeling/curves/properties/geometry.html#bpy-types-curve-extrude"),
("bpy.types.curvemodifier*", "modeling/modifiers/deform/curve.html#bpy-types-curvemodifier"),
+ ("bpy.types.editbone.head*", "animation/armatures/bones/properties/transform.html#bpy-types-editbone-head"),
+ ("bpy.types.editbone.lock*", "animation/armatures/bones/properties/transform.html#bpy-types-editbone-lock"),
+ ("bpy.types.editbone.roll*", "animation/armatures/bones/properties/transform.html#bpy-types-editbone-roll"),
+ ("bpy.types.editbone.tail*", "animation/armatures/bones/properties/transform.html#bpy-types-editbone-tail"),
("bpy.types.fieldsettings*", "physics/forces/force_fields/index.html#bpy-types-fieldsettings"),
- ("bpy.types.imagesequence*", "video_editing/sequencer/strips/movie_image.html#bpy-types-imagesequence"),
+ ("bpy.types.imagesequence*", "video_editing/sequencer/strips/image.html#bpy-types-imagesequence"),
("bpy.types.marbletexture*", "render/materials/legacy_textures/types/marble.html#bpy-types-marbletexture"),
("bpy.types.modifier.show*", "modeling/modifiers/introduction.html#bpy-types-modifier-show"),
- ("bpy.types.moviesequence*", "video_editing/sequencer/strips/movie_image.html#bpy-types-moviesequence"),
+ ("bpy.types.moviesequence*", "video_editing/sequencer/strips/movie.html#bpy-types-moviesequence"),
("bpy.types.movietracking*", "movie_clip/tracking/index.html#bpy-types-movietracking"),
("bpy.types.nlastrip.mute*", "editors/nla/sidebar.html#bpy-types-nlastrip-mute"),
("bpy.types.nlastrip.name*", "editors/nla/sidebar.html#bpy-types-nlastrip-name"),
@@ -1880,7 +1968,7 @@ url_manual_mapping = (
("bpy.types.latticepoint*", "animation/lattice.html#bpy-types-latticepoint"),
("bpy.types.magictexture*", "render/materials/legacy_textures/types/magic.html#bpy-types-magictexture"),
("bpy.types.maskmodifier*", "modeling/modifiers/generate/mask.html#bpy-types-maskmodifier"),
- ("bpy.types.masksequence*", "video_editing/sequencer/strips/clip_mask.html#bpy-types-masksequence"),
+ ("bpy.types.masksequence*", "video_editing/sequencer/strips/mask.html#bpy-types-masksequence"),
("bpy.types.materialslot*", "render/materials/assignment.html#bpy-types-materialslot"),
("bpy.types.metasequence*", "video_editing/sequencer/meta.html#bpy-types-metasequence"),
("bpy.types.object.color*", "scene_layout/object/properties/display.html#bpy-types-object-color"),
@@ -1982,6 +2070,8 @@ url_manual_mapping = (
("bpy.types.constraint*", "animation/constraints/index.html#bpy-types-constraint"),
("bpy.types.imagepaint*", "sculpt_paint/texture_paint/index.html#bpy-types-imagepaint"),
("bpy.types.lightprobe*", "render/eevee/light_probes/index.html#bpy-types-lightprobe"),
+ ("bpy.types.maskparent*", "movie_clip/masking/sidebar.html#bpy-types-maskparent"),
+ ("bpy.types.maskspline*", "movie_clip/masking/sidebar.html#bpy-types-maskspline"),
("bpy.types.node.color*", "interface/controls/nodes/sidebar.html#bpy-types-node-color"),
("bpy.types.node.label*", "interface/controls/nodes/sidebar.html#bpy-types-node-label"),
("bpy.types.nodesocket*", "interface/controls/nodes/parts.html#bpy-types-nodesocket"),
@@ -2017,6 +2107,7 @@ url_manual_mapping = (
("bpy.types.dopesheet*", "editors/dope_sheet/index.html#bpy-types-dopesheet"),
("bpy.types.fmodifier*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifier"),
("bpy.types.freestyle*", "render/freestyle/index.html#bpy-types-freestyle"),
+ ("bpy.types.masklayer*", "movie_clip/masking/sidebar.html#bpy-types-masklayer"),
("bpy.types.movieclip*", "movie_clip/index.html#bpy-types-movieclip"),
("bpy.types.node.name*", "interface/controls/nodes/sidebar.html#bpy-types-node-name"),
("bpy.types.nodeframe*", "interface/controls/nodes/frame.html#bpy-types-nodeframe"),
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index dbc7ce650a3..bd14b2c532c 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -3010,6 +3010,22 @@ def km_clip_dopesheet_editor(_params):
return keymap
+def km_spreadsheet_generic(_params):
+ items = []
+ keymap = (
+ "Spreadsheet Generic",
+ {"space_type": 'SPREADSHEET', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ items.extend([
+ *_template_space_region_type_toggle(
+ sidebar_key={"type": 'N', "value": 'PRESS'},
+ ),
+ ])
+
+ return keymap
+
# ------------------------------------------------------------------------------
# Animation
@@ -4090,7 +4106,7 @@ def km_pose(params):
("pose.bone_layers", {"type": 'M', "value": 'PRESS'}, None),
("transform.bbone_resize", {"type": 'S', "value": 'PRESS', "ctrl": True, "alt": True}, None),
("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None),
- ("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None),
+ ("anim.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
("poselib.browse_interactive", {"type": 'L', "value": 'PRESS', "alt": True}, None),
("poselib.pose_add", {"type": 'L', "value": 'PRESS', "shift": True}, None),
@@ -4162,7 +4178,7 @@ def km_object_mode(params):
("wm.context_toggle", {"type": 'PERIOD', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'tool_settings.use_transform_data_origin')]}),
("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None),
- ("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None),
+ ("anim.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
("collection.create", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("collection.objects_remove", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
@@ -7067,6 +7083,7 @@ def generate_keymaps(params=None):
km_image(params),
km_node_generic(params),
km_node_editor(params),
+ km_spreadsheet_generic(params),
km_info(params),
km_file_browser(params),
km_file_browser_main(params),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index dbf583149e3..e56783fcc21 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -3000,7 +3000,7 @@ def km_pose(params):
("anim.keyframe_insert_by_name", {"type": 'R', "value": 'PRESS', "shift": True},
{"properties": [("type", 'Scaling')]}),
- ("anim.keyframe_delete_v3d", {"type": 'S', "value": 'PRESS', "alt": True}, None),
+ ("anim.keyframe_delete", {"type": 'S', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
*_template_items_context_menu("VIEW3D_MT_pose_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Tools
@@ -3071,7 +3071,7 @@ def km_object_mode(params):
{"properties": [("type", 'Rotation')]}),
("anim.keyframe_insert_by_name", {"type": 'R', "value": 'PRESS', "shift": True},
{"properties": [("type", 'Scaling')]}),
- ("anim.keyframe_delete_v3d", {"type": 'S', "value": 'PRESS', "alt": True}, None),
+ ("anim.keyframe_delete", {"type": 'S', "value": 'PRESS', "alt": True}, None),
("anim.keying_set_active_set", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
*_template_items_context_menu("VIEW3D_MT_object_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("object.move_to_collection", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
diff --git a/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py b/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py
index 192ba2cf5b5..40dd0729fec 100644
--- a/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py
+++ b/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py
@@ -23,7 +23,7 @@ from bpy.app.handlers import persistent
@persistent
-def load_handler(dummy):
+def load_handler(_):
import bpy
# 2D Animation
diff --git a/release/scripts/startup/bl_app_templates_system/Sculpting/__init__.py b/release/scripts/startup/bl_app_templates_system/Sculpting/__init__.py
index 4d1361ed22a..ef085bcd688 100644
--- a/release/scripts/startup/bl_app_templates_system/Sculpting/__init__.py
+++ b/release/scripts/startup/bl_app_templates_system/Sculpting/__init__.py
@@ -21,7 +21,7 @@ from bpy.app.handlers import persistent
@persistent
-def load_handler(dummy):
+def load_handler(_):
import bpy
# Apply subdivision modifier on startup
bpy.ops.object.mode_set(mode='OBJECT')
diff --git a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py
index c97c3466085..ae3fdee56ac 100644
--- a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py
+++ b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py
@@ -21,7 +21,7 @@ from bpy.app.handlers import persistent
@persistent
-def load_handler(dummy):
+def load_handler(_):
from bpy import context
screen = context.screen
for area in screen.areas:
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 6150789ea10..3cefaf6929b 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -331,14 +331,15 @@ class NODE_OT_active_preview_toggle(Operator):
active_node = ntree.nodes.active
if active_node.active_preview:
- self.disable_preview(context, ntree, active_node)
+ self._disable_preview(context, active_node)
else:
- self.enable_preview(context, node_editor, ntree, active_node)
+ self._enable_preview(context, node_editor, ntree, active_node)
return {'FINISHED'}
- def enable_preview(self, context, node_editor, ntree, active_node):
- spreadsheets = self.find_unpinned_spreadsheets(context)
+ @classmethod
+ def _enable_preview(cls, context, node_editor, ntree, active_node):
+ spreadsheets = cls._find_unpinned_spreadsheets(context)
for spreadsheet in spreadsheets:
spreadsheet.set_geometry_node_context(node_editor, active_node)
@@ -347,14 +348,16 @@ class NODE_OT_active_preview_toggle(Operator):
node.active_preview = False
active_node.active_preview = True
- def disable_preview(self, context, ntree, active_node):
- spreadsheets = self.find_unpinned_spreadsheets(context)
+ @classmethod
+ def _disable_preview(cls, context, active_node):
+ spreadsheets = cls._find_unpinned_spreadsheets(context)
for spreadsheet in spreadsheets:
spreadsheet.context_path.clear()
active_node.active_preview = False
- def find_unpinned_spreadsheets(self, context):
+ @staticmethod
+ def _find_unpinned_spreadsheets(context):
spreadsheets = []
for window in context.window_manager.windows:
for area in window.screen.areas:
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 6452ad8465b..daf64642f68 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -156,11 +156,11 @@ class BONE_PT_curved(BoneButtonsPanel, Panel):
col = topcol.column(align=True)
col.prop(bbone, "bbone_curveinx", text="Curve In X")
- col.prop(bbone, "bbone_curveiny", text="In Y")
+ col.prop(bbone, "bbone_curveinz", text="Z")
col = topcol.column(align=True)
col.prop(bbone, "bbone_curveoutx", text="Curve Out X")
- col.prop(bbone, "bbone_curveouty", text="Out Y")
+ col.prop(bbone, "bbone_curveoutz", text="Z")
col = topcol.column(align=True)
col.prop(bbone, "bbone_rollin", text="Roll In")
@@ -168,30 +168,55 @@ class BONE_PT_curved(BoneButtonsPanel, Panel):
col.prop(bone, "use_endroll_as_inroll")
col = topcol.column(align=True)
- col.prop(bbone, "bbone_scaleinx", text="Scale In X")
- col.prop(bbone, "bbone_scaleiny", text="In Y")
+ col.prop(bbone, "bbone_scalein", text="Scale In")
col = topcol.column(align=True)
- col.prop(bbone, "bbone_scaleoutx", text="Scale Out X")
- col.prop(bbone, "bbone_scaleouty", text="Out Y")
+ col.prop(bbone, "bbone_scaleout", text="Scale Out")
col = topcol.column(align=True)
col.prop(bbone, "bbone_easein", text="Ease In")
col.prop(bbone, "bbone_easeout", text="Out")
+ col.prop(bone, "use_scale_easing")
col = topcol.column(align=True)
col.prop(bone, "bbone_handle_type_start", text="Start Handle")
- col = col.column(align=True)
- col.active = (bone.bbone_handle_type_start != 'AUTO')
- col.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
+ col2 = col.column(align=True)
+ col2.active = (bone.bbone_handle_type_start != 'AUTO')
+ col2.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
+
+ row = col.row(align=True)
+ row.use_property_split = False
+ split = row.split(factor=0.4)
+ split.alignment = 'RIGHT'
+ split.label(text="Scale")
+ split2 = split.split(factor=0.7)
+ row2 = split2.row(align=True)
+ row2.prop(bone, "bbone_handle_use_scale_start", index=0, text="X", toggle=True)
+ row2.prop(bone, "bbone_handle_use_scale_start", index=1, text="Y", toggle=True)
+ row2.prop(bone, "bbone_handle_use_scale_start", index=2, text="Z", toggle=True)
+ split2.prop(bone, "bbone_handle_use_ease_start", text="Ease", toggle=True)
+ row.label(icon="BLANK1")
col = topcol.column(align=True)
col.prop(bone, "bbone_handle_type_end", text="End Handle")
- col = col.column(align=True)
- col.active = (bone.bbone_handle_type_end != 'AUTO')
- col.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
+ col2 = col.column(align=True)
+ col2.active = (bone.bbone_handle_type_end != 'AUTO')
+ col2.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
+
+ row = col.row(align=True)
+ row.use_property_split = False
+ split = row.split(factor=0.4)
+ split.alignment = 'RIGHT'
+ split.label(text="Scale")
+ split2 = split.split(factor=0.7)
+ row2 = split2.row(align=True)
+ row2.prop(bone, "bbone_handle_use_scale_end", index=0, text="X", toggle=True)
+ row2.prop(bone, "bbone_handle_use_scale_end", index=1, text="Y", toggle=True)
+ row2.prop(bone, "bbone_handle_use_scale_end", index=2, text="Z", toggle=True)
+ split2.prop(bone, "bbone_handle_use_ease_end", text="Ease", toggle=True)
+ row.label(icon="BLANK1")
class BONE_PT_relations(BoneButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index a9d7b8d71f3..b0e466d3e51 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -517,7 +517,6 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel):
col.prop(mesh, "remesh_voxel_size")
col.prop(mesh, "remesh_voxel_adaptivity")
col.prop(mesh, "use_remesh_fix_poles")
- col.prop(mesh, "use_remesh_smooth_normals")
col = layout.column(heading="Preserve")
col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index e7893b8c448..ffb7b9e5c20 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -594,9 +594,9 @@ class DOPESHEET_MT_delete(Menu):
class DOPESHEET_MT_context_menu(Menu):
bl_label = "Dope Sheet Context Menu"
- def draw(self, _context):
+ def draw(self, context):
layout = self.layout
- st = _context.space_data
+ st = context.space_data
layout.operator_context = 'INVOKE_DEFAULT'
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index b236b2ee7cf..1ad88744b16 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -44,6 +44,10 @@ class FILEBROWSER_HT_header(Header):
layout.separator_spacer()
+ layout.prop(params, "import_type", text="")
+
+ layout.separator_spacer()
+
# Uses prop_with_popover() as popover() only adds the triangle icon in headers.
layout.prop_with_popover(
params,
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 11eaf55a98b..3fafa328289 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -914,6 +914,12 @@ class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
bl_category = "Mask"
+class IMAGE_PT_mask_display(MASK_PT_display, Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Mask"
+
+
# --- end mask ---
class IMAGE_PT_snapping(Panel):
@@ -1616,6 +1622,7 @@ classes = (
IMAGE_PT_active_tool,
IMAGE_PT_mask,
IMAGE_PT_mask_layers,
+ IMAGE_PT_mask_display,
IMAGE_PT_active_mask_spline,
IMAGE_PT_active_mask_point,
IMAGE_PT_snapping,
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 07d9b0ee1f8..13a8e46e2b8 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -392,6 +392,11 @@ class SEQUENCER_MT_view(Menu):
layout.menu("SEQUENCER_MT_proxy")
layout.operator_context = 'INVOKE_DEFAULT'
+
+ layout.separator()
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("sequencer.refresh_all", icon='FILE_REFRESH', text="Refresh All")
+ layout.operator_context = 'INVOKE_DEFAULT'
if is_sequencer_view:
layout.separator()
@@ -401,12 +406,6 @@ class SEQUENCER_MT_view(Menu):
layout.menu("SEQUENCER_MT_range")
layout.separator()
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("sequencer.refresh_all", icon='FILE_REFRESH', text="Refresh All")
-
- layout.separator()
- layout.operator_context = 'INVOKE_DEFAULT'
-
layout.prop(st, "show_locked_time")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py
index 13e435a7350..360849a0c7a 100644
--- a/release/scripts/startup/bl_ui/space_spreadsheet.py
+++ b/release/scripts/startup/bl_ui/space_spreadsheet.py
@@ -59,9 +59,12 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False)
layout.separator_spacer()
-
- if isinstance(obj, bpy.types.Object) and obj.mode == 'EDIT':
- layout.prop(space, "show_only_selected", text="Selected Only")
+
+ row = layout.row(align=True)
+ sub = row.row(align=True)
+ sub.active = self.selection_filter_available(space)
+ sub.prop(space, "show_only_selected", text="")
+ row.prop(space, "use_filter", toggle=True, icon='FILTER', icon_only=True)
def draw_without_context_path(self, layout):
layout.label(text="No active context")
@@ -102,6 +105,17 @@ class SPREADSHEET_HT_header(bpy.types.Header):
def draw_spreadsheet_context_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
layout.prop(space, "display_context_path_collapsed", icon_only=True, emboss=False, icon=icon)
+ def selection_filter_available(self, space):
+ root_context = space.context_path[0]
+ if root_context.type != 'OBJECT':
+ return False
+ obj = root_context.object
+ if obj is None:
+ return False
+ if obj.type != 'MESH' or obj.mode != 'EDIT':
+ return False
+ return True
+
classes = (
SPREADSHEET_HT_header,
)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 26ad22d3ac2..f9359a8b4a0 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -605,6 +605,23 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
# col.row().prop(system, "opensubdiv_compute_type", text="")
+class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
+ bl_label = "Operating System Settings"
+
+ @classmethod
+ def poll(cls, _context):
+ # Only for Windows so far
+ import sys
+ return sys.platform[:3] == "win"
+
+ def draw_centered(self, _context, layout):
+ layout.label(text="Make this installation your default Blender")
+ split = layout.split(factor=0.4)
+ split.alignment = 'RIGHT'
+ split.label(text="")
+ split.operator("file.associate_blend", text="Make Default")
+
+
class USERPREF_PT_system_memory(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Memory & Limits"
@@ -2324,6 +2341,7 @@ classes = (
USERPREF_PT_animation_fcurves,
USERPREF_PT_system_cycles_devices,
+ USERPREF_PT_system_os_settings,
USERPREF_PT_system_memory,
USERPREF_PT_system_video_sequencer,
USERPREF_PT_system_sound,
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 5f47aa90026..80cede9ee5a 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2530,7 +2530,7 @@ class VIEW3D_MT_object_context_menu(Menu):
layout.operator_menu_enum("gpencil.convert", "type", text="Convert To")
if (
- obj.type in {'MESH', 'CURVE', 'SURFACE', 'GPENCIL', 'LATTICE', 'ARMATURE', 'META'} or
+ obj.type in {'MESH', 'CURVE', 'SURFACE', 'GPENCIL', 'LATTICE', 'ARMATURE', 'META', 'FONT'} or
(obj.type == 'EMPTY' and obj.instance_collection is not None)
):
layout.operator_context = 'INVOKE_REGION_WIN'
@@ -3727,6 +3727,8 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
layout = self.layout
+ with_freestyle = bpy.app.build_options.freestyle
+
layout.operator_context = 'INVOKE_REGION_WIN'
# If nothing is selected
@@ -3844,10 +3846,11 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
col.operator("mesh.mark_sharp")
col.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
- col.separator()
+ if with_freestyle:
+ col.separator()
- col.operator("mesh.mark_freestyle_edge").clear = False
- col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
+ col.operator("mesh.mark_freestyle_edge").clear = False
+ col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
col.separator()
@@ -4014,38 +4017,6 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("object.vertex_parent_set")
-class VIEW3D_MT_edit_mesh_edges_data(Menu):
- bl_label = "Edge Data"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator_context = 'INVOKE_REGION_WIN'
-
- layout.operator("transform.edge_crease")
- layout.operator("transform.edge_bevelweight")
-
- layout.separator()
-
- layout.operator("mesh.mark_seam").clear = False
- layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
-
- layout.separator()
-
- layout.operator("mesh.mark_sharp")
- layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
-
- layout.operator("mesh.mark_sharp", text="Mark Sharp from Vertices").use_verts = True
- props = layout.operator("mesh.mark_sharp", text="Clear Sharp from Vertices")
- props.use_verts = True
- props.clear = True
-
- layout.separator()
-
- layout.operator("mesh.mark_freestyle_edge").clear = False
- layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
-
-
class VIEW3D_MT_edit_mesh_edges(Menu):
bl_label = "Edge"
@@ -6186,9 +6157,6 @@ class VIEW3D_PT_overlay_geometry(Panel):
sub.active = overlay.show_fade_inactive
sub.prop(overlay, "fade_inactive_alpha", text="Fade Inactive Geometry")
- row = col.row(align=True)
- row.prop(overlay, "show_mode_transfer", text="Flash on Mode Transfer")
-
col = layout.column(align=True)
col.active = display_all
@@ -7609,7 +7577,6 @@ classes = (
VIEW3D_MT_edit_mesh_extrude,
VIEW3D_MT_edit_mesh_vertices,
VIEW3D_MT_edit_mesh_edges,
- VIEW3D_MT_edit_mesh_edges_data,
VIEW3D_MT_edit_mesh_faces,
VIEW3D_MT_edit_mesh_faces_data,
VIEW3D_MT_edit_mesh_normals,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 89bb2005f53..bc385faf378 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -832,7 +832,6 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
props.mode = 'VOXEL'
col.prop(mesh, "remesh_voxel_adaptivity")
col.prop(mesh, "use_remesh_fix_poles")
- col.prop(mesh, "use_remesh_smooth_normals")
col = layout.column(heading="Preserve", align=True)
col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py
index 83151a3480c..2fc2d966ea9 100644
--- a/release/scripts/startup/keyingsets_builtins.py
+++ b/release/scripts/startup/keyingsets_builtins.py
@@ -532,7 +532,7 @@ class WholeCharacterMixin:
prop_path = '["%s"]' % bpy.utils.escape_identifier(prop)
try:
rna_property = bone.path_resolve(prop_path, False)
- except ValueError as ex:
+ except ValueError:
# This happens when a custom property is set to None. In that case it cannot
# be converted to an FCurve-compatible value, so we can't keyframe it anyway.
continue
@@ -582,7 +582,7 @@ class BUILTIN_KSI_DeltaLocation(KeyingSetInfo):
iterator = keyingsets_utils.RKS_ITER_selected_objects
# generator - delta location channels only
- def generate(self, context, ks, data):
+ def generate(self, _context, ks, data):
# get id-block and path info
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
@@ -608,7 +608,7 @@ class BUILTIN_KSI_DeltaRotation(KeyingSetInfo):
iterator = keyingsets_utils.RKS_ITER_selected_objects
# generator - delta location channels only
- def generate(self, context, ks, data):
+ def generate(self, _context, ks, data):
# get id-block and path info
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
@@ -642,7 +642,7 @@ class BUILTIN_KSI_DeltaScale(KeyingSetInfo):
iterator = keyingsets_utils.RKS_ITER_selected_objects
# generator - delta location channels only
- def generate(self, context, ks, data):
+ def generate(self, _context, ks, data):
# get id-block and path info
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 9db2670d7c0..005e282fc0f 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -66,7 +66,7 @@ class GeometryNodeCategory(SortedNodeCategory):
# menu entry for node group tools
-def group_tools_draw(self, layout, context):
+def group_tools_draw(self, layout, _context):
layout.operator("node.group_make")
layout.operator("node.group_ungroup")
layout.separator()
@@ -119,8 +119,8 @@ def node_group_items(context):
if group.name.startswith('.'):
continue
yield NodeItem(node_tree_group_type[group.bl_idname],
- group.name,
- {"node_tree": "bpy.data.node_groups[%r]" % group.name})
+ label=group.name,
+ settings={"node_tree": "bpy.data.node_groups[%r]" % group.name})
# only show input/output nodes inside node groups
@@ -501,11 +501,14 @@ geometry_node_categories = [
NodeItem("ShaderNodeCombineRGB"),
]),
GeometryNodeCategory("GEO_CURVE", "Curve", items=[
+ NodeItem("GeometryNodeCurveSubdivide"),
NodeItem("GeometryNodeCurveToMesh"),
NodeItem("GeometryNodeCurveResample"),
NodeItem("GeometryNodeCurveDeform"),
NodeItem("GeometryNodeMeshToCurve"),
+ NodeItem("GeometryNodeCurveToPoints"),
NodeItem("GeometryNodeCurveLength"),
+ NodeItem("GeometryNodeCurveReverse"),
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
NodeItem("GeometryNodeBoundBox"),
@@ -513,6 +516,8 @@ geometry_node_categories = [
NodeItem("GeometryNodeDeleteGeometry"),
NodeItem("GeometryNodeTransform"),
NodeItem("GeometryNodeJoinGeometry"),
+ NodeItem("GeometryNodeSeparateComponents"),
+ NodeItem("GeometryNodeRaycast"),
]),
GeometryNodeCategory("GEO_INPUT", "Input", items=[
NodeItem("GeometryNodeObjectInfo"),
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 092eec578c9..7d553b68185 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -345,7 +345,7 @@ void DM_interp_vert_data(struct DerivedMesh *source,
void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
-/* same as above but wont use render settings */
+/* same as above but won't use render settings */
struct Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *,
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 3002a9cc10d..112b8bf3ad4 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -80,11 +80,10 @@ typedef struct EditBone {
/* Bendy-Bone parameters */
short segments;
float roll1, roll2;
- float curve_in_x, curve_in_y;
- float curve_out_x, curve_out_y;
+ float curve_in_x, curve_in_z;
+ float curve_out_x, curve_out_z;
float ease1, ease2;
- float scale_in_x, scale_in_y;
- float scale_out_x, scale_out_y;
+ float scale_in[3], scale_out[3];
/** for envelope scaling */
float oldlength;
@@ -92,6 +91,10 @@ typedef struct EditBone {
/** Type of next/prev bone handles */
char bbone_prev_type;
char bbone_next_type;
+ /** B-Bone flags. */
+ int bbone_flag;
+ short bbone_prev_flag;
+ short bbone_next_flag;
/** Next/prev bones to use as handle references when calculating bbones (optional) */
struct EditBone *bbone_prev;
struct EditBone *bbone_next;
@@ -298,8 +301,8 @@ typedef struct BBoneSplineParameters {
/* Control values. */
float ease1, ease2;
float roll1, roll2;
- float scale_in_x, scale_in_y, scale_out_x, scale_out_y;
- float curve_in_x, curve_in_y, curve_out_x, curve_out_y;
+ float scale_in[3], scale_out[3];
+ float curve_in_x, curve_in_z, curve_out_x, curve_out_z;
} BBoneSplineParameters;
void BKE_pchan_bbone_handles_get(struct bPoseChannel *pchan,
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 6ad910ff8ab..1767077fa45 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 4
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 429e294a337..3e0a343a766 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -25,6 +25,7 @@ extern "C" {
struct BlendFileData;
struct BlendFileReadParams;
+struct BlendFileReadReport;
struct ID;
struct Main;
struct MemFile;
@@ -35,7 +36,7 @@ struct bContext;
void BKE_blendfile_read_setup_ex(struct bContext *C,
struct BlendFileData *bfd,
const struct BlendFileReadParams *params,
- struct ReportList *reports,
+ struct BlendFileReadReport *reports,
/* Extra args. */
const bool startup_update_defaults,
const char *startup_app_template);
@@ -43,11 +44,11 @@ void BKE_blendfile_read_setup_ex(struct bContext *C,
void BKE_blendfile_read_setup(struct bContext *C,
struct BlendFileData *bfd,
const struct BlendFileReadParams *params,
- struct ReportList *reports);
+ struct BlendFileReadReport *reports);
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
- struct ReportList *reports);
+ struct BlendFileReadReport *reports);
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index eb9c68f80ec..2687a5ea16c 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -156,7 +156,7 @@ struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render);
-ListBase BKE_curve_bevel_make(const struct Curve *ob);
+ListBase BKE_curve_bevel_make(const struct Curve *curve);
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index ffa0b4d0091..a2d9bbcd011 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -93,8 +93,8 @@ void BKE_displist_make_curveTypes_forRender(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *ob,
struct ListBase *dispbase,
- struct Mesh **r_final,
- const bool for_orco);
+ const bool for_orco,
+ struct Mesh **r_final);
void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_displist_make_mball_forRender(struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 3a1eedfd807..075a9bc0eac 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -34,6 +34,7 @@ extern "C" {
struct BMLoop;
struct BMesh;
struct BMPartialUpdate;
+struct BMeshCalcTessellation_Params;
struct BoundBox;
struct Depsgraph;
struct Mesh;
@@ -85,8 +86,17 @@ typedef struct BMEditMesh {
} BMEditMesh;
/* editmesh.c */
+void BKE_editmesh_looptri_calc_ex(BMEditMesh *em,
+ const struct BMeshCalcTessellation_Params *params);
void BKE_editmesh_looptri_calc(BMEditMesh *em);
+void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em,
+ struct BMPartialUpdate *bmpinfo,
+ const struct BMeshCalcTessellation_Params *params);
void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo);
+void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
+ struct BMPartialUpdate *bmpinfo);
+
+void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em);
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate);
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index bb145580928..d0a1f102a43 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -119,6 +119,7 @@ struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src,
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
const bool dup_frames,
const bool dup_strokes);
+void BKE_gpencil_layer_copy_settings(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
void BKE_gpencil_frame_selected_hash(struct bGPdata *gpd, struct GHash *r_list);
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index c6406c8478c..8fbc2112c77 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -294,6 +294,22 @@ bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
+/* Stores the maximum calculation range in the whole modifier stack for line art so the cache can
+ * cover everything that will be visible. */
+typedef struct GpencilLineartLimitInfo {
+ char min_level;
+ char max_level;
+ short edge_types;
+} GpencilLineartLimitInfo;
+
+GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const struct Object *ob);
+
+void BKE_gpencil_set_lineart_modifier_limits(struct GpencilModifierData *md,
+ const struct GpencilLineartLimitInfo *info,
+ const bool is_first_lineart);
+bool BKE_gpencil_is_first_lineart_in_stack(const struct Object *ob,
+ const struct GpencilModifierData *md);
+
void BKE_gpencil_lattice_init(struct Object *ob);
void BKE_gpencil_lattice_clear(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 4dc99e64cf2..3eb0ff44129 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -43,6 +43,7 @@ extern "C" {
#endif
struct Collection;
+struct BlendFileReadReport;
struct ID;
struct IDOverrideLibrary;
struct IDOverrideLibraryProperty;
@@ -90,11 +91,11 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
struct Collection *override_resync_residual_storage,
const bool do_hierarchy_enforce,
const bool do_post_process,
- struct ReportList *reports);
+ struct BlendFileReadReport *reports);
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
- struct ReportList *reports);
+ struct BlendFileReadReport *reports);
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 62837c4f2a7..8ddfb0c8eb2 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -98,7 +98,8 @@ void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_clear_geometry(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
-void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src);
+void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src);
+void BKE_mesh_copy_parameters(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -134,7 +135,10 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
-int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
+int BKE_mesh_mface_index_validate(struct MFace *mface,
+ struct CustomData *mfdata,
+ int mfindex,
+ int nr);
struct Mesh *BKE_mesh_from_object(struct Object *ob);
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
@@ -246,7 +250,6 @@ bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys);
void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys);
-void BKE_mesh_tessface_calc(struct Mesh *mesh);
void BKE_mesh_tessface_ensure(struct Mesh *mesh);
void BKE_mesh_tessface_clear(struct Mesh *mesh);
@@ -269,6 +272,32 @@ void BKE_mesh_vert_coords_apply_with_mat4(struct Mesh *mesh,
void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3]);
void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vert_normals)[3]);
+/* *** mesh_tessellate.c *** */
+
+int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
+ struct CustomData *ldata,
+ struct CustomData *pdata,
+ struct MVert *mvert,
+ int totface,
+ int totloop,
+ int totpoly,
+ const bool do_face_nor_copy);
+void BKE_mesh_tessface_calc(struct Mesh *mesh);
+
+void BKE_mesh_recalc_looptri(const struct MLoop *mloop,
+ const struct MPoly *mpoly,
+ const struct MVert *mvert,
+ int totloop,
+ int totpoly,
+ struct MLoopTri *mlooptri);
+void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
+ const struct MPoly *mpoly,
+ const struct MVert *mvert,
+ int totloop,
+ int totpoly,
+ struct MLoopTri *mlooptri,
+ const float (*poly_normals)[3]);
+
/* *** mesh_evaluate.c *** */
void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me);
@@ -508,45 +537,6 @@ void BKE_mesh_calc_volume(const struct MVert *mverts,
float r_center[3]);
/* tessface */
-void BKE_mesh_loops_to_mface_corners(struct CustomData *fdata,
- struct CustomData *ldata,
- struct CustomData *pdata,
- unsigned int lindex[4],
- int findex,
- const int polyindex,
- const int mf_len,
- const int numUV,
- const int numCol,
- const bool hasPCol,
- const bool hasOrigSpace,
- const bool hasLNor);
-void BKE_mesh_loops_to_tessdata(struct CustomData *fdata,
- struct CustomData *ldata,
- struct MFace *mface,
- 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,
- const int *polyindices,
- unsigned int (*loopindices)[4],
- const int num_faces,
- const char *layer_name);
-int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
- struct CustomData *ldata,
- struct CustomData *pdata,
- struct MVert *mvert,
- int totface,
- int totloop,
- int totpoly,
- const bool do_face_nor_copy);
-void BKE_mesh_recalc_looptri(const struct MLoop *mloop,
- const struct MPoly *mpoly,
- const struct MVert *mvert,
- int totloop,
- int totpoly,
- struct MLoopTri *mlooptri);
void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index f504650e349..dc747ba5b42 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -28,6 +28,11 @@
struct Mesh;
+namespace blender::bke {
+struct ReadAttributeLookup;
+class OutputAttribute;
+} // namespace blender::bke
+
namespace blender::bke::mesh_surface_sample {
using fn::CPPType;
@@ -35,6 +40,8 @@ using fn::GMutableSpan;
using fn::GSpan;
using fn::GVArray;
+Span<MLoopTri> get_mesh_looptris(const Mesh &mesh);
+
void sample_point_attribute(const Mesh &mesh,
Span<int> looptri_indices,
Span<float3> bary_coords,
@@ -52,4 +59,39 @@ void sample_face_attribute(const Mesh &mesh,
const GVArray &data_in,
GMutableSpan data_out);
+enum class eAttributeMapMode {
+ INTERPOLATED,
+ NEAREST,
+};
+
+/**
+ * A utility class that performs attribute interpolation from a source mesh.
+ *
+ * The interpolator is only valid as long as the mesh is valid.
+ * Barycentric weights are needed when interpolating point or corner domain attributes,
+ * these are computed lazily when needed and re-used.
+ */
+class MeshAttributeInterpolator {
+ private:
+ const Mesh *mesh_;
+ const Span<float3> positions_;
+ const Span<int> looptri_indices_;
+
+ Array<float3> bary_coords_;
+ Array<float3> nearest_weights_;
+
+ public:
+ MeshAttributeInterpolator(const Mesh *mesh,
+ const Span<float3> positions,
+ const Span<int> looptri_indices);
+
+ void sample_attribute(const ReadAttributeLookup &src_attribute,
+ OutputAttribute &dst_attribute,
+ eAttributeMapMode mode);
+
+ protected:
+ Span<float3> ensure_barycentric_coords();
+ Span<float3> ensure_nearest_weights();
+};
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 48b4540e3d9..0b4e1191956 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -324,7 +324,7 @@ typedef struct ModifierTypeInfo {
/**
* True when a deform modifier uses normals, the requiredDataMask
- * cant be used here because that refers to a normal layer whereas
+ * can't be used here because that refers to a normal layer whereas
* in this case we need to know if the deform modifier uses normals.
*
* this is needed because applying 2 deform modifiers will give the
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 5fa7d2b2a95..87140964ccb 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1434,7 +1434,12 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_LENGTH 1054
#define GEO_NODE_SELECT_BY_MATERIAL 1055
#define GEO_NODE_CONVEX_HULL 1056
-#define GEO_NODE_CURVE_DEFORM 1057
+#define GEO_NODE_CURVE_TO_POINTS 1057
+#define GEO_NODE_CURVE_REVERSE 1058
+#define GEO_NODE_SEPARATE_COMPONENTS 1059
+#define GEO_NODE_CURVE_SUBDIVIDE 1060
+#define GEO_NODE_RAYCAST 1061
+#define GEO_NODE_CURVE_DEFORM 1062
/** \} */
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index f3a5c794de8..b0b1657c162 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -337,9 +337,9 @@ bool BKE_object_obdata_texspace_get(struct Object *ob,
float **r_loc,
float **r_size);
-struct Mesh *BKE_object_get_evaluated_mesh(struct Object *object);
-struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object);
-struct Mesh *BKE_object_get_original_mesh(struct Object *object);
+struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object);
+struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
+struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
@@ -377,6 +377,7 @@ void BKE_object_runtime_reset_on_copy(struct Object *object, const int flag);
void BKE_object_runtime_free_data(struct Object *object);
void BKE_object_batch_cache_dirty_tag(struct Object *ob);
+void BKE_object_data_batch_cache_dirty_tag(struct ID *object_data);
/* this function returns a superset of the scenes selection based on relationships */
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 170eb4ba662..8731162b720 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -33,7 +33,7 @@ extern "C" {
#endif
/* Point cache clearing option, for BKE_ptcache_id_clear, before
- * and after are non inclusive (they wont remove the cfra) */
+ * and after are non-inclusive (they won't remove the cfra) */
#define PTCACHE_CLEAR_ALL 0
#define PTCACHE_CLEAR_FRAME 1
#define PTCACHE_CLEAR_BEFORE 2
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index e385f77565b..7e3783a3ee9 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -160,6 +160,8 @@ void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
bool BKE_shaderfx_depends_ontime(struct ShaderFxData *fx);
+bool BKE_shaderfx_is_nonlocal_in_liboverride(const struct Object *ob,
+ const struct ShaderFxData *shaderfx);
struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_findby_name(struct Object *ob, const char *name);
void BKE_shaderfx_copydata_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 60a9b9bb89a..8b8de115330 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -49,7 +49,7 @@ using SplinePtr = std::unique_ptr<Spline>;
* evaluation happens in a layer on top of the evaluated points generated by the derived types.
*
* There are a few methods to evaluate a spline:
- * 1. #evaluated_positions and #interpolate_to_evaluated_points give data for the initial
+ * 1. #evaluated_positions and #interpolate_to_evaluated give data for the initial
* evaluated points, depending on the resolution.
* 2. #lookup_evaluated_factor and #lookup_evaluated_factor are meant for one-off lookups
* along the length of a curve.
@@ -74,8 +74,7 @@ class Spline {
Minimum,
Tangent,
};
- /* Only #Zup is supported at the moment. */
- NormalCalculationMode normal_mode;
+ NormalCalculationMode normal_mode = Minimum;
blender::bke::CustomDataAttributes attributes;
@@ -108,9 +107,9 @@ class Spline {
copy_base_settings(other, *this);
}
- virtual SplinePtr copy() const = 0;
- /** Return a new spline with the same type and settings like "cyclic", but without any data. */
- virtual SplinePtr copy_settings() const = 0;
+ SplinePtr copy() const;
+ SplinePtr copy_only_settings() const;
+ SplinePtr copy_without_attributes() const;
Spline::Type type() const;
@@ -177,23 +176,23 @@ class Spline {
LookupResult lookup_data_from_index_factor(const float index_factor) const;
- void sample_based_on_index_factors(const blender::fn::GVArray &src,
- blender::Span<float> index_factors,
- blender::fn::GMutableSpan dst) const;
+ void sample_with_index_factors(const blender::fn::GVArray &src,
+ blender::Span<float> index_factors,
+ blender::fn::GMutableSpan dst) const;
template<typename T>
- void sample_based_on_index_factors(const blender::VArray<T> &src,
- blender::Span<float> index_factors,
- blender::MutableSpan<T> dst) const
+ void sample_with_index_factors(const blender::VArray<T> &src,
+ blender::Span<float> index_factors,
+ blender::MutableSpan<T> dst) const
{
- this->sample_based_on_index_factors(
+ this->sample_with_index_factors(
blender::fn::GVArray_For_VArray(src), index_factors, blender::fn::GMutableSpan(dst));
}
template<typename T>
- void sample_based_on_index_factors(blender::Span<T> src,
- blender::Span<float> index_factors,
- blender::MutableSpan<T> dst) const
+ void sample_with_index_factors(blender::Span<T> src,
+ blender::Span<float> index_factors,
+ blender::MutableSpan<T> dst) const
{
- this->sample_based_on_index_factors(blender::VArray_For_Span(src), index_factors, dst);
+ this->sample_with_index_factors(blender::VArray_For_Span(src), index_factors, dst);
}
/**
@@ -201,24 +200,21 @@ class Spline {
* evaluated points. For poly splines, the lifetime of the returned virtual array must not
* exceed the lifetime of the input data.
*/
- virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const = 0;
- blender::fn::GVArrayPtr interpolate_to_evaluated_points(blender::fn::GSpan data) const;
+ virtual blender::fn::GVArrayPtr interpolate_to_evaluated(
+ const blender::fn::GVArray &src) const = 0;
+ blender::fn::GVArrayPtr interpolate_to_evaluated(blender::fn::GSpan data) const;
template<typename T>
- blender::fn::GVArray_Typed<T> interpolate_to_evaluated_points(blender::Span<T> data) const
+ blender::fn::GVArray_Typed<T> interpolate_to_evaluated(blender::Span<T> data) const
{
- return blender::fn::GVArray_Typed<T>(
- this->interpolate_to_evaluated_points(blender::fn::GSpan(data)));
+ return blender::fn::GVArray_Typed<T>(this->interpolate_to_evaluated(blender::fn::GSpan(data)));
}
protected:
virtual void correct_end_tangents() const = 0;
- /** Copy settings stored in the base spline class. */
- static void copy_base_settings(const Spline &src, Spline &dst)
- {
- dst.normal_mode = src.normal_mode;
- dst.is_cyclic_ = src.is_cyclic_;
- }
+ virtual void copy_settings(Spline &dst) const = 0;
+ virtual void copy_data(Spline &dst) const = 0;
+
+ static void copy_base_settings(const Spline &src, Spline &dst);
};
/**
@@ -271,8 +267,6 @@ class BezierSpline final : public Spline {
mutable bool mapping_cache_dirty_ = true;
public:
- virtual SplinePtr copy() const final;
- SplinePtr copy_settings() const final;
BezierSpline() : Spline(Type::Bezier)
{
}
@@ -339,16 +333,19 @@ class BezierSpline final : public Spline {
};
InterpolationData interpolation_data_from_index_factor(const float index_factor) const;
- virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const override;
+ virtual blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const;
+
+ void evaluate_segment(const int index,
+ const int next_index,
+ blender::MutableSpan<blender::float3> positions) const;
+ bool segment_is_vector(const int start_index) const;
private:
- void ensure_auto_handles() const;
void correct_end_tangents() const final;
- bool segment_is_vector(const int start_index) const;
- void evaluate_bezier_segment(const int index,
- const int next_index,
- blender::MutableSpan<blender::float3> positions) const;
+ void copy_settings(Spline &dst) const final;
+ void copy_data(Spline &dst) const final;
+
+ void ensure_auto_handles() const;
};
/**
@@ -413,8 +410,6 @@ class NURBSpline final : public Spline {
mutable bool position_cache_dirty_ = true;
public:
- SplinePtr copy() const final;
- SplinePtr copy_settings() const final;
NURBSpline() : Spline(Type::NURBS)
{
}
@@ -461,13 +456,15 @@ class NURBSpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
- blender::fn::GVArrayPtr interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const final;
+ blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
protected:
void correct_end_tangents() const final;
+ void copy_settings(Spline &dst) const final;
+ void copy_data(Spline &dst) const final;
+
void calculate_knots() const;
- void calculate_basis_cache() const;
+ blender::Span<BasisCache> calculate_basis_cache() const;
};
/**
@@ -481,8 +478,6 @@ class PolySpline final : public Spline {
blender::Vector<float> tilts_;
public:
- SplinePtr copy() const final;
- SplinePtr copy_settings() const final;
PolySpline() : Spline(Type::Poly)
{
}
@@ -511,11 +506,12 @@ class PolySpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
- blender::fn::GVArrayPtr interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const final;
+ blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
protected:
void correct_end_tangents() const final;
+ void copy_settings(Spline &dst) const final;
+ void copy_data(Spline &dst) const final;
};
/**
@@ -540,6 +536,7 @@ struct CurveEval {
blender::Span<SplinePtr> splines() const;
blender::MutableSpan<SplinePtr> splines();
+ void resize(const int size);
void add_spline(SplinePtr spline);
void remove_splines(blender::IndexMask mask);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 021d7e15814..0f36887b234 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -194,6 +194,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_sample.cc
intern/mesh_tangent.c
+ intern/mesh_tessellate.c
intern/mesh_validate.c
intern/mesh_validate.cc
intern/mesh_wrapper.c
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index d4dd7e248d5..6caed3936d4 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -42,6 +42,7 @@
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_task.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
@@ -962,7 +963,7 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
/* Return an empty mesh instead of null. */
if (mesh_output == nullptr) {
mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
- BKE_mesh_copy_settings(mesh_output, input_mesh);
+ BKE_mesh_copy_parameters_for_eval(mesh_output, input_mesh);
}
}
@@ -1463,10 +1464,14 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BLI_assert(runtime->eval_mutex != nullptr);
BLI_mutex_lock((ThreadMutex *)runtime->eval_mutex);
if (runtime->mesh_eval == nullptr) {
- mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
- mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
- mesh_calc_finalize(mesh_input, mesh_final);
- runtime->mesh_eval = mesh_final;
+ /* Isolate since computing normals is multithreaded and we are holding a lock. */
+ blender::threading::isolate_task([&] {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ mesh_calc_modifier_final_normals(
+ mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
+ mesh_calc_finalize(mesh_input, mesh_final);
+ runtime->mesh_eval = mesh_final;
+ });
}
BLI_mutex_unlock((ThreadMutex *)runtime->eval_mutex);
}
@@ -1567,7 +1572,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
/* BMESH_ONLY, ensure tessface's used for drawing,
* but don't recalculate if the last modifier in the stack gives us tessfaces
* check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential
- * but quiets annoying error messages since tessfaces wont be created. */
+ * but quiets annoying error messages since tessfaces won't be created. */
if (final_datamask->fmask & CD_MASK_MFACE) {
if (mesh_final->edit_mesh == nullptr) {
BKE_mesh_tessface_ensure(mesh_final);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index a7e36b09516..71d242e9c79 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -665,8 +665,8 @@ bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
- chan->scale_in_x = chan->scale_in_y = 1.0f;
- chan->scale_out_x = chan->scale_out_y = 1.0f;
+ copy_v3_fl(chan->scale_in, 1.0f);
+ copy_v3_fl(chan->scale_out, 1.0f);
chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
@@ -846,8 +846,9 @@ void BKE_pose_copy_data_ex(bPose **dst,
}
if (copy_constraints) {
- BKE_constraints_copy_ex(
- &listb, &pchan->constraints, flag, true); /* BKE_constraints_copy NULLs listb */
+ /* #BKE_constraints_copy NULL's `listb` */
+ BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true);
+
pchan->constraints = listb;
/* XXX: This is needed for motionpath drawing to work.
@@ -1659,11 +1660,12 @@ void BKE_pose_rest(bPose *pose, bool selected_bones_only)
pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
pchan->roll1 = pchan->roll2 = 0.0f;
- pchan->curve_in_x = pchan->curve_in_y = 0.0f;
- pchan->curve_out_x = pchan->curve_out_y = 0.0f;
+ pchan->curve_in_x = pchan->curve_in_z = 0.0f;
+ pchan->curve_out_x = pchan->curve_out_z = 0.0f;
pchan->ease1 = pchan->ease2 = 0.0f;
- pchan->scale_in_x = pchan->scale_in_y = 1.0f;
- pchan->scale_out_x = pchan->scale_out_y = 1.0f;
+
+ copy_v3_fl(pchan->scale_in, 1.0f);
+ copy_v3_fl(pchan->scale_out, 1.0f);
pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
}
@@ -1686,15 +1688,14 @@ void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchan
pchanto->roll1 = pchanfrom->roll1;
pchanto->roll2 = pchanfrom->roll2;
pchanto->curve_in_x = pchanfrom->curve_in_x;
- pchanto->curve_in_y = pchanfrom->curve_in_y;
+ pchanto->curve_in_z = pchanfrom->curve_in_z;
pchanto->curve_out_x = pchanfrom->curve_out_x;
- pchanto->curve_out_y = pchanfrom->curve_out_y;
+ pchanto->curve_out_z = pchanfrom->curve_out_z;
pchanto->ease1 = pchanfrom->ease1;
pchanto->ease2 = pchanfrom->ease2;
- pchanto->scale_in_x = pchanfrom->scale_in_x;
- pchanto->scale_in_y = pchanfrom->scale_in_y;
- pchanto->scale_out_x = pchanfrom->scale_out_x;
- pchanto->scale_out_y = pchanfrom->scale_out_y;
+
+ copy_v3_v3(pchanto->scale_in, pchanfrom->scale_in);
+ copy_v3_v3(pchanto->scale_out, pchanfrom->scale_out);
pchanto->rotmode = pchanfrom->rotmode;
pchanto->flag = pchanfrom->flag;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 4ea71922df5..a57e1d6b2dd 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -853,6 +853,7 @@ bool bone_autoside_name(
static void equalize_cubic_bezier(const float control[4][3],
int temp_segments,
int final_segments,
+ const float *segment_scales,
float *r_t_points)
{
float(*coords)[3] = BLI_array_alloca(coords, temp_segments + 1);
@@ -877,12 +878,19 @@ static void equalize_cubic_bezier(const float control[4][3],
}
/* Go over distances and calculate new parameter values. */
- float dist_step = pdist[temp_segments] / final_segments;
+ float dist_step = pdist[temp_segments];
+ float dist = 0, sum = 0;
+
+ for (int i = 0; i < final_segments; i++) {
+ sum += segment_scales[i];
+ }
+
+ dist_step /= sum;
r_t_points[0] = 0.0f;
for (int i = 1, nr = 1; i <= final_segments; i++) {
- float dist = i * dist_step;
+ dist += segment_scales[i - 1] * dist_step;
/* We're looking for location (distance) 'dist' in the array. */
while ((nr < temp_segments) && (dist >= pdist[nr])) {
@@ -951,7 +959,7 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float imat[4][4], posemat[4][4];
+ float imat[4][4], posemat[4][4], tmpmat[4][4];
float delta[3];
memset(param, 0, sizeof(*param));
@@ -988,6 +996,11 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
invert_m4_m4(imat, pchan->pose_mat);
}
+ float prev_scale[3], next_scale[3];
+
+ copy_v3_fl(prev_scale, 1.0f);
+ copy_v3_fl(next_scale, 1.0f);
+
if (prev) {
float h1[3];
bool done = false;
@@ -1033,6 +1046,12 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
if (!param->prev_bbone) {
/* Find the previous roll to interpolate. */
mul_m4_m4m4(param->prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
+
+ /* Retrieve the local scale of the bone if necessary. */
+ if ((bone->bbone_prev_flag & BBONE_HANDLE_SCALE_ANY) && !rest) {
+ BKE_armature_mat_pose_to_bone(prev, prev->pose_mat, tmpmat);
+ mat4_to_size(prev_scale, tmpmat);
+ }
}
}
@@ -1080,6 +1099,12 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
/* Find the next roll to interpolate as well. */
mul_m4_m4m4(param->next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
+
+ /* Retrieve the local scale of the bone if necessary. */
+ if ((bone->bbone_next_flag & BBONE_HANDLE_SCALE_ANY) && !rest) {
+ BKE_armature_mat_pose_to_bone(next, next->pose_mat, tmpmat);
+ mat4_to_size(next_scale, tmpmat);
+ }
}
/* Add effects from bbone properties over the top
@@ -1103,7 +1128,7 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
param->roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
param->roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
- if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (bone->bbone_flag & BBONE_ADD_PARENT_END_ROLL) {
if (prev) {
if (prev->bone) {
param->roll1 += prev->bone->roll2;
@@ -1115,17 +1140,61 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
}
}
- param->scale_in_x = bone->scale_in_x * (!rest ? pchan->scale_in_x : 1.0f);
- param->scale_in_y = bone->scale_in_y * (!rest ? pchan->scale_in_y : 1.0f);
- param->scale_out_x = bone->scale_out_x * (!rest ? pchan->scale_out_x : 1.0f);
- param->scale_out_y = bone->scale_out_y * (!rest ? pchan->scale_out_y : 1.0f);
+ copy_v3_v3(param->scale_in, bone->scale_in);
+ copy_v3_v3(param->scale_out, bone->scale_out);
- /* Extra curve x / y */
+ if (!rest) {
+ mul_v3_v3(param->scale_in, pchan->scale_in);
+ mul_v3_v3(param->scale_out, pchan->scale_out);
+ }
+
+ /* Extra curve x / z */
param->curve_in_x = bone->curve_in_x + (!rest ? pchan->curve_in_x : 0.0f);
- param->curve_in_y = bone->curve_in_y + (!rest ? pchan->curve_in_y : 0.0f);
+ param->curve_in_z = bone->curve_in_z + (!rest ? pchan->curve_in_z : 0.0f);
param->curve_out_x = bone->curve_out_x + (!rest ? pchan->curve_out_x : 0.0f);
- param->curve_out_y = bone->curve_out_y + (!rest ? pchan->curve_out_y : 0.0f);
+ param->curve_out_z = bone->curve_out_z + (!rest ? pchan->curve_out_z : 0.0f);
+
+ if (bone->bbone_flag & BBONE_SCALE_EASING) {
+ param->ease1 *= param->scale_in[1];
+ param->curve_in_x *= param->scale_in[1];
+ param->curve_in_z *= param->scale_in[1];
+
+ param->ease2 *= param->scale_out[1];
+ param->curve_out_x *= param->scale_out[1];
+ param->curve_out_z *= param->scale_out[1];
+ }
+
+ /* Custom handle scale. */
+ if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_X) {
+ param->scale_in[0] *= prev_scale[0];
+ }
+ if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_Y) {
+ param->scale_in[1] *= prev_scale[1];
+ }
+ if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_Z) {
+ param->scale_in[2] *= prev_scale[2];
+ }
+ if (bone->bbone_prev_flag & BBONE_HANDLE_SCALE_EASE) {
+ param->ease1 *= prev_scale[1];
+ param->curve_in_x *= prev_scale[1];
+ param->curve_in_z *= prev_scale[1];
+ }
+
+ if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_X) {
+ param->scale_out[0] *= next_scale[0];
+ }
+ if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_Y) {
+ param->scale_out[1] *= next_scale[1];
+ }
+ if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_Z) {
+ param->scale_out[2] *= next_scale[2];
+ }
+ if (bone->bbone_next_flag & BBONE_HANDLE_SCALE_EASE) {
+ param->ease2 *= next_scale[1];
+ param->curve_out_x *= next_scale[1];
+ param->curve_out_z *= next_scale[1];
+ }
}
}
@@ -1250,13 +1319,13 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
* in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
*/
const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f;
- const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
+ const float zscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
h1[0] += param->curve_in_x * xscale_correction;
- h1[2] += param->curve_in_y * yscale_correction;
+ h1[2] += param->curve_in_z * zscale_correction;
h2[0] += param->curve_out_x * xscale_correction;
- h2[2] += param->curve_out_y * yscale_correction;
+ h2[2] += param->curve_out_z * zscale_correction;
}
}
@@ -1266,7 +1335,7 @@ static void make_bbone_spline_matrix(BBoneSplineParameters *param,
const float axis[3],
float roll,
float scalex,
- float scaley,
+ float scalez,
float result[4][4])
{
float mat3[3][3];
@@ -1283,7 +1352,7 @@ static void make_bbone_spline_matrix(BBoneSplineParameters *param,
/* BBone scale... */
mul_v3_fl(result[0], scalex);
- mul_v3_fl(result[2], scaley);
+ mul_v3_fl(result[2], scalez);
}
/* Fade from first to second derivative when the handle is very short. */
@@ -1329,9 +1398,25 @@ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
copy_v3_v3(bezt_controls[1], h1);
zero_v3(bezt_controls[0]);
+ /* Compute lengthwise segment scale. */
+ float segment_scales[MAX_BBONE_SUBDIV];
+
+ CLAMP_MIN(param->scale_in[1], 0.0001f);
+ CLAMP_MIN(param->scale_out[1], 0.0001f);
+
+ const float log_scale_in_len = logf(param->scale_in[1]);
+ const float log_scale_out_len = logf(param->scale_out[1]);
+
+ for (int i = 0; i < param->segments; i++) {
+ const float fac = ((float)i) / (param->segments - 1);
+ segment_scales[i] = expf(interpf(log_scale_out_len, log_scale_in_len, fac));
+ }
+
+ /* Compute segment vertex offsets along the curve length. */
float bezt_points[MAX_BBONE_SUBDIV + 1];
- equalize_cubic_bezier(bezt_controls, MAX_BBONE_SUBDIV, param->segments, bezt_points);
+ equalize_cubic_bezier(
+ bezt_controls, MAX_BBONE_SUBDIV, param->segments, segment_scales, bezt_points);
/* Deformation uses N+1 matrices computed at points between the segments. */
if (for_deform) {
@@ -1352,8 +1437,8 @@ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
bezt_controls[0],
axis,
roll1,
- param->scale_in_x,
- param->scale_in_y,
+ param->scale_in[0],
+ param->scale_in[2],
result_array[0].mat);
for (int a = 1; a < param->segments; a++) {
@@ -1361,11 +1446,11 @@ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
float fac = ((float)a) / param->segments;
float roll = interpf(roll2, roll1, fac);
- float scalex = interpf(param->scale_out_x, param->scale_in_x, fac);
- float scaley = interpf(param->scale_out_y, param->scale_in_y, fac);
+ float scalex = interpf(param->scale_out[0], param->scale_in[0], fac);
+ float scalez = interpf(param->scale_out[2], param->scale_in[2], fac);
make_bbone_spline_matrix(
- param, scalemats, cur, axis, roll, scalex, scaley, result_array[a].mat);
+ param, scalemats, cur, axis, roll, scalex, scalez, result_array[a].mat);
}
negate_v3(bezt_deriv2[1]);
@@ -1375,8 +1460,8 @@ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
bezt_controls[3],
axis,
roll2,
- param->scale_out_x,
- param->scale_out_y,
+ param->scale_out[0],
+ param->scale_out[2],
result_array[param->segments].mat);
}
/* Other code (e.g. display) uses matrices for the segments themselves. */
@@ -1390,11 +1475,11 @@ int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
float fac = (a + 0.5f) / param->segments;
float roll = interpf(roll2, roll1, fac);
- float scalex = interpf(param->scale_out_x, param->scale_in_x, fac);
- float scaley = interpf(param->scale_out_y, param->scale_in_y, fac);
+ float scalex = interpf(param->scale_out[0], param->scale_in[0], fac);
+ float scalez = interpf(param->scale_out[2], param->scale_in[2], fac);
make_bbone_spline_matrix(
- param, scalemats, prev, axis, roll, scalex, scaley, result_array[a].mat);
+ param, scalemats, prev, axis, roll, scalex, scalez, result_array[a].mat);
copy_v3_v3(prev, cur);
}
}
@@ -2296,7 +2381,7 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
return;
}
- /* in some cases when rigs change, we cant synchronize
+ /* in some cases when rigs change, we can't synchronize
* to avoid crashing check for possible errors here */
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone->layer & layer_protected) {
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index ec8962d5f6d..c8fedc086b8 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -87,7 +87,7 @@ bool BKE_copybuffer_read(Main *bmain_dst,
ReportList *reports,
const uint64_t id_types_mask)
{
- BlendHandle *bh = BLO_blendhandle_from_file(libname, reports);
+ BlendHandle *bh = BLO_blendhandle_from_file(libname, &(BlendFileReadReport){.reports = reports});
if (bh == NULL) {
/* Error reports will have been made by BLO_blendhandle_from_file(). */
return false;
@@ -106,7 +106,7 @@ bool BKE_copybuffer_read(Main *bmain_dst,
/* Append, rather than linking. */
Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath_abs));
BKE_library_make_local(bmain_dst, lib, NULL, true, false);
- /* Important we unset, otherwise these object wont
+ /* Important we unset, otherwise these object won't
* link into other scenes from this blend file.
*/
BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
@@ -133,7 +133,7 @@ int BKE_copybuffer_paste(bContext *C,
BlendHandle *bh;
const int id_tag_extra = 0;
- bh = BLO_blendhandle_from_file(libname, reports);
+ bh = BLO_blendhandle_from_file(libname, &(BlendFileReadReport){.reports = reports});
if (bh == NULL) {
/* error reports will have been made by BLO_blendhandle_from_file() */
@@ -166,7 +166,7 @@ int BKE_copybuffer_paste(bContext *C,
lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath_abs));
BKE_library_make_local(bmain, lib, NULL, true, false);
- /* important we unset, otherwise these object wont
+ /* important we unset, otherwise these object won't
* link into other scenes from this blend file */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 02076823675..6f47cd1336e 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -78,9 +78,10 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
if (UNDO_DISK) {
const struct BlendFileReadParams params = {0};
- struct BlendFileData *bfd = BKE_blendfile_read(mfu->filename, &params, NULL);
+ struct BlendFileData *bfd = BKE_blendfile_read(
+ mfu->filename, &params, &(BlendFileReadReport){NULL});
if (bfd != NULL) {
- BKE_blendfile_read_setup(C, bfd, &params, NULL);
+ BKE_blendfile_read_setup(C, bfd, &params, &(BlendFileReadReport){NULL});
success = true;
}
}
@@ -93,7 +94,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
struct BlendFileData *bfd = BKE_blendfile_read_from_memfile(
bmain, &mfu->memfile, &params, NULL);
if (bfd != NULL) {
- BKE_blendfile_read_setup(C, bfd, &params, NULL);
+ BKE_blendfile_read_setup(C, bfd, &params, &(BlendFileReadReport){NULL});
success = true;
}
}
@@ -105,7 +106,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
if (success) {
/* important not to update time here, else non keyed transforms are lost */
- DEG_on_visible_update(bmain, false);
+ DEG_tag_on_visible_update(bmain, false);
}
return success;
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 54fd3f55c31..9ea1c8fedda 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -36,6 +36,8 @@
#include "BLI_system.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "IMB_colormanagement.h"
#include "BKE_addon.h"
@@ -136,7 +138,7 @@ static void setup_app_userdef(BlendFileData *bfd)
static void setup_app_data(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
Main *bmain = G_MAIN;
Scene *curscene = NULL;
@@ -155,7 +157,7 @@ static void setup_app_data(bContext *C,
/* may happen with library files - UNDO file should never have NULL curscene (but may have a
* NULL curscreen)... */
else if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
- BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
+ BKE_report(reports->reports, RPT_WARNING, "Library file, loading empty scene");
mode = LOAD_UI_OFF;
}
else if (G.fileflags & G_FILE_NO_UI) {
@@ -269,7 +271,7 @@ static void setup_app_data(bContext *C,
}
/* We need to tag this here because events may be handled immediately after.
- * only the current screen is important because we wont have to handle
+ * only the current screen is important because we won't have to handle
* events from multiple screens at once.*/
if (curscreen) {
BKE_screen_gizmo_tag_refresh(curscreen);
@@ -396,11 +398,17 @@ static void setup_app_data(bContext *C,
}
if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
+ reports->duration.lib_overrides_resync = PIL_check_seconds_timer();
+
BKE_lib_override_library_main_resync(
bmain,
curscene,
bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene),
reports);
+
+ reports->duration.lib_overrides_resync = PIL_check_seconds_timer() -
+ reports->duration.lib_overrides_resync;
+
/* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
BKE_lib_override_library_main_operations_create(bmain, true);
}
@@ -409,7 +417,7 @@ static void setup_app_data(bContext *C,
static void setup_app_blend_file_data(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
if ((params->skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
setup_app_userdef(bfd);
@@ -419,12 +427,12 @@ static void setup_app_blend_file_data(bContext *C,
}
}
-static void handle_subversion_warning(Main *main, ReportList *reports)
+static void handle_subversion_warning(Main *main, BlendFileReadReport *reports)
{
if (main->minversionfile > BLENDER_FILE_VERSION ||
(main->minversionfile == BLENDER_FILE_VERSION &&
main->minsubversionfile > BLENDER_FILE_SUBVERSION)) {
- BKE_reportf(reports,
+ BKE_reportf(reports->reports,
RPT_ERROR,
"File written by newer Blender binary (%d.%d), expect loss of data!",
main->minversionfile,
@@ -443,7 +451,7 @@ static void handle_subversion_warning(Main *main, ReportList *reports)
void BKE_blendfile_read_setup_ex(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
- ReportList *reports,
+ BlendFileReadReport *reports,
/* Extra args. */
const bool startup_update_defaults,
const char *startup_app_template)
@@ -460,7 +468,7 @@ void BKE_blendfile_read_setup_ex(bContext *C,
void BKE_blendfile_read_setup(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL);
}
@@ -470,7 +478,7 @@ void BKE_blendfile_read_setup(bContext *C,
*/
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
/* Don't print startup file loading. */
if (params->is_startup == false) {
@@ -482,7 +490,7 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath,
handle_subversion_warning(bfd->main, reports);
}
else {
- BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
+ BKE_reports_prependf(reports->reports, "Loading '%s' failed: ", filepath);
}
return bfd;
}
@@ -559,7 +567,9 @@ UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
BlendFileData *bfd;
UserDef *userdef = NULL;
- bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
+ bfd = BLO_read_from_file(filepath,
+ BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF,
+ &(struct BlendFileReadReport){.reports = reports});
if (bfd) {
if (bfd->user) {
userdef = bfd->user;
@@ -770,7 +780,8 @@ WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepat
WorkspaceConfigFileData *workspace_config = NULL;
if (filepath) {
- bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_USERDEF, reports);
+ bfd = BLO_read_from_file(
+ filepath, BLO_READ_SKIP_USERDEF, &(struct BlendFileReadReport){.reports = reports});
}
else {
bfd = BLO_read_from_memory(filebuf, filelength, BLO_READ_SKIP_USERDEF, reports);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 47427beccba..f26a9f06697 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -345,7 +345,7 @@ static bool missing_files_find__recursive(char *filename_new,
BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
if (BLI_stat(path, &status) == -1) {
- continue; /* cant stat, don't bother with this file, could print debug info here */
+ continue; /* can't stat, don't bother with this file, could print debug info here */
}
if (S_ISREG(status.st_mode)) { /* is file */
@@ -812,7 +812,7 @@ bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pa
if (BLI_path_abs(filepath, base_old)) {
/* Path was relative and is now absolute. Remap.
* Important BLI_path_normalize runs before the path is made relative
- * because it wont work for paths that start with "//../" */
+ * because it won't work for paths that start with "//../" */
BLI_path_normalize(base_new, filepath);
BLI_path_rel(filepath, base_new);
BLI_strncpy(path_dst, filepath, FILE_MAX);
@@ -850,7 +850,7 @@ static bool bpath_list_append(void *userdata, char *UNUSED(path_dst), const char
static bool bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
{
- /* assume ls->first wont be NULL because the number of paths can't change!
+ /* assume ls->first won't be NULL because the number of paths can't change!
* (if they do caller is wrong) */
ListBase *ls = userdata;
struct PathStore *path_store = ls->first;
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index bc63e423c09..116e6279657 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -31,6 +31,7 @@
#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -160,6 +161,26 @@ void bvhcache_free(BVHCache *bvh_cache)
MEM_freeN(bvh_cache);
}
+/* BVH tree balancing inside a mutex lock must be run in isolation. Balancing
+ * is multithreaded, and we do not want the current thread to start another task
+ * that may involve acquiring the same mutex lock that it is waiting for. */
+static void bvhtree_balance_isolated(void *userdata)
+{
+ BLI_bvhtree_balance((BVHTree *)userdata);
+}
+
+static void bvhtree_balance(BVHTree *tree, const bool isolate)
+{
+ if (tree) {
+ if (isolate) {
+ BLI_task_isolate(bvhtree_balance_isolated, tree);
+ }
+ else {
+ BLI_bvhtree_balance(tree);
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
@@ -566,7 +587,6 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
BLI_bvhtree_insert(tree, i, eve->co, 1);
}
BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -600,7 +620,6 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
}
}
@@ -649,6 +668,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
if (data->cached == false) {
tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis, em, verts_mask, verts_num_active);
+ bvhtree_balance(tree, true);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
@@ -660,6 +680,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
else {
tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis, em, verts_mask, verts_num_active);
+ bvhtree_balance(tree, false);
}
if (tree) {
@@ -711,6 +732,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
if (in_cache == false) {
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
+ bvhtree_balance(tree, bvh_cache_p != NULL);
if (bvh_cache_p) {
/* Save on cache for later use */
@@ -771,7 +793,6 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
BLI_bvhtree_insert(tree, i, co[0], 2);
}
BLI_assert(BLI_bvhtree_get_len(tree) == edges_num_active);
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -809,7 +830,6 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const MVert *vert,
BLI_bvhtree_insert(tree, i, co[0], 2);
}
- BLI_bvhtree_balance(tree);
}
}
@@ -861,7 +881,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
if (data->cached == false) {
tree = bvhtree_from_editmesh_edges_create_tree(
epsilon, tree_type, axis, em, edges_mask, edges_num_active);
-
+ bvhtree_balance(tree, true);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
@@ -872,6 +892,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
else {
tree = bvhtree_from_editmesh_edges_create_tree(
epsilon, tree_type, axis, em, edges_mask, edges_num_active);
+ bvhtree_balance(tree, false);
}
if (tree) {
@@ -928,12 +949,17 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
if (bvh_cache_p) {
+ bvhtree_balance(tree, true);
+
BVHCache *bvh_cache = *bvh_cache_p;
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
in_cache = true;
}
+ else {
+ bvhtree_balance(tree, false);
+ }
}
if (bvh_cache_p) {
@@ -994,7 +1020,6 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
}
}
BLI_assert(BLI_bvhtree_get_len(tree) == faces_num_active);
- BLI_bvhtree_balance(tree);
}
}
@@ -1057,6 +1082,7 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
if (in_cache == false) {
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
+ bvhtree_balance(tree, bvh_cache_p != NULL);
if (bvh_cache_p) {
/* Save on cache for later use */
@@ -1127,7 +1153,6 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
}
}
BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
- BLI_bvhtree_balance(tree);
}
}
@@ -1173,7 +1198,6 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
}
}
BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
- BLI_bvhtree_balance(tree);
}
}
@@ -1229,6 +1253,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
bool in_cache = bvhcache_find(
bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
BVHCache *bvh_cache = *bvh_cache_p;
+ bvhtree_balance(tree, true);
if (in_cache == false) {
tree = bvhtree_from_editmesh_looptri_create_tree(
@@ -1243,6 +1268,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
else {
tree = bvhtree_from_editmesh_looptri_create_tree(
epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
+ bvhtree_balance(tree, false);
}
if (tree) {
@@ -1303,6 +1329,8 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
looptri_mask,
looptri_num_active);
+ bvhtree_balance(tree, bvh_cache_p != NULL);
+
if (bvh_cache_p) {
BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
@@ -1742,7 +1770,7 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
BLI_bvhtree_insert(tree, i, pointcloud->co[i], 1);
}
BLI_assert(BLI_bvhtree_get_len(tree) == pointcloud->totpoint);
- BLI_bvhtree_balance(tree);
+ bvhtree_balance(tree, false);
data->coords = pointcloud->co;
data->tree = tree;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index feae033337d..30e9ae39b67 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -198,6 +198,9 @@ void BKE_cachefile_reader_open(CacheFile *cache_file,
void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reader)
{
#ifdef WITH_ALEMBIC
+ /* Multiple modifiers and constraints can call this function concurrently, and
+ * cachefile_handle_free() can also be called at the same time. */
+ BLI_spin_lock(&spin);
if (*reader != NULL) {
if (cache_file) {
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
@@ -206,13 +209,11 @@ void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reade
CacheReader_free(*reader);
*reader = NULL;
- /* Multiple modifiers and constraints can call this function concurrently. */
- BLI_spin_lock(&spin);
if (cache_file && cache_file->handle_readers) {
BLI_gset_remove(cache_file->handle_readers, reader, NULL);
}
- BLI_spin_unlock(&spin);
}
+ BLI_spin_unlock(&spin);
#else
UNUSED_VARS(cache_file, reader);
#endif
diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c
index 10c6d2213ff..7deac4e4f19 100644
--- a/source/blender/blenkernel/intern/curve_deform.c
+++ b/source/blender/blenkernel/intern/curve_deform.c
@@ -173,12 +173,10 @@ static bool calc_curve_deform(
copy_qt_qt(quat, new_quat);
copy_v3_v3(cent, co);
- /* zero the axis which is not used,
- * the big block of text above now applies to these 3 lines */
- quat_apply_track(quat,
- axis,
- (ELEM(axis, 0, 2)) ? 1 :
- 0); /* up flag is a dummy, set so no rotation is done */
+ /* Zero the axis which is not used,
+ * the big block of text above now applies to these 3 lines.
+ * The `upflag` argument may be a dummy, set so no rotation is done. */
+ quat_apply_track(quat, axis, (ELEM(axis, 0, 2)) ? 1 : 0);
vec_apply_track(cent, axis);
cent[index] = 0.0f;
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 9cafe1124b1..0a6e4458a35 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -15,10 +15,13 @@
*/
#include "BLI_array.hh"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
#include "DNA_curve_types.h"
@@ -28,9 +31,12 @@
using blender::Array;
using blender::float3;
using blender::float4x4;
+using blender::IndexRange;
using blender::Map;
+using blender::MutableSpan;
using blender::Span;
using blender::StringRefNull;
+using blender::Vector;
blender::Span<SplinePtr> CurveEval::splines() const
{
@@ -42,6 +48,12 @@ blender::MutableSpan<SplinePtr> CurveEval::splines()
return splines_;
}
+void CurveEval::resize(const int size)
+{
+ splines_.resize(size);
+ attributes.reallocate(size);
+}
+
/**
* \warning Call #reallocate on the spline's attributes after adding all splines.
*/
@@ -162,70 +174,118 @@ static NURBSpline::KnotsMode knots_mode_from_dna_nurb(const short flag)
return NURBSpline::KnotsMode::Normal;
}
+static SplinePtr spline_from_dna_bezier(const Nurb &nurb)
+{
+ std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
+ spline->set_resolution(nurb.resolu);
+ spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
+
+ Span<const BezTriple> src_points{nurb.bezt, nurb.pntsu};
+ spline->resize(src_points.size());
+ MutableSpan<float3> positions = spline->positions();
+ MutableSpan<float3> handle_positions_left = spline->handle_positions_left();
+ MutableSpan<float3> handle_positions_right = spline->handle_positions_right();
+ MutableSpan<BezierSpline::HandleType> handle_types_left = spline->handle_types_left();
+ MutableSpan<BezierSpline::HandleType> handle_types_right = spline->handle_types_right();
+ MutableSpan<float> radii = spline->radii();
+ MutableSpan<float> tilts = spline->tilts();
+
+ blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ const BezTriple &bezt = src_points[i];
+ positions[i] = bezt.vec[1];
+ handle_positions_left[i] = bezt.vec[0];
+ handle_types_left[i] = handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h1);
+ handle_positions_right[i] = bezt.vec[2];
+ handle_types_right[i] = handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h2);
+ radii[i] = bezt.radius;
+ tilts[i] = bezt.tilt;
+ }
+ });
+
+ return spline;
+}
+
+static SplinePtr spline_from_dna_nurbs(const Nurb &nurb)
+{
+ std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
+ spline->set_resolution(nurb.resolu);
+ spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
+ spline->set_order(nurb.orderu);
+ spline->knots_mode = knots_mode_from_dna_nurb(nurb.flagu);
+
+ Span<const BPoint> src_points{nurb.bp, nurb.pntsu};
+ spline->resize(src_points.size());
+ MutableSpan<float3> positions = spline->positions();
+ MutableSpan<float> weights = spline->weights();
+ MutableSpan<float> radii = spline->radii();
+ MutableSpan<float> tilts = spline->tilts();
+
+ blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ const BPoint &bp = src_points[i];
+ positions[i] = bp.vec;
+ weights[i] = bp.vec[3];
+ radii[i] = bp.radius;
+ tilts[i] = bp.tilt;
+ }
+ });
+
+ return spline;
+}
+
+static SplinePtr spline_from_dna_poly(const Nurb &nurb)
+{
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
+
+ Span<const BPoint> src_points{nurb.bp, nurb.pntsu};
+ spline->resize(src_points.size());
+ MutableSpan<float3> positions = spline->positions();
+ MutableSpan<float> radii = spline->radii();
+ MutableSpan<float> tilts = spline->tilts();
+
+ blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ const BPoint &bp = src_points[i];
+ positions[i] = bp.vec;
+ radii[i] = bp.radius;
+ tilts[i] = bp.tilt;
+ }
+ });
+
+ return spline;
+}
+
std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
{
+ Vector<const Nurb *> nurbs(*BKE_curve_nurbs_get(&const_cast<Curve &>(dna_curve)));
+
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ curve->resize(nurbs.size());
+ MutableSpan<SplinePtr> splines = curve->splines();
- const ListBase *nurbs = BKE_curve_nurbs_get(&const_cast<Curve &>(dna_curve));
-
- /* TODO: Optimize by reserving the correct points size. */
- LISTBASE_FOREACH (const Nurb *, nurb, nurbs) {
- switch (nurb->type) {
- case CU_BEZIER: {
- std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
- spline->set_resolution(nurb->resolu);
- spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
-
- for (const BezTriple &bezt : Span(nurb->bezt, nurb->pntsu)) {
- spline->add_point(bezt.vec[1],
- handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h1),
- bezt.vec[0],
- handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h2),
- bezt.vec[2],
- bezt.radius,
- bezt.tilt);
- }
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- break;
- }
- case CU_NURBS: {
- std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
- spline->set_resolution(nurb->resolu);
- spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
- spline->set_order(nurb->orderu);
- spline->knots_mode = knots_mode_from_dna_nurb(nurb->flagu);
-
- for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
- spline->add_point(bp.vec, bp.radius, bp.tilt, bp.vec[3]);
- }
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- break;
- }
- case CU_POLY: {
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
-
- for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
- spline->add_point(bp.vec, bp.radius, bp.tilt);
- }
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- break;
- }
- default: {
- BLI_assert_unreachable();
- break;
+ blender::threading::parallel_for(nurbs.index_range(), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ switch (nurbs[i]->type) {
+ case CU_BEZIER:
+ splines[i] = spline_from_dna_bezier(*nurbs[i]);
+ break;
+ case CU_NURBS:
+ splines[i] = spline_from_dna_nurbs(*nurbs[i]);
+ break;
+ case CU_POLY:
+ splines[i] = spline_from_dna_poly(*nurbs[i]);
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
}
}
- }
-
- /* Though the curve has no attributes, this is necessary to properly set the custom data size. */
- curve->attributes.reallocate(curve->splines().size());
+ });
- /* Note: Normal mode is stored separately in each spline to facilitate combining splines
- * from multiple curve objects, where the value may be different. */
+ /* Normal mode is stored separately in each spline to facilitate combining
+ * splines from multiple curve objects, where the value may be different. */
const Spline::NormalCalculationMode normal_mode = normal_mode_from_dna_curve(
dna_curve.twist_mode);
for (SplinePtr &spline : curve->splines()) {
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 710dfdaf137..b1bb8b9715e 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1970,7 +1970,7 @@ const CustomData_MeshMasks CD_MASK_BMESH = {
CD_MASK_SCULPT_FACE_SETS),
};
/**
- * cover values copied by #BKE_mesh_loops_to_tessdata
+ * cover values copied by #mesh_loops_to_tessdata
*/
const CustomData_MeshMasks CD_MASK_FACECORNERS = {
.vmask = 0,
@@ -2020,35 +2020,35 @@ static const char *layerType_getName(int type)
void customData_mask_layers__print(const CustomData_MeshMasks *mask)
{
- printf("verts mask=0x%lx:\n", (long unsigned int)mask->vmask);
+ printf("verts mask=0x%" PRIx64 ":\n", mask->vmask);
for (int i = 0; i < CD_NUMTYPES; i++) {
if (mask->vmask & CD_TYPE_AS_MASK(i)) {
printf(" %s\n", layerType_getName(i));
}
}
- printf("edges mask=0x%lx:\n", (long unsigned int)mask->emask);
+ printf("edges mask=0x%" PRIx64 ":\n", mask->emask);
for (int i = 0; i < CD_NUMTYPES; i++) {
if (mask->emask & CD_TYPE_AS_MASK(i)) {
printf(" %s\n", layerType_getName(i));
}
}
- printf("faces mask=0x%lx:\n", (long unsigned int)mask->fmask);
+ printf("faces mask=0x%" PRIx64 ":\n", mask->fmask);
for (int i = 0; i < CD_NUMTYPES; i++) {
if (mask->fmask & CD_TYPE_AS_MASK(i)) {
printf(" %s\n", layerType_getName(i));
}
}
- printf("loops mask=0x%lx:\n", (long unsigned int)mask->lmask);
+ printf("loops mask=0x%" PRIx64 ":\n", mask->lmask);
for (int i = 0; i < CD_NUMTYPES; i++) {
if (mask->lmask & CD_TYPE_AS_MASK(i)) {
printf(" %s\n", layerType_getName(i));
}
}
- printf("polys mask=0x%lx:\n", (long unsigned int)mask->pmask);
+ printf("polys mask=0x%" PRIx64 ":\n", mask->pmask);
for (int i = 0; i < CD_NUMTYPES; i++) {
if (mask->pmask & CD_TYPE_AS_MASK(i)) {
printf(" %s\n", layerType_getName(i));
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 8661941bd4c..70355f3883d 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -1420,237 +1420,237 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
if (ob->type == OB_SURF) {
displist_make_surf(depsgraph, scene, ob, dispbase, r_final, for_render, for_orco);
+ return;
}
- else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
- ListBase nubase = {nullptr, nullptr};
- bool force_mesh_conversion = false;
- BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ ListBase nubase = {nullptr, nullptr};
+ bool force_mesh_conversion = false;
- /* We only re-evaluate path if evaluation is not happening for orco.
- * If the calculation happens for orco, we should never free data which
- * was needed before and only not needed for orco calculation. */
- if (!for_orco) {
- if (ob->runtime.curve_cache->anim_path_accum_length) {
- MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
- }
- ob->runtime.curve_cache->anim_path_accum_length = nullptr;
- }
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
- if (ob->type == OB_FONT) {
- BKE_vfont_to_curve_nubase(ob, FO_EDIT, &nubase);
- }
- else {
- BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(const_cast<Curve *>(cu)));
+ /* We only re-evaluate path if evaluation is not happening for orco.
+ * If the calculation happens for orco, we should never free data which
+ * was needed before and only not needed for orco calculation. */
+ if (!for_orco) {
+ if (ob->runtime.curve_cache->anim_path_accum_length) {
+ MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
}
+ ob->runtime.curve_cache->anim_path_accum_length = nullptr;
+ }
- if (!for_orco) {
- force_mesh_conversion = BKE_curve_calc_modifiers_pre(
- depsgraph, scene, ob, &nubase, &nubase, for_render);
- }
+ if (ob->type == OB_FONT) {
+ BKE_vfont_to_curve_nubase(ob, FO_EDIT, &nubase);
+ }
+ else {
+ BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(const_cast<Curve *>(cu)));
+ }
- BKE_curve_bevelList_make(ob, &nubase, for_render);
+ if (!for_orco) {
+ force_mesh_conversion = BKE_curve_calc_modifiers_pre(
+ depsgraph, scene, ob, &nubase, &nubase, for_render);
+ }
- /* If curve has no bevel will return nothing */
- ListBase dlbev = BKE_curve_bevel_make(cu);
+ BKE_curve_bevelList_make(ob, &nubase, for_render);
- /* no bevel or extrude, and no width correction? */
- if (BLI_listbase_is_empty(&dlbev) && cu->width == 1.0f) {
- curve_to_displist(cu, &nubase, for_render, dispbase);
- }
- else {
- const float widfac = cu->width - 1.0f;
+ /* If curve has no bevel will return nothing */
+ ListBase dlbev = BKE_curve_bevel_make(cu);
- BevList *bl = (BevList *)ob->runtime.curve_cache->bev.first;
- Nurb *nu = (Nurb *)nubase.first;
- for (; bl && nu; bl = bl->next, nu = nu->next) {
- float *data;
+ /* no bevel or extrude, and no width correction? */
+ if (BLI_listbase_is_empty(&dlbev) && cu->width == 1.0f) {
+ curve_to_displist(cu, &nubase, for_render, dispbase);
+ }
+ else {
+ const float widfac = cu->width - 1.0f;
- if (bl->nr == 0) { /* blank bevel lists can happen */
- continue;
- }
+ BevList *bl = (BevList *)ob->runtime.curve_cache->bev.first;
+ Nurb *nu = (Nurb *)nubase.first;
+ for (; bl && nu; bl = bl->next, nu = nu->next) {
+ float *data;
- /* exception handling; curve without bevel or extrude, with width correction */
- if (BLI_listbase_is_empty(&dlbev)) {
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev");
- dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
- BLI_addtail(dispbase, dl);
+ if (bl->nr == 0) { /* blank bevel lists can happen */
+ continue;
+ }
- if (bl->poly != -1) {
- dl->type = DL_POLY;
- }
- else {
- dl->type = DL_SEGM;
- dl->flag = (DL_FRONT_CURVE | DL_BACK_CURVE);
- }
+ /* exception handling; curve without bevel or extrude, with width correction */
+ if (BLI_listbase_is_empty(&dlbev)) {
+ DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev");
+ dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
+ BLI_addtail(dispbase, dl);
- dl->parts = 1;
- dl->nr = bl->nr;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
- dl->rt = nu->flag;
+ if (bl->poly != -1) {
+ dl->type = DL_POLY;
+ }
+ else {
+ dl->type = DL_SEGM;
+ dl->flag = (DL_FRONT_CURVE | DL_BACK_CURVE);
+ }
- int a = dl->nr;
- BevPoint *bevp = bl->bevpoints;
- data = dl->verts;
- while (a--) {
- data[0] = bevp->vec[0] + widfac * bevp->sina;
- data[1] = bevp->vec[1] + widfac * bevp->cosa;
- data[2] = bevp->vec[2];
- bevp++;
- data += 3;
- }
+ dl->parts = 1;
+ dl->nr = bl->nr;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+ dl->rt = nu->flag;
+
+ int a = dl->nr;
+ BevPoint *bevp = bl->bevpoints;
+ data = dl->verts;
+ while (a--) {
+ data[0] = bevp->vec[0] + widfac * bevp->sina;
+ data[1] = bevp->vec[1] + widfac * bevp->cosa;
+ data[2] = bevp->vec[2];
+ bevp++;
+ data += 3;
+ }
+ }
+ else {
+ ListBase bottom_capbase = {nullptr, nullptr};
+ ListBase top_capbase = {nullptr, nullptr};
+ float bottom_no[3] = {0.0f};
+ float top_no[3] = {0.0f};
+ float first_blend = 0.0f, last_blend = 0.0f;
+ int start, steps = 0;
+
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ calc_bevfac_mapping_default(bl, &start, &first_blend, &steps, &last_blend);
}
else {
- ListBase bottom_capbase = {nullptr, nullptr};
- ListBase top_capbase = {nullptr, nullptr};
- float bottom_no[3] = {0.0f};
- float top_no[3] = {0.0f};
- float first_blend = 0.0f, last_blend = 0.0f;
- int start, steps = 0;
-
- if (nu->flagu & CU_NURB_CYCLIC) {
- calc_bevfac_mapping_default(bl, &start, &first_blend, &steps, &last_blend);
+ if (fabsf(cu->bevfac2 - cu->bevfac1) < FLT_EPSILON) {
+ continue;
}
- else {
- if (fabsf(cu->bevfac2 - cu->bevfac1) < FLT_EPSILON) {
- continue;
- }
- calc_bevfac_mapping(cu, bl, nu, &start, &first_blend, &steps, &last_blend);
+ calc_bevfac_mapping(cu, bl, nu, &start, &first_blend, &steps, &last_blend);
+ }
+
+ LISTBASE_FOREACH (DispList *, dlb, &dlbev) {
+ /* for each part of the bevel use a separate displblock */
+ DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev1");
+ dl->verts = data = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ dl->type = DL_SURF;
+
+ dl->flag = dlb->flag & (DL_FRONT_CURVE | DL_BACK_CURVE);
+ if (dlb->type == DL_POLY) {
+ dl->flag |= DL_CYCL_U;
+ }
+ if ((bl->poly >= 0) && (steps > 2)) {
+ dl->flag |= DL_CYCL_V;
}
- LISTBASE_FOREACH (DispList *, dlb, &dlbev) {
- /* for each part of the bevel use a separate displblock */
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev1");
- dl->verts = data = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, "dlverts");
- BLI_addtail(dispbase, dl);
+ dl->parts = steps;
+ dl->nr = dlb->nr;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+ dl->rt = nu->flag;
- dl->type = DL_SURF;
+ /* for each point of poly make a bevel piece */
+ BevPoint *bevp_first = bl->bevpoints;
+ BevPoint *bevp_last = &bl->bevpoints[bl->nr - 1];
+ BevPoint *bevp = &bl->bevpoints[start];
+ for (int i = start, a = 0; a < steps; i++, bevp++, a++) {
+ float radius_factor = 1.0;
+ float *cur_data = data;
- dl->flag = dlb->flag & (DL_FRONT_CURVE | DL_BACK_CURVE);
- if (dlb->type == DL_POLY) {
- dl->flag |= DL_CYCL_U;
- }
- if ((bl->poly >= 0) && (steps > 2)) {
- dl->flag |= DL_CYCL_V;
+ if (cu->taperobj == nullptr) {
+ radius_factor = bevp->radius;
}
+ else {
+ float taper_factor;
+ if (cu->flag & CU_MAP_TAPER) {
+ float len = (steps - 3) + first_blend + last_blend;
- dl->parts = steps;
- dl->nr = dlb->nr;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
- dl->rt = nu->flag;
-
- /* for each point of poly make a bevel piece */
- BevPoint *bevp_first = bl->bevpoints;
- BevPoint *bevp_last = &bl->bevpoints[bl->nr - 1];
- BevPoint *bevp = &bl->bevpoints[start];
- for (int i = start, a = 0; a < steps; i++, bevp++, a++) {
- float radius_factor = 1.0;
- float *cur_data = data;
-
- if (cu->taperobj == nullptr) {
- radius_factor = bevp->radius;
- }
- else {
- float taper_factor;
- if (cu->flag & CU_MAP_TAPER) {
- float len = (steps - 3) + first_blend + last_blend;
-
- if (a == 0) {
- taper_factor = 0.0f;
- }
- else if (a == steps - 1) {
- taper_factor = 1.0f;
- }
- else {
- taper_factor = ((float)a - (1.0f - first_blend)) / len;
- }
+ if (a == 0) {
+ taper_factor = 0.0f;
+ }
+ else if (a == steps - 1) {
+ taper_factor = 1.0f;
}
else {
- float len = bl->nr - 1;
- taper_factor = (float)i / len;
-
- if (a == 0) {
- taper_factor += (1.0f - first_blend) / len;
- }
- else if (a == steps - 1) {
- taper_factor -= (1.0f - last_blend) / len;
- }
+ taper_factor = ((float)a - (1.0f - first_blend)) / len;
}
+ }
+ else {
+ float len = bl->nr - 1;
+ taper_factor = (float)i / len;
- radius_factor = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_factor);
-
- if (cu->taper_radius_mode == CU_TAPER_RADIUS_MULTIPLY) {
- radius_factor *= bevp->radius;
+ if (a == 0) {
+ taper_factor += (1.0f - first_blend) / len;
}
- else if (cu->taper_radius_mode == CU_TAPER_RADIUS_ADD) {
- radius_factor += bevp->radius;
+ else if (a == steps - 1) {
+ taper_factor -= (1.0f - last_blend) / len;
}
}
- /* rotate bevel piece and write in data */
- if ((a == 0) && (bevp != bevp_last)) {
- rotateBevelPiece(
- cu, bevp, bevp + 1, dlb, 1.0f - first_blend, widfac, radius_factor, &data);
- }
- else if ((a == steps - 1) && (bevp != bevp_first)) {
- rotateBevelPiece(
- cu, bevp, bevp - 1, dlb, 1.0f - last_blend, widfac, radius_factor, &data);
+ radius_factor = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_factor);
+
+ if (cu->taper_radius_mode == CU_TAPER_RADIUS_MULTIPLY) {
+ radius_factor *= bevp->radius;
}
- else {
- rotateBevelPiece(cu, bevp, nullptr, dlb, 0.0f, widfac, radius_factor, &data);
+ else if (cu->taper_radius_mode == CU_TAPER_RADIUS_ADD) {
+ radius_factor += bevp->radius;
}
+ }
- if ((cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) {
- if (a == 1) {
- fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase);
- copy_v3_v3(bottom_no, bevp->dir);
- }
- if (a == steps - 1) {
- fillBevelCap(nu, dlb, cur_data, &top_capbase);
- negate_v3_v3(top_no, bevp->dir);
- }
- }
+ /* rotate bevel piece and write in data */
+ if ((a == 0) && (bevp != bevp_last)) {
+ rotateBevelPiece(
+ cu, bevp, bevp + 1, dlb, 1.0f - first_blend, widfac, radius_factor, &data);
+ }
+ else if ((a == steps - 1) && (bevp != bevp_first)) {
+ rotateBevelPiece(
+ cu, bevp, bevp - 1, dlb, 1.0f - last_blend, widfac, radius_factor, &data);
+ }
+ else {
+ rotateBevelPiece(cu, bevp, nullptr, dlb, 0.0f, widfac, radius_factor, &data);
}
- /* gl array drawing: using indices */
- displist_surf_indices(dl);
+ if ((cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) {
+ if (a == 1) {
+ fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase);
+ copy_v3_v3(bottom_no, bevp->dir);
+ }
+ if (a == steps - 1) {
+ fillBevelCap(nu, dlb, cur_data, &top_capbase);
+ negate_v3_v3(top_no, bevp->dir);
+ }
+ }
}
- if (bottom_capbase.first) {
- BKE_displist_fill(&bottom_capbase, dispbase, bottom_no, false);
- BKE_displist_fill(&top_capbase, dispbase, top_no, false);
- BKE_displist_free(&bottom_capbase);
- BKE_displist_free(&top_capbase);
- }
+ /* gl array drawing: using indices */
+ displist_surf_indices(dl);
}
- }
- BKE_displist_free(&dlbev);
- }
- if (!(cu->flag & CU_DEFORM_FILL)) {
- curve_to_filledpoly(cu, dispbase);
+ if (bottom_capbase.first) {
+ BKE_displist_fill(&bottom_capbase, dispbase, bottom_no, false);
+ BKE_displist_fill(&top_capbase, dispbase, top_no, false);
+ BKE_displist_free(&bottom_capbase);
+ BKE_displist_free(&top_capbase);
+ }
+ }
}
+ BKE_displist_free(&dlbev);
+ }
- if (!for_orco) {
- if ((cu->flag & CU_PATH) ||
- DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH) {
- BKE_anim_path_calc_data(ob);
- }
+ if (!(cu->flag & CU_DEFORM_FILL)) {
+ curve_to_filledpoly(cu, dispbase);
+ }
- BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(
- depsgraph, scene, ob, dispbase, for_render, force_mesh_conversion, r_final);
+ if (!for_orco) {
+ if ((cu->flag & CU_PATH) ||
+ DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH) {
+ BKE_anim_path_calc_data(ob);
}
- if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) {
- curve_to_filledpoly(cu, dispbase);
- }
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, dispbase, for_render, force_mesh_conversion, r_final);
+ }
- BKE_nurbList_free(&nubase);
+ if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) {
+ curve_to_filledpoly(cu, dispbase);
}
+
+ BKE_nurbList_free(&nubase);
}
void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
@@ -1689,8 +1689,8 @@ void BKE_displist_make_curveTypes_forRender(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
ListBase *dispbase,
- Mesh **r_final,
- const bool for_orco)
+ const bool for_orco,
+ Mesh **r_final)
{
if (ob->runtime.curve_cache == nullptr) {
ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache),
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 42af3a391ed..788a51257bf 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -5185,7 +5185,7 @@ static int dynamicPaint_prepareEffectStep(struct Depsgraph *depsgraph,
}
/* Get number of required steps using average point distance
- * so that just a few ultra close pixels wont up substeps to max. */
+ * so that just a few ultra close pixels won't increase substeps to max. */
/* adjust number of required substep by fastest active effect */
if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 472de1f3c77..b512309a773 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -96,7 +96,8 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob)
return ((Mesh *)ob->data)->edit_mesh;
}
-static void editmesh_tessface_calc_intern(BMEditMesh *em)
+static void editmesh_tessface_calc_intern(BMEditMesh *em,
+ const struct BMeshCalcTessellation_Params *params)
{
/* allocating space before calculating the tessellation */
@@ -130,12 +131,13 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
em->tottri = looptris_tot;
/* after allocating the em->looptris, we're ready to tessellate */
- BM_mesh_calc_tessellation(em->bm, em->looptris);
+ BM_mesh_calc_tessellation_ex(em->bm, em->looptris, params);
}
-void BKE_editmesh_looptri_calc(BMEditMesh *em)
+void BKE_editmesh_looptri_calc_ex(BMEditMesh *em,
+ const struct BMeshCalcTessellation_Params *params)
{
- editmesh_tessface_calc_intern(em);
+ editmesh_tessface_calc_intern(em, params);
/* commented because editbmesh_build_data() ensures we get tessfaces */
#if 0
@@ -149,12 +151,62 @@ void BKE_editmesh_looptri_calc(BMEditMesh *em)
#endif
}
-void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo)
+void BKE_editmesh_looptri_calc(BMEditMesh *em)
+{
+ BKE_editmesh_looptri_calc_ex(em,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = false,
+ });
+}
+
+/**
+ * Performing the face normal calculation at the same time as tessellation
+ * gives a reasonable performance boost (approx ~20% faster).
+ */
+void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
+{
+ BKE_editmesh_looptri_calc_ex(em,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = true,
+ });
+ BM_mesh_normals_update_ex(em->bm,
+ &(const struct BMeshNormalsUpdate_Params){
+ .face_normals = false,
+ });
+}
+
+void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em,
+ struct BMPartialUpdate *bmpinfo,
+ const struct BMeshCalcTessellation_Params *params)
{
BLI_assert(em->tottri == poly_to_tri_count(em->bm->totface, em->bm->totloop));
BLI_assert(em->looptris != NULL);
- BM_mesh_calc_tessellation_with_partial(em->bm, em->looptris, bmpinfo);
+ BM_mesh_calc_tessellation_with_partial_ex(em->bm, em->looptris, bmpinfo, params);
+}
+
+void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo)
+{
+ BKE_editmesh_looptri_calc_with_partial_ex(em,
+ bmpinfo,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = false,
+ });
+}
+
+void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
+ struct BMPartialUpdate *bmpinfo)
+{
+ BKE_editmesh_looptri_calc_with_partial_ex(em,
+ bmpinfo,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = true,
+ });
+ BM_mesh_normals_update_with_partial_ex(em->bm,
+ bmpinfo,
+ &(const struct BMeshNormalsUpdate_Params){
+ .face_normals = false,
+ });
}
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index c4f855dd8c2..9e0e1933a00 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -117,7 +117,7 @@ BMBVHTree *BKE_bmbvh_new_ex(BMesh *bm,
for (int i = 0; i < looptris_tot; i++) {
if (test_fn) {
- /* note, the arrays wont align now! take care */
+ /* Note: the arrays won't align now! Take care. */
f_test = looptris[i][0]->f;
if (f_test != f_test_prev) {
test_fn_ret = test_fn(f_test, user_data);
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index 088a2087a96..d849f4ab37d 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -362,7 +362,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
/* Calculation */
if (em->tottri != 0) {
TaskPool *task_pool;
- task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 493a267c2f0..553575b5c7b 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1615,8 +1615,9 @@ static void emit_from_particles(Object *flow_ob,
}
}
- state.time = BKE_scene_frame_get(
- scene); /* DEG_get_ctime(depsgraph) does not give subframe time */
+ /* `DEG_get_ctime(depsgraph)` does not give sub-frame time. */
+ state.time = BKE_scene_frame_get(scene);
+
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
continue;
}
@@ -4234,7 +4235,7 @@ struct Mesh *BKE_fluid_modifier_do(
result = BKE_mesh_copy_for_eval(me, false);
}
else {
- BKE_mesh_copy_settings(result, me);
+ BKE_mesh_copy_parameters_for_eval(result, me);
}
/* Liquid simulation has a texture space that based on the bounds of the fluid mesh.
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index de8dc355557..b5c49dbb8b2 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -240,14 +240,18 @@ static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVA
* unless it is necessary (in that case the materialize functions will be called).
*/
template<typename T> class VArray_For_SplineToPoint final : public VArray<T> {
+ GVArrayPtr original_varray_;
/* Store existing data materialized if it was not already a span. This is expected
* to be worth it because a single spline's value will likely be accessed many times. */
- VArray_Span<T> original_data_;
+ fn::GVArray_Span<T> original_data_;
Array<int> offsets_;
public:
- VArray_For_SplineToPoint(const VArray<T> &original_varray, Array<int> offsets)
- : VArray<T>(offsets.last()), original_data_(original_varray), offsets_(std::move(offsets))
+ VArray_For_SplineToPoint(GVArrayPtr original_varray, Array<int> offsets)
+ : VArray<T>(offsets.last()),
+ original_varray_(std::move(original_varray)),
+ original_data_(*original_varray_),
+ offsets_(std::move(offsets))
{
}
@@ -309,7 +313,7 @@ static GVArrayPtr adapt_curve_domain_spline_to_point(const CurveEval &curve, GVA
Array<int> offsets = curve.control_point_offsets();
new_varray = std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplineToPoint<T>>>(
- offsets.last(), *varray->typed<T>(), std::move(offsets));
+ offsets.last(), std::move(varray), std::move(offsets));
});
return new_varray;
}
@@ -1007,9 +1011,10 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return false;
}
+ /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */
bool layer_freed = false;
for (SplinePtr &spline : curve->splines()) {
- spline->attributes.remove(attribute_name);
+ layer_freed = spline->attributes.remove(attribute_name);
}
return layer_freed;
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 69840ba1612..8cf08d05d9d 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -399,7 +399,7 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
const GeometrySet &set = set_group.geometry_set;
if (set.has_mesh()) {
const Mesh &mesh = *set.get_mesh_for_read();
- BKE_mesh_copy_settings(new_mesh, &mesh);
+ BKE_mesh_copy_parameters_for_eval(new_mesh, &mesh);
break;
}
}
@@ -472,6 +472,11 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
poly_offset += mesh.totpoly;
}
}
+
+ const float3 point_normal{0.0f, 0.0f, 1.0f};
+ short point_normal_short[3];
+ normal_float_to_short_v3(point_normal_short, point_normal);
+
if (convert_points_to_vertices && set.has_pointcloud()) {
const PointCloud &pointcloud = *set.get_pointcloud_for_read();
for (const float4x4 &transform : set_group.transforms) {
@@ -480,6 +485,7 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
const float3 old_position = pointcloud.co[i];
const float3 new_position = transform * old_position;
copy_v3_v3(new_vert.co, new_position);
+ memcpy(&new_vert.no, point_normal_short, sizeof(point_normal_short));
}
vert_offset += pointcloud.totpoint;
}
@@ -544,7 +550,45 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
}
}
-static CurveEval *join_curve_splines(Span<GeometryInstanceGroup> set_groups)
+static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup> set_groups)
+{
+ /* Count the total number of points. */
+ int totpoint = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ if (set.has<PointCloudComponent>()) {
+ const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
+ totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ }
+ }
+ if (totpoint == 0) {
+ return nullptr;
+ }
+
+ PointCloud *new_pointcloud = BKE_pointcloud_new_nomain(totpoint);
+
+ /* Transform each instance's point locations into the new point cloud. */
+ int offset = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const PointCloud *pointcloud = set.get_pointcloud_for_read();
+ if (pointcloud == nullptr) {
+ continue;
+ }
+ for (const float4x4 &transform : set_group.transforms) {
+ for (const int i : IndexRange(pointcloud->totpoint)) {
+ const float3 old_position = pointcloud->co[i];
+ const float3 new_position = transform * old_position;
+ copy_v3_v3(new_pointcloud->co[offset + i], new_position);
+ }
+ offset += pointcloud->totpoint;
+ }
+ }
+
+ return new_pointcloud;
+}
+
+static CurveEval *join_curve_splines_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups)
{
Vector<SplinePtr> new_splines;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -556,7 +600,7 @@ static CurveEval *join_curve_splines(Span<GeometryInstanceGroup> set_groups)
const CurveEval &source_curve = *set.get_curve_for_read();
for (const SplinePtr &source_spline : source_curve.splines()) {
for (const float4x4 &transform : set_group.transforms) {
- SplinePtr new_spline = source_spline->copy();
+ SplinePtr new_spline = source_spline->copy_without_attributes();
new_spline->transform(transform);
new_splines.append(std::move(new_spline));
}
@@ -571,15 +615,6 @@ static CurveEval *join_curve_splines(Span<GeometryInstanceGroup> set_groups)
new_curve->add_spline(std::move(new_spline));
}
- for (SplinePtr &spline : new_curve->splines()) {
- /* Spline instances should have no custom attributes, since they always come
- * from original objects which currently do not support custom attributes.
- *
- * This is only true as long as a #GeometrySet cannot be instanced directly. */
- BLI_assert(spline->attributes.data.totlayer == 0);
- UNUSED_VARS_NDEBUG(spline);
- }
-
new_curve->attributes.reallocate(new_curve->splines().size());
return new_curve;
}
@@ -617,24 +652,17 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_groups,
GeometrySet &result)
{
- int totpoint = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<PointCloudComponent>()) {
- const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
- totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
- }
- }
- if (totpoint == 0) {
+ PointCloud *new_pointcloud = join_pointcloud_position_attribute(set_groups);
+ if (new_pointcloud == nullptr) {
return;
}
PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
- dst_component.replace(pointcloud);
+ dst_component.replace(new_pointcloud);
+
Map<std::string, AttributeKind> attributes;
geometry_set_gather_instances_attribute_info(
- set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {}, attributes);
+ set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {"position"}, attributes);
join_attributes(set_groups,
{GEO_COMPONENT_TYPE_POINT_CLOUD},
attributes,
@@ -644,19 +672,38 @@ static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_grou
static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
GeometrySet &result)
{
- /* Not yet supported. Joining volume grids with the same name requires resampling of at least
- * one of the grids. The cell size of the resulting volume has to be determined somehow. */
- UNUSED_VARS(set_groups, result);
+ /* Not yet supported; for now only return the first volume. Joining volume grids with the same
+ * name requires resampling of at least one of the grids. The cell size of the resulting volume
+ * has to be determined somehow. */
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ if (set.has<VolumeComponent>()) {
+ result.add(*set.get_component_for_read<VolumeComponent>());
+ return;
+ }
+ }
}
static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
{
- CurveEval *curve = join_curve_splines(set_groups);
+ CurveEval *curve = join_curve_splines_and_builtin_attributes(set_groups);
if (curve == nullptr) {
return;
}
+
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
dst_component.replace(curve);
+
+ Map<std::string, AttributeKind> attributes;
+ geometry_set_gather_instances_attribute_info(
+ set_groups,
+ {GEO_COMPONENT_TYPE_CURVE},
+ {"position", "radius", "tilt", "cyclic", "resolution"},
+ attributes);
+ join_attributes(set_groups,
+ {GEO_COMPONENT_TYPE_CURVE},
+ attributes,
+ static_cast<GeometryComponent &>(dst_component));
}
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 6d1476485ca..a66c3cf3573 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -1103,6 +1103,35 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
}
/**
+ * Make a copy of a given gpencil layer settings.
+ */
+void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
+{
+ gpl_dst->line_change = gpl_src->line_change;
+ copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
+ gpl_dst->opacity = gpl_src->opacity;
+ gpl_dst->vertex_paint_opacity = gpl_src->vertex_paint_opacity;
+ gpl_dst->pass_index = gpl_src->pass_index;
+ gpl_dst->parent = gpl_src->parent;
+ copy_m4_m4(gpl_dst->inverse, gpl_src->inverse);
+ BLI_strncpy(gpl_dst->parsubstr, gpl_src->parsubstr, 64);
+ gpl_dst->partype = gpl_src->partype;
+ BLI_strncpy(gpl_dst->viewlayername, gpl_src->viewlayername, 64);
+ copy_v3_v3(gpl_dst->location, gpl_src->location);
+ copy_v3_v3(gpl_dst->rotation, gpl_src->rotation);
+ copy_v3_v3(gpl_dst->scale, gpl_src->scale);
+ copy_m4_m4(gpl_dst->layer_mat, gpl_src->layer_mat);
+ copy_m4_m4(gpl_dst->layer_invmat, gpl_src->layer_invmat);
+ /* Use Lights flag. */
+ if (gpl_src->flag & GP_LAYER_USE_LIGHTS) {
+ gpl_dst->flag |= GP_LAYER_USE_LIGHTS;
+ }
+ else {
+ gpl_dst->flag &= ~GP_LAYER_USE_LIGHTS;
+ }
+}
+
+/**
* Make a copy of a given gpencil data-block.
*
* XXX: Should this be deprecated?
@@ -2980,8 +3009,8 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
bGPdata *gpd = (bGPdata *)ob->data;
float cur_mat[4][4];
- bool changed = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bool changed = false;
unit_m4(cur_mat);
if (gpl->actframe != NULL) {
if (gpl->parent != NULL) {
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index 7f839650f33..36b8b5e52f0 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -793,6 +793,7 @@ bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf)
{
bGPDspoint *pt = &gps->points[i];
float sco[3] = {0.0f};
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
/* Do nothing if not enough points to smooth out */
if (gps->totpoints <= 2) {
@@ -802,7 +803,7 @@ bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf)
/* Only affect endpoints by a fraction of the normal strength,
* to prevent the stroke from shrinking too much
*/
- if (ELEM(i, 0, gps->totpoints - 1)) {
+ if (!is_cyclic && ELEM(i, 0, gps->totpoints - 1)) {
inf *= 0.1f;
}
@@ -828,8 +829,22 @@ bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf)
int before = i - step;
int after = i + step;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ if (is_cyclic) {
+ if (before < 0) {
+ /* Sub to end point (before is already negative). */
+ before = gps->totpoints + before;
+ CLAMP(before, 0, gps->totpoints - 1);
+ }
+ if (after > gps->totpoints - 1) {
+ /* Add to start point. */
+ after = after - gps->totpoints;
+ CLAMP(after, 0, gps->totpoints - 1);
+ }
+ }
+ else {
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+ }
pt1 = &gps->points[before];
pt2 = &gps->points[after];
@@ -855,6 +870,7 @@ bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf)
bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
/* Do nothing if not enough points */
if ((gps->totpoints <= 2) || (point_index < 1)) {
@@ -862,7 +878,7 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
}
/* Only affect endpoints by a fraction of the normal influence */
float inf = influence;
- if (ELEM(point_index, 0, gps->totpoints - 1)) {
+ if (!is_cyclic && ELEM(point_index, 0, gps->totpoints - 1)) {
inf *= 0.01f;
}
/* Limit max influence to reduce pop effect. */
@@ -884,9 +900,22 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
int before = point_index - step;
int after = point_index + step;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
+ if (is_cyclic) {
+ if (before < 0) {
+ /* Sub to end point (before is already negative). */
+ before = gps->totpoints + before;
+ CLAMP(before, 0, gps->totpoints - 1);
+ }
+ if (after > gps->totpoints - 1) {
+ /* Add to start point. */
+ after = after - gps->totpoints;
+ CLAMP(after, 0, gps->totpoints - 1);
+ }
+ }
+ else {
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+ }
pt1 = &gps->points[before];
pt2 = &gps->points[after];
@@ -919,6 +948,7 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
/* Do nothing if not enough points */
if ((gps->totpoints <= 2) || (point_index < 1)) {
@@ -926,7 +956,7 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
}
/* Only affect endpoints by a fraction of the normal influence */
float inf = influence;
- if (ELEM(point_index, 0, gps->totpoints - 1)) {
+ if (!is_cyclic && ELEM(point_index, 0, gps->totpoints - 1)) {
inf *= 0.01f;
}
/* Limit max influence to reduce pop effect. */
@@ -948,9 +978,22 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
int before = point_index - step;
int after = point_index + step;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
+ if (is_cyclic) {
+ if (before < 0) {
+ /* Sub to end point (before is already negative). */
+ before = gps->totpoints + before;
+ CLAMP(before, 0, gps->totpoints - 1);
+ }
+ if (after > gps->totpoints - 1) {
+ /* Add to start point. */
+ after = after - gps->totpoints;
+ CLAMP(after, 0, gps->totpoints - 1);
+ }
+ }
+ else {
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+ }
pt1 = &gps->points[before];
pt2 = &gps->points[after];
@@ -982,6 +1025,7 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
/* Do nothing if not enough points */
if (gps->totpoints <= 2) {
@@ -993,9 +1037,22 @@ bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influe
int before = point_index - 1;
int after = point_index + 1;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
+ if (is_cyclic) {
+ if (before < 0) {
+ /* Sub to end point (before is already negative). */
+ before = gps->totpoints + before;
+ CLAMP(before, 0, gps->totpoints - 1);
+ }
+ if (after > gps->totpoints - 1) {
+ /* Add to start point. */
+ after = after - gps->totpoints;
+ CLAMP(after, 0, gps->totpoints - 1);
+ }
+ }
+ else {
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+ }
pta = &gps->points[before];
ptc = &gps->points[after];
@@ -2984,6 +3041,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
/* Add new stroke to the frame or delete if below limit */
if ((limit > 0) && (new_stroke->totpoints <= limit)) {
+ if (gps_first == new_stroke) {
+ gps_first = NULL;
+ }
BKE_gpencil_free_stroke(new_stroke);
}
else {
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 16386cac029..9f5f70ab2ba 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -55,6 +55,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "MOD_gpencil_lineart.h"
#include "MOD_gpencil_modifiertypes.h"
#include "BLO_read_write.h"
@@ -202,6 +203,60 @@ bool BKE_gpencil_has_transform_modifiers(Object *ob)
return false;
}
+GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const Object *ob)
+{
+ GpencilLineartLimitInfo info = {0};
+ bool is_first = true;
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Lineart) {
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ if (is_first || (lmd->flags & LRT_GPENCIL_USE_CACHE)) {
+ info.min_level = MIN2(info.min_level, lmd->level_start);
+ info.max_level = MAX2(info.max_level,
+ (lmd->use_multiple_levels ? lmd->level_end : lmd->level_start));
+ info.edge_types |= lmd->edge_types;
+ }
+ }
+ }
+ return info;
+}
+
+void BKE_gpencil_set_lineart_modifier_limits(GpencilModifierData *md,
+ const GpencilLineartLimitInfo *info,
+ const bool is_first_lineart)
+{
+ BLI_assert(md->type == eGpencilModifierType_Lineart);
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
+ if (is_first_lineart || lmd->flags & LRT_GPENCIL_USE_CACHE) {
+ lmd->level_start_override = info->min_level;
+ lmd->level_end_override = info->max_level;
+ lmd->edge_types_override = info->edge_types;
+ }
+ else {
+ lmd->level_start_override = lmd->level_start;
+ lmd->level_end_override = lmd->level_end;
+ lmd->edge_types_override = lmd->edge_types;
+ }
+}
+
+bool BKE_gpencil_is_first_lineart_in_stack(const Object *ob, const GpencilModifierData *md)
+{
+ if (md->type != eGpencilModifierType_Lineart) {
+ return false;
+ }
+ LISTBASE_FOREACH (GpencilModifierData *, gmd, &ob->greasepencil_modifiers) {
+ if (gmd->type == eGpencilModifierType_Lineart) {
+ if (gmd == md) {
+ return true;
+ }
+ return false;
+ }
+ }
+ /* If we reach here it means md is not in ob's modifier stack. */
+ BLI_assert(false);
+ return false;
+}
+
/* apply time modifiers */
static int gpencil_time_modifier(
Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render)
@@ -771,6 +826,8 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
BKE_gpencil_lattice_init(ob);
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
+ bool is_first_lineart = true;
+ GpencilLineartLimitInfo info = BKE_gpencil_get_lineart_modifier_limits(ob);
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -781,6 +838,11 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
continue;
}
+ if (md->type == eGpencilModifierType_Lineart) {
+ BKE_gpencil_set_lineart_modifier_limits(md, &info, is_first_lineart);
+ is_first_lineart = false;
+ }
+
/* Apply geometry modifiers (add new geometry). */
if (mti && mti->generateStrokes) {
mti->generateStrokes(md, depsgraph, ob);
@@ -806,6 +868,8 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
/* Clear any lattice data. */
BKE_gpencil_lattice_clear(ob);
+
+ MOD_lineart_clear_cache(&gpd->runtime.lineart_cache);
}
void BKE_gpencil_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 2f7e2b41a73..7a3619154a6 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -68,6 +68,7 @@
#include "BLI_math_vector.h"
#include "BLI_mempool.h"
#include "BLI_system.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_timecode.h" /* For stamp time-code format. */
#include "BLI_utildefines.h"
@@ -882,6 +883,39 @@ Image *BKE_image_load_exists(Main *bmain, const char *filepath)
return BKE_image_load_exists_ex(bmain, filepath, NULL);
}
+typedef struct ImageFillData {
+ short gen_type;
+ uint width;
+ uint height;
+ unsigned char *rect;
+ float *rect_float;
+ float fill_color[4];
+} ImageFillData;
+
+static void image_buf_fill_isolated(void *usersata_v)
+{
+ ImageFillData *usersata = usersata_v;
+
+ const short gen_type = usersata->gen_type;
+ const uint width = usersata->width;
+ const uint height = usersata->height;
+
+ unsigned char *rect = usersata->rect;
+ float *rect_float = usersata->rect_float;
+
+ switch (gen_type) {
+ case IMA_GENTYPE_GRID:
+ BKE_image_buf_fill_checker(rect, rect_float, width, height);
+ break;
+ case IMA_GENTYPE_GRID_COLOR:
+ BKE_image_buf_fill_checker_color(rect, rect_float, width, height);
+ break;
+ default:
+ BKE_image_buf_fill_color(rect, rect_float, width, height, usersata->fill_color);
+ break;
+ }
+}
+
static ImBuf *add_ibuf_size(unsigned int width,
unsigned int height,
const char *name,
@@ -944,17 +978,16 @@ static ImBuf *add_ibuf_size(unsigned int width,
STRNCPY(ibuf->name, name);
- switch (gen_type) {
- case IMA_GENTYPE_GRID:
- BKE_image_buf_fill_checker(rect, rect_float, width, height);
- break;
- case IMA_GENTYPE_GRID_COLOR:
- BKE_image_buf_fill_checker_color(rect, rect_float, width, height);
- break;
- default:
- BKE_image_buf_fill_color(rect, rect_float, width, height, fill_color);
- break;
- }
+ ImageFillData data;
+
+ data.gen_type = gen_type;
+ data.width = width;
+ data.height = height;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ copy_v4_v4(data.fill_color, fill_color);
+
+ BLI_task_isolate(image_buf_fill_isolated, &data);
return ibuf;
}
@@ -5326,7 +5359,7 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_ran
}
}
- /* important to apply after else we cant loop on frames 100 - 110 for eg. */
+ /* important to apply after else we can't loop on frames 100 - 110 for eg. */
framenr += iuser->offset;
return framenr;
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index ceb13c4955e..1a0cc8c2924 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -69,10 +69,11 @@ static void image_buf_fill_color_slice(
}
}
-static void image_buf_fill_color_thread_do(void *data_v, int start_scanline, int num_scanlines)
+static void image_buf_fill_color_thread_do(void *data_v, int scanline)
{
FillColorThreadData *data = (FillColorThreadData *)data_v;
- size_t offset = ((size_t)start_scanline) * data->width * 4;
+ const int num_scanlines = 1;
+ size_t offset = ((size_t)scanline) * data->width * 4;
unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
image_buf_fill_color_slice(rect, rect_float, data->width, num_scanlines, data->color);
@@ -197,13 +198,14 @@ typedef struct FillCheckerThreadData {
int width;
} FillCheckerThreadData;
-static void image_buf_fill_checker_thread_do(void *data_v, int start_scanline, int num_scanlines)
+static void image_buf_fill_checker_thread_do(void *data_v, int scanline)
{
FillCheckerThreadData *data = (FillCheckerThreadData *)data_v;
- size_t offset = ((size_t)start_scanline) * data->width * 4;
+ size_t offset = ((size_t)scanline) * data->width * 4;
+ const int num_scanlines = 1;
unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
- image_buf_fill_checker_slice(rect, rect_float, data->width, num_scanlines, start_scanline);
+ image_buf_fill_checker_slice(rect, rect_float, data->width, num_scanlines, scanline);
}
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
@@ -444,16 +446,15 @@ typedef struct FillCheckerColorThreadData {
int width, height;
} FillCheckerColorThreadData;
-static void checker_board_color_prepare_thread_do(void *data_v,
- int start_scanline,
- int num_scanlines)
+static void checker_board_color_prepare_thread_do(void *data_v, int scanline)
{
FillCheckerColorThreadData *data = (FillCheckerColorThreadData *)data_v;
- size_t offset = ((size_t)data->width) * start_scanline * 4;
+ const int num_scanlines = 1;
+ size_t offset = ((size_t)data->width) * scanline * 4;
unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
checker_board_color_prepare_slice(
- rect, rect_float, data->width, num_scanlines, start_scanline, data->height);
+ rect, rect_float, data->width, num_scanlines, scanline, data->height);
}
void BKE_image_buf_fill_checker_color(unsigned char *rect,
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 2ac10586fd9..fb9c38f51b7 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -1000,7 +1000,7 @@ void BKE_main_collection_sync_remap(const Main *bmain)
/* On remapping of object or collection pointers free caches. */
/* TODO: try to make this faster */
- for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
MEM_SAFE_FREE(view_layer->object_bases_array);
@@ -1009,6 +1009,10 @@ void BKE_main_collection_sync_remap(const Main *bmain)
view_layer->object_bases_hash = NULL;
}
}
+
+ BKE_collection_object_cache_free(scene->master_collection);
+ DEG_id_tag_update_ex((Main *)bmain, &scene->master_collection->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update_ex((Main *)bmain, &scene->id, ID_RECALC_COPY_ON_WRITE);
}
for (Collection *collection = bmain->collections.first; collection;
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index f26b85338f0..b7cacba20b3 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -1952,7 +1952,7 @@ void BKE_library_make_local(Main *bmain,
}
/* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so it's possible to tag data
* you don't want to be made local, used for appending data,
- * so any libdata already linked wont become local (very nasty
+ * so any libdata already linked won't become local (very nasty
* to discover all your links are lost after appending).
* Also, never ever make proxified objects local, would not make any sense. */
/* Some more notes:
diff --git a/source/blender/blenkernel/intern/lib_id_test.cc b/source/blender/blenkernel/intern/lib_id_test.cc
index 8e21ae88aa6..f6988a2d71f 100644
--- a/source/blender/blenkernel/intern/lib_id_test.cc
+++ b/source/blender/blenkernel/intern/lib_id_test.cc
@@ -123,7 +123,7 @@ TEST(lib_id_main_unique_name, local_ids_1)
test_lib_id_main_sort_check_order({id_a, id_b, id_c});
BLI_strncpy(id_c->name, id_a->name, sizeof(id_c->name));
- BKE_id_new_name_validate(&ctx.bmain->objects, id_c, NULL, false);
+ BKE_id_new_name_validate(&ctx.bmain->objects, id_c, nullptr, false);
EXPECT_TRUE(strcmp(id_c->name + 2, "OB_A.001") == 0);
EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
EXPECT_TRUE(ctx.bmain->objects.first == id_a);
@@ -150,7 +150,7 @@ TEST(lib_id_main_unique_name, linked_ids_1)
id_b->lib = lib_a;
id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name));
- BKE_id_new_name_validate(&ctx.bmain->objects, id_b, NULL, true);
+ BKE_id_new_name_validate(&ctx.bmain->objects, id_b, nullptr, true);
EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A.001") == 0);
EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
EXPECT_TRUE(ctx.bmain->objects.first == id_c);
@@ -160,7 +160,7 @@ TEST(lib_id_main_unique_name, linked_ids_1)
id_b->lib = lib_b;
id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name));
- BKE_id_new_name_validate(&ctx.bmain->objects, id_b, NULL, true);
+ BKE_id_new_name_validate(&ctx.bmain->objects, id_b, nullptr, true);
EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A") == 0);
EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
EXPECT_TRUE(ctx.bmain->objects.first == id_c);
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 6b2ffa3b944..9a45f484581 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -52,12 +52,17 @@
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BLO_readfile.h"
+
#include "BLI_ghash.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "RNA_access.h"
#include "RNA_types.h"
@@ -466,11 +471,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
typedef struct LibOverrideGroupTagData {
Main *bmain;
+ Scene *scene;
ID *id_root;
uint tag;
uint missing_tag;
/* Whether we are looping on override data, or their references (linked) one. */
bool is_override;
+ /* Whether we are creating new override, or resyncing existing one. */
+ bool is_resync;
} LibOverrideGroupTagData;
/* Tag all IDs in dependency relationships within an override hierarchy/group.
@@ -591,7 +599,9 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
+ Scene *scene = data->scene;
ID *id_root = data->id_root;
+ const bool is_resync = data->is_resync;
BLI_assert(!data->is_override);
if ((id_root->tag & LIB_TAG_MISSING)) {
@@ -616,6 +626,43 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
}
}
}
+
+ /* For each object tagged for override, ensure we get at least one local or liboverride
+ * collection to host it. Avoids getting a bunch of random object in the scene's master
+ * collection when all objects' dependencies are not properly 'packed' into a single root
+ * collection. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ID_IS_LINKED(ob) && (ob->id.tag & data->tag) != 0) {
+ Collection *instantiating_collection = NULL;
+ Collection *instantiating_collection_override_candidate = NULL;
+ /* Loop over all collections instantiating the object, if we already have a 'locale' one we
+ * have nothing to do, otherwise try to find a 'linked' one that we can override too. */
+ while ((instantiating_collection = BKE_collection_object_find(
+ bmain, scene, instantiating_collection, ob)) != NULL) {
+ /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the linked
+ * object, it is also fine. */
+ if (!ID_IS_LINKED(instantiating_collection) ||
+ (is_resync && ID_IS_LINKED(id_root) &&
+ instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
+ break;
+ }
+ else if (ID_IS_LINKED(instantiating_collection) &&
+ (!is_resync || instantiating_collection->id.lib == id_root->lib)) {
+ instantiating_collection_override_candidate = instantiating_collection;
+ }
+ }
+
+ if (instantiating_collection == NULL &&
+ instantiating_collection_override_candidate != NULL) {
+ if ((instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING)) {
+ instantiating_collection_override_candidate->id.tag |= data->missing_tag;
+ }
+ else {
+ instantiating_collection_override_candidate->id.tag |= data->tag;
+ }
+ }
+ }
+ }
}
}
@@ -694,14 +741,16 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
lib_override_overrides_group_tag_recursive(data);
}
-static bool lib_override_library_create_do(Main *bmain, ID *id_root)
+static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_root)
{
BKE_main_relations_create(bmain, 0);
LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = scene,
.id_root = id_root,
.tag = LIB_TAG_DOIT,
.missing_tag = LIB_TAG_MISSING,
- .is_override = false};
+ .is_override = false,
+ .is_resync = false};
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -862,7 +911,7 @@ bool BKE_lib_override_library_create(Main *bmain,
*r_id_root_override = NULL;
}
- const bool success = lib_override_library_create_do(bmain, id_root);
+ const bool success = lib_override_library_create_do(bmain, scene, id_root);
if (!success) {
return success;
@@ -958,7 +1007,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
Collection *override_resync_residual_storage,
const bool do_hierarchy_enforce,
const bool do_post_process,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -966,10 +1015,12 @@ bool BKE_lib_override_library_resync(Main *bmain,
BKE_main_relations_create(bmain, 0);
LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = scene,
.id_root = id_root,
.tag = LIB_TAG_DOIT,
.missing_tag = LIB_TAG_MISSING,
- .is_override = true};
+ .is_override = true,
+ .is_resync = true};
lib_override_overrides_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1286,7 +1337,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
id_root = id_root_reference->newid;
if (user_edited_overrides_deletion_count > 0) {
- BKE_reportf(reports,
+ BKE_reportf(reports != NULL ? reports->reports : NULL,
RPT_WARNING,
"During resync of data-block %s, %d obsolete overrides were deleted, that had "
"local changes defined by user",
@@ -1438,8 +1489,11 @@ static void lib_override_library_main_resync_on_library_indirect_level(
ViewLayer *view_layer,
Collection *override_resync_residual_storage,
const int library_indirect_level,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
+ const bool do_reports_recursive_resync_timing = (library_indirect_level != 0);
+ const double init_time = do_reports_recursive_resync_timing ? PIL_check_seconds_timer() : 0.0;
+
BKE_main_relations_create(bmain, 0);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
@@ -1460,10 +1514,12 @@ static void lib_override_library_main_resync_on_library_indirect_level(
}
LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = scene,
.id_root = id->override_library->reference,
.tag = LIB_TAG_DOIT,
.missing_tag = LIB_TAG_MISSING,
- .is_override = false};
+ .is_override = false,
+ .is_resync = true};
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
@@ -1530,6 +1586,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
(!ID_IS_LINKED(id) && library_indirect_level != 0)) {
continue;
}
+ Library *library = id->lib;
int level = 0;
/* In complex non-supported cases, with several different override hierarchies sharing
@@ -1541,12 +1598,21 @@ static void lib_override_library_main_resync_on_library_indirect_level(
id = lib_override_library_main_resync_find_root_recurse(id, &level);
id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id));
+ BLI_assert(id->lib == library);
do_continue = true;
- CLOG_INFO(&LOG, 2, "Resyncing %s (%p)...", id->name, id->lib);
+ CLOG_INFO(&LOG, 2, "Resyncing %s (%p)...", id->name, library);
const bool success = BKE_lib_override_library_resync(
bmain, scene, view_layer, id, override_resync_residual_storage, false, false, reports);
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
+ if (success) {
+ reports->count.resynced_lib_overrides++;
+ if (library_indirect_level > 0 &&
+ BLI_linklist_index(reports->resynced_lib_overrides_libraries, library) < 0) {
+ BLI_linklist_prepend(&reports->resynced_lib_overrides_libraries, library);
+ reports->resynced_lib_overrides_libraries_count++;
+ }
+ }
break;
}
FOREACH_MAIN_LISTBASE_ID_END;
@@ -1556,6 +1622,10 @@ static void lib_override_library_main_resync_on_library_indirect_level(
}
FOREACH_MAIN_LISTBASE_END;
}
+
+ if (do_reports_recursive_resync_timing) {
+ reports->duration.lib_overrides_recursive_resync += PIL_check_seconds_timer() - init_time;
+ }
}
static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
@@ -1633,7 +1703,7 @@ static int lib_override_libraries_index_define(Main *bmain)
void BKE_lib_override_library_main_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
/* We use a specific collection to gather/store all 'orphaned' override collections and objects
* generated by re-sync-process. This avoids putting them in scene's master collection. */
@@ -1688,10 +1758,12 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
/* Tag all library overrides in the chains of dependencies from the given root one. */
BKE_main_relations_create(bmain, 0);
LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = NULL,
.id_root = id_root,
.tag = LIB_TAG_DOIT,
.missing_tag = LIB_TAG_MISSING,
- .is_override = true};
+ .is_override = true,
+ .is_resync = false};
lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain);
@@ -2335,8 +2407,7 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
}
struct LibOverrideOpCreateData create_pool_data = {.bmain = bmain, .changed = false};
- TaskPool *task_pool = BLI_task_pool_create(
- &create_pool_data, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ TaskPool *task_pool = BLI_task_pool_create(&create_pool_data, TASK_PRIORITY_HIGH);
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index ddbc7e7d1ef..08d3236f3a9 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -900,9 +900,11 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
-/* Copy user editable settings that we want to preserve through the modifier stack
- * or operations where a mesh with new topology is created based on another mesh. */
-void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src)
+/**
+ * Copy user editable settings that we want to preserve
+ * when a new mesh is based on an existing mesh.
+ */
+void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
{
/* Copy general settings. */
me_dst->editflag = me_src->editflag;
@@ -920,6 +922,20 @@ void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src)
me_dst->texflag = me_src->texflag;
copy_v3_v3(me_dst->loc, me_src->loc);
copy_v3_v3(me_dst->size, me_src->size);
+}
+
+/**
+ * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
+ * (the modifier stack for example).
+ *
+ * \warning User counts are not handled for ID's.
+ */
+void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
+{
+ /* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
+ BLI_assert(me_dst->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE));
+
+ BKE_mesh_copy_parameters(me_dst, me_src);
/* Copy materials. */
if (me_dst->mat != NULL) {
@@ -951,7 +967,7 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totpoly = polys_len;
me_dst->cd_flag = me_src->cd_flag;
- BKE_mesh_copy_settings(me_dst, me_src);
+ BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
@@ -1038,7 +1054,7 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me(NULL, bm, mesh, params);
- BKE_mesh_copy_settings(mesh, me_settings);
+ BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
return mesh;
}
@@ -1048,7 +1064,7 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
{
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
- BKE_mesh_copy_settings(mesh, me_settings);
+ BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
return mesh;
}
@@ -1198,9 +1214,11 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
}
}
-/* rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
- * this is necessary to make the if (mface->v4) check for quads work */
-int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
+/**
+ * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
+ * this is necessary to make the if #MFace.v4 check for quads work.
+ */
+int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr)
{
/* first test if the face is legal */
if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) {
@@ -1244,8 +1262,8 @@ int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
if (mface->v3 == 0) {
static int corner_indices[4] = {1, 2, 0, 3};
- SWAP(unsigned int, mface->v1, mface->v2);
- SWAP(unsigned int, mface->v2, mface->v3);
+ SWAP(uint, mface->v1, mface->v2);
+ SWAP(uint, mface->v2, mface->v3);
if (fdata) {
CustomData_swap_corners(fdata, mfindex, corner_indices);
@@ -1256,8 +1274,8 @@ int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
if (mface->v3 == 0 || mface->v4 == 0) {
static int corner_indices[4] = {2, 3, 0, 1};
- SWAP(unsigned int, mface->v1, mface->v3);
- SWAP(unsigned int, mface->v2, mface->v4);
+ SWAP(uint, mface->v1, mface->v3);
+ SWAP(uint, mface->v2, mface->v4);
if (fdata) {
CustomData_swap_corners(fdata, mfindex, corner_indices);
@@ -1359,7 +1377,7 @@ void BKE_mesh_material_index_clear(Mesh *me)
}
}
-void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len)
+void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
{
const short remap_len_short = (short)remap_len;
@@ -1423,10 +1441,7 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint ver
* vertex. Returns the index of the loop matching vertex, or -1 if the
* vertex is not in \a poly
*/
-int poly_get_adj_loops_from_vert(const MPoly *poly,
- const MLoop *mloop,
- unsigned int vert,
- unsigned int r_adj[2])
+int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint vert, uint r_adj[2])
{
int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert);
@@ -1521,12 +1536,12 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
{
- MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert);
+ CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert);
/* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */
BKE_mesh_update_customdata_pointers(me, false);
int i = me->totvert;
- for (mvert = me->mvert; i--; mvert++) {
+ for (MVert *mvert = me->mvert; i--; mvert++) {
add_v3_v3(mvert->co, offset);
}
@@ -1541,22 +1556,6 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
}
}
-void BKE_mesh_tessface_calc(Mesh *mesh)
-{
- mesh->totface = BKE_mesh_tessface_calc_ex(
- &mesh->fdata,
- &mesh->ldata,
- &mesh->pdata,
- mesh->mvert,
- mesh->totface,
- mesh->totloop,
- mesh->totpoly,
- /* calc normals right after, don't copy from polys here */
- false);
-
- BKE_mesh_update_customdata_pointers(mesh, true);
-}
-
void BKE_mesh_tessface_ensure(Mesh *mesh)
{
if (mesh->totpoly && mesh->totface == 0) {
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index e893a3983bd..934f9ce5018 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -148,7 +148,7 @@ static void make_edges_mdata_extend(
int totedge = *r_totedge;
int totedge_new;
EdgeHash *eh;
- unsigned int eh_reserve;
+ uint eh_reserve;
const MPoly *mp;
int i;
@@ -174,7 +174,7 @@ static void make_edges_mdata_extend(
if (totedge_new) {
EdgeHashIterator *ehi;
MEdge *medge;
- unsigned int e_index = totedge;
+ uint e_index = totedge;
*r_alledge = medge = (*r_alledge ?
MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) :
@@ -719,17 +719,17 @@ typedef struct EdgeLink {
typedef struct VertLink {
Link *next, *prev;
- unsigned int index;
+ uint index;
} VertLink;
-static void prependPolyLineVert(ListBase *lb, unsigned int index)
+static void prependPolyLineVert(ListBase *lb, uint index)
{
VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
vl->index = index;
BLI_addhead(lb, vl);
}
-static void appendPolyLineVert(ListBase *lb, unsigned int index)
+static void appendPolyLineVert(ListBase *lb, uint index)
{
VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
vl->index = index;
@@ -784,8 +784,8 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
bool closed = false;
int totpoly = 0;
MEdge *med_current = ((EdgeLink *)edges.last)->edge;
- unsigned int startVert = med_current->v1;
- unsigned int endVert = med_current->v2;
+ uint startVert = med_current->v1;
+ uint endVert = med_current->v2;
bool ok = true;
appendPolyLineVert(&polyline, startVert);
@@ -1113,7 +1113,7 @@ static void curve_to_mesh_eval_ensure(Object *object)
* Brecht says hold off with that. */
Mesh *mesh_eval = NULL;
BKE_displist_make_curveTypes_forRender(
- NULL, NULL, &remapped_object, &remapped_object.runtime.curve_cache->disp, &mesh_eval, false);
+ NULL, NULL, &remapped_object, &remapped_object.runtime.curve_cache->disp, false, &mesh_eval);
/* Note: this is to be consistent with `BKE_displist_make_curveTypes()`, however that is not a
* real issue currently, code here is broken in more than one way, fix(es) will be done
@@ -1704,7 +1704,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
tmp.texflag &= ~ME_AUTOSPACE_EVALUATED;
/* Clear any run-time data.
- * Even though this mesh wont typically have run-time data, the Python API can for e.g.
+ * Even though this mesh won't typically have run-time data, the Python API can for e.g.
* create loop-triangle cache here, which is confusing when left in the mesh, see: T81136. */
BKE_mesh_runtime_clear_geometry(&tmp);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 345546bc9cf..2260ffc668a 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -40,7 +40,6 @@
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
-#include "BLI_polyfill_2d.h"
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -478,7 +477,7 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts,
for (int i = 0; i < looptri_num; i++) {
const MLoopTri *lt = &looptri[i];
float *f_no = fnors[i];
- const unsigned int vtri[3] = {
+ const uint vtri[3] = {
mloop[lt->tri[0]].v,
mloop[lt->tri[1]].v,
mloop[lt->tri[2]].v,
@@ -1058,7 +1057,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
if (lnors_spacearr) {
float vec_curr[3], vec_prev[3];
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
const MVert *mv_pivot = &mverts[mv_pivot_index];
const MEdge *me_curr = &medges[ml_curr->e];
const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
@@ -1117,7 +1116,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
* number of sharp edges per vertex, I doubt the additional memory usage would be worth it,
* especially as it should not be a common case in real-life meshes anyway).
*/
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
const MVert *mv_pivot = &mverts[mv_pivot_index];
/* ml_curr would be mlfan_prev if we needed that one. */
@@ -1361,7 +1360,7 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
const int ml_prev_index,
const int mp_curr_index)
{
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
const int *e2lfan_curr;
const MLoop *mlfan_curr;
/* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
@@ -1715,8 +1714,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
loop_split_generator(NULL, &common_data);
}
else {
- TaskPool *task_pool = BLI_task_pool_create(
- &common_data, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH);
loop_split_generator(task_pool, &common_data);
@@ -2134,7 +2132,7 @@ void BKE_mesh_normals_loop_to_vertex(const int numVerts,
int i;
const MLoop *ml;
for (i = 0, ml = mloops; i < numLoops; i++, ml++) {
- const unsigned int v = ml->v;
+ const uint v = ml->v;
add_v3_v3(r_vert_clnors[v], clnors[i]);
vert_loops_nbr[v]++;
@@ -2316,7 +2314,7 @@ float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const
}
/* finally calculate the area */
- float area = area_poly_v3((const float(*)[3])vertexcos, (unsigned int)mpoly->totloop);
+ float area = area_poly_v3((const float(*)[3])vertexcos, (uint)mpoly->totloop);
return area;
}
@@ -2519,9 +2517,7 @@ void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop
}
}
-void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap,
- const MPoly *mp,
- const MLoop *mloop)
+void BKE_mesh_poly_edgebitmap_insert(uint *edge_bitmap, const MPoly *mp, const MLoop *mloop)
{
const MLoop *ml;
int i = mp->totloop;
@@ -2567,7 +2563,7 @@ bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
const MLoop *mloop = me->mloop;
const MVert *mvert = me->mvert;
zero_v3(r_cent);
- for (mpoly = me->mpoly; i--; mpoly++) {
+ for (; i--; mpoly++) {
int loopend = mpoly->loopstart + mpoly->totloop;
for (int j = mpoly->loopstart; j < loopend; j++) {
add_v3_v3(r_cent, mvert[mloop[j].v].co);
@@ -2789,638 +2785,6 @@ void BKE_mesh_calc_volume(const MVert *mverts,
/** \name NGon Tessellation (NGon/Tessface Conversion)
* \{ */
-/**
- * Convert a triangle or quadrangle of loop/poly data to tessface data
- */
-void BKE_mesh_loops_to_mface_corners(
- CustomData *fdata,
- CustomData *ldata,
- CustomData *UNUSED(pdata),
- unsigned int lindex[4],
- int findex,
- const int UNUSED(polyindex),
- const int mf_len, /* 3 or 4 */
-
- /* cache values to avoid lookups every time */
- const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
- const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
- const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
- const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
- const bool hasLNor /* CustomData_has_layer(ldata, CD_NORMAL) */
-)
-{
- MTFace *texface;
- MCol *mcol;
- MLoopCol *mloopcol;
- MLoopUV *mloopuv;
- int i, j;
-
- for (i = 0; i < numUV; i++) {
- texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
-
- for (j = 0; j < mf_len; j++) {
- mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
- copy_v2_v2(texface->uv[j], mloopuv->uv);
- }
- }
-
- for (i = 0; i < numCol; i++) {
- mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
-
- for (j = 0; j < mf_len; j++) {
- mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, (int)lindex[j], i);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
-
- if (hasPCol) {
- mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL);
-
- for (j = 0; j < mf_len; j++) {
- mloopcol = CustomData_get(ldata, (int)lindex[j], CD_PREVIEW_MLOOPCOL);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
-
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
- OrigSpaceLoop *lof;
-
- for (j = 0; j < mf_len; j++) {
- lof = CustomData_get(ldata, (int)lindex[j], CD_ORIGSPACE_MLOOP);
- copy_v2_v2(of->uv[j], lof->uv);
- }
- }
-
- if (hasLNor) {
- short(*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
-
- for (j = 0; j < mf_len; j++) {
- normal_float_to_short_v3(tlnors[j], CustomData_get(ldata, (int)lindex[j], CD_NORMAL));
- }
- }
-}
-
-/**
- * Convert all CD layers from loop/poly to tessface data.
- *
- * \param loopindices: is an array of an int[4] per tessface,
- * mapping tessface's verts to loops indices.
- *
- * \note when mface is not NULL, mface[face_index].v4
- * is used to test quads, else, loopindices[face_index][3] is used.
- */
-void BKE_mesh_loops_to_tessdata(CustomData *fdata,
- CustomData *ldata,
- MFace *mface,
- const int *polyindices,
- unsigned int (*loopindices)[4],
- const int num_faces)
-{
- /* Note: performances are sub-optimal when we get a NULL mface,
- * we could be ~25% quicker with dedicated code...
- * Issue is, unless having two different functions with nearly the same code,
- * there's not much ways to solve this. Better imho to live with it for now. :/ --mont29
- */
- const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
- const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
- const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
- const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
- int findex, i, j;
- const int *pidx;
- unsigned int(*lidx)[4];
-
- for (i = 0; i < numUV; i++) {
- MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
- pidx++, lidx++, findex++, texface++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
- }
- }
- }
-
- for (i = 0; i < numCol; i++) {
- MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
- MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasPCol) {
- MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
- MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
- OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
- }
- }
- }
-
- if (hasLoopNormal) {
- short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
- float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
- }
- }
- }
-
- if (hasLoopTangent) {
- /* need to do for all uv maps at some point */
- float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
- float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
- pidx++, lidx++, findex++) {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
-}
-
-void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata,
- CustomData *ldata,
- MFace *mface,
- const int *polyindices,
- unsigned int (*loopindices)[4],
- const int num_faces,
- const char *layer_name)
-{
- /* Note: performances are sub-optimal when we get a NULL mface,
- * we could be ~25% quicker with dedicated code...
- * Issue is, unless having two different functions with nearly the same code,
- * there's not much ways to solve this. Better imho to live with it for now. :/ --mont29
- */
-
- float(*ftangents)[4] = NULL;
- float(*ltangents)[4] = NULL;
-
- int findex, j;
- const int *pidx;
- unsigned int(*lidx)[4];
-
- if (layer_name) {
- ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
- }
- else {
- ltangents = CustomData_get_layer(ldata, CD_TANGENT);
- }
-
- if (ltangents) {
- /* need to do for all uv maps at some point */
- if (layer_name) {
- ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
- }
- else {
- ftangents = CustomData_get_layer(fdata, CD_TANGENT);
- }
- if (ftangents) {
- for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
- pidx++, lidx++, findex++) {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
- }
-}
-
-/**
- * Recreate tessellation.
- *
- * \param do_face_nor_copy: Controls whether the normals from the poly
- * are copied to the tessellated faces.
- *
- * \return number of tessellation faces.
- */
-int BKE_mesh_tessface_calc_ex(CustomData *fdata,
- CustomData *ldata,
- CustomData *pdata,
- MVert *mvert,
- int totface,
- int totloop,
- int totpoly,
- const bool do_face_nor_copy)
-{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
-
-#define USE_TESSFACE_SPEEDUP
-#define USE_TESSFACE_QUADS /* NEEDS FURTHER TESTING */
-
-/* We abuse MFace->edcode to tag quad faces. See below for details. */
-#define TESSFACE_IS_QUAD 1
-
- const int looptri_num = poly_to_tri_count(totpoly, totloop);
-
- MPoly *mp, *mpoly;
- MLoop *ml, *mloop;
- MFace *mface, *mf;
- MemArena *arena = NULL;
- int *mface_to_poly_map;
- unsigned int(*lindices)[4];
- int poly_index, mface_index;
- unsigned int j;
-
- mpoly = CustomData_get_layer(pdata, CD_MPOLY);
- mloop = CustomData_get_layer(ldata, CD_MLOOP);
-
- /* allocate the length of totfaces, avoid many small reallocs,
- * if all faces are tri's it will be correct, quads == 2x allocs */
- /* take care. we are _not_ calloc'ing so be sure to initialize each field */
- mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
- mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
- lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
-
- mface_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
- const unsigned int mp_totloop = (unsigned int)mp->totloop;
- unsigned int l1, l2, l3, l4;
- unsigned int *lidx;
- if (mp_totloop < 3) {
- /* do nothing */
- }
-
-#ifdef USE_TESSFACE_SPEEDUP
-
-# define ML_TO_MF(i1, i2, i3) \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* set loop indices, transformed to vert indices later */ \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = 0; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = 0; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = 0; \
- (void)0
-
-/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
-# define ML_TO_MF_QUAD() \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* set loop indices, transformed to vert indices later */ \
- l1 = mp_loopstart + 0; /* EXCEPTION */ \
- l2 = mp_loopstart + 1; /* EXCEPTION */ \
- l3 = mp_loopstart + 2; /* EXCEPTION */ \
- l4 = mp_loopstart + 3; /* EXCEPTION */ \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = mloop[l4].v; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = l4; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = TESSFACE_IS_QUAD; \
- (void)0
-
- else if (mp_totloop == 3) {
- ML_TO_MF(0, 1, 2);
- mface_index++;
- }
- else if (mp_totloop == 4) {
-# ifdef USE_TESSFACE_QUADS
- ML_TO_MF_QUAD();
- mface_index++;
-# else
- ML_TO_MF(0, 1, 2);
- mface_index++;
- ML_TO_MF(0, 2, 3);
- mface_index++;
-# endif
- }
-#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
-
- float normal[3];
-
- float axis_mat[3][3];
- float(*projverts)[2];
- unsigned int(*tris)[3];
-
- const unsigned int totfilltri = mp_totloop - 2;
-
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
-
- zero_v3(normal);
-
- /* calc normal, flipped: to get a positive 2d cross product */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
-
- /* project verts to 2d */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
-
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
-
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
-
- /* apply fill */
- for (j = 0; j < totfilltri; j++) {
- unsigned int *tri = tris[j];
- lidx = lindices[mface_index];
-
- mface_to_poly_map[mface_index] = poly_index;
- mf = &mface[mface_index];
-
- /* set loop indices, transformed to vert indices later */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
-
- mf->v1 = mloop[l1].v;
- mf->v2 = mloop[l2].v;
- mf->v3 = mloop[l3].v;
- mf->v4 = 0;
-
- lidx[0] = l1;
- lidx[1] = l2;
- lidx[2] = l3;
- lidx[3] = 0;
-
- mf->mat_nr = mp->mat_nr;
- mf->flag = mp->flag;
- mf->edcode = 0;
-
- mface_index++;
- }
-
- BLI_memarena_clear(arena);
- }
- }
-
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
-
- CustomData_free(fdata, totface);
- totface = mface_index;
-
- BLI_assert(totface <= looptri_num);
-
- /* not essential but without this we store over-alloc'd memory in the CustomData layers */
- if (LIKELY(looptri_num != totface)) {
- mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
- mface_to_poly_map = MEM_reallocN(mface_to_poly_map,
- sizeof(*mface_to_poly_map) * (size_t)totface);
- }
-
- CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
-
- /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
- * they are directly tessellated from */
- CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, ldata, totface);
-
- if (do_face_nor_copy) {
- /* If polys have a normals layer, copying that to faces can help
- * avoid the need to recalculate normals later */
- if (CustomData_has_layer(pdata, CD_NORMAL)) {
- float(*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
- float(*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
- for (mface_index = 0; mface_index < totface; mface_index++) {
- copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Polygons take care of their loops ordering, hence not of their vertices ordering.
- * Currently, our tfaces' fourth vertex index might be 0 even for a quad. However,
- * we know our fourth loop index is never 0 for quads (because they are sorted for polygons,
- * and our quads are still mere copies of their polygons).
- * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata
- * will use the fourth loop index as quad test.
- * ...
- */
- BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
- * test_index_face() will check this and rotate the tessellated face if needed.
- */
-#ifdef USE_TESSFACE_QUADS
- mf = mface;
- for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
- if (mf->edcode == TESSFACE_IS_QUAD) {
- test_index_face(mf, fdata, mface_index, 4);
- mf->edcode = 0;
- }
- }
-#endif
-
- MEM_freeN(lindices);
-
- return totface;
-
-#undef USE_TESSFACE_SPEEDUP
-#undef USE_TESSFACE_QUADS
-
-#undef ML_TO_MF
-#undef ML_TO_MF_QUAD
-}
-
-/**
- * Calculate tessellation into #MLoopTri which exist only for this purpose.
- */
-void BKE_mesh_recalc_looptri(const MLoop *mloop,
- const MPoly *mpoly,
- const MVert *mvert,
- int totloop,
- int totpoly,
- MLoopTri *mlooptri)
-{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
-
-#define USE_TESSFACE_SPEEDUP
-
- const MPoly *mp;
- const MLoop *ml;
- MLoopTri *mlt;
- MemArena *arena = NULL;
- int poly_index, mlooptri_index;
- unsigned int j;
-
- mlooptri_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
- const unsigned int mp_totloop = (unsigned int)mp->totloop;
- unsigned int l1, l2, l3;
- if (mp_totloop < 3) {
- /* do nothing */
- }
-
-#ifdef USE_TESSFACE_SPEEDUP
-
-# define ML_TO_MLT(i1, i2, i3) \
- { \
- mlt = &mlooptri[mlooptri_index]; \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3); \
- mlt->poly = (unsigned int)poly_index; \
- } \
- ((void)0)
-
- else if (mp_totloop == 3) {
- ML_TO_MLT(0, 1, 2);
- mlooptri_index++;
- }
- else if (mp_totloop == 4) {
- ML_TO_MLT(0, 1, 2);
- MLoopTri *mlt_a = mlt;
- mlooptri_index++;
- ML_TO_MLT(0, 2, 3);
- MLoopTri *mlt_b = mlt;
- mlooptri_index++;
-
- if (UNLIKELY(is_quad_flip_v3_first_third_fast(mvert[mloop[mlt_a->tri[0]].v].co,
- mvert[mloop[mlt_a->tri[1]].v].co,
- mvert[mloop[mlt_a->tri[2]].v].co,
- mvert[mloop[mlt_b->tri[2]].v].co))) {
- /* flip out of degenerate 0-2 state. */
- mlt_a->tri[2] = mlt_b->tri[2];
- mlt_b->tri[0] = mlt_a->tri[1];
- }
- }
-#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
-
- float normal[3];
-
- float axis_mat[3][3];
- float(*projverts)[2];
- unsigned int(*tris)[3];
-
- const unsigned int totfilltri = mp_totloop - 2;
-
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
-
- zero_v3(normal);
-
- /* calc normal, flipped: to get a positive 2d cross product */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
-
- /* project verts to 2d */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
-
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
-
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
-
- /* apply fill */
- for (j = 0; j < totfilltri; j++) {
- unsigned int *tri = tris[j];
-
- mlt = &mlooptri[mlooptri_index];
-
- /* set loop indices, transformed to vert indices later */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
-
- ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3);
- mlt->poly = (unsigned int)poly_index;
-
- mlooptri_index++;
- }
-
- BLI_memarena_clear(arena);
- }
- }
-
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
-
- BLI_assert(mlooptri_index == poly_to_tri_count(totpoly, totloop));
- UNUSED_VARS_NDEBUG(totloop);
-
-#undef USE_TESSFACE_SPEEDUP
-#undef ML_TO_MLT
-}
-
static void bm_corners_to_loops_ex(ID *id,
CustomData *fdata,
CustomData *ldata,
@@ -3630,7 +2994,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
}
- eh = BLI_edgehash_new_ex(__func__, (unsigned int)totedge_i);
+ eh = BLI_edgehash_new_ex(__func__, (uint)totedge_i);
/* build edge hash */
me = medge;
@@ -3769,12 +3133,12 @@ void BKE_mesh_polygon_flip_ex(MPoly *mpoly,
/* We also have to update loops edge
* (they will get their original 'other edge', that is,
* the original edge of their original previous loop)... */
- unsigned int prev_edge_index = mloop[loopstart].e;
+ uint prev_edge_index = mloop[loopstart].e;
mloop[loopstart].e = mloop[loopend].e;
for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
mloop[loopend].e = mloop[loopend - 1].e;
- SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
+ SWAP(uint, mloop[loopstart].e, prev_edge_index);
if (!loops_in_ldata) {
SWAP(MLoop, mloop[loopstart], mloop[loopend]);
@@ -4027,9 +3391,9 @@ void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
const MLoop *loopstart = mloop + mp->loopstart;
for (int j = 0; j < mp->totloop; j++) {
- unsigned int v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v;
- unsigned int v_curr = loopstart[j].v;
- unsigned int v_next = loopstart[(j + 1) % mp->totloop].v;
+ uint v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v;
+ uint v_curr = loopstart[j].v;
+ uint v_next = loopstart[(j + 1) % mp->totloop].v;
float tvec[3];
diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc
index 2a364b183b2..6ac1aa9b2b9 100644
--- a/source/blender/blenkernel/intern/mesh_fair.cc
+++ b/source/blender/blenkernel/intern/mesh_fair.cc
@@ -65,7 +65,7 @@ class FairingContext {
float r_adj_prev[3]) = 0;
/* Get the other vertex index for a loop. */
- virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) = 0;
+ virtual int other_vertex_index_from_loop(const int loop, const uint v) = 0;
int vertex_count_get()
{
@@ -257,7 +257,7 @@ class MeshFairingContext : public FairingContext {
copy_v3_v3(r_adj_prev, co_[ME_POLY_LOOP_PREV(mloop_, p, corner)->v]);
}
- int other_vertex_index_from_loop(const int loop, const unsigned int v) override
+ int other_vertex_index_from_loop(const int loop, const uint v) override
{
MEdge *e = &medge_[mloop_[loop].e];
if (e->v1 == v) {
@@ -332,7 +332,7 @@ class BMeshFairingContext : public FairingContext {
copy_v3_v3(r_adj_prev, bmloop_[loop]->prev->v->co);
}
- int other_vertex_index_from_loop(const int loop, const unsigned int v) override
+ int other_vertex_index_from_loop(const int loop, const uint v) override
{
BMLoop *l = bmloop_[loop];
BMVert *bmvert = BM_vert_at_index(bm, v);
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 81642b156d5..d4119f48193 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -48,8 +48,8 @@
UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
const MLoop *mloop,
const MLoopUV *mloopuv,
- unsigned int totpoly,
- unsigned int totvert,
+ uint totpoly,
+ uint totvert,
const float limit[2],
const bool selected,
const bool use_winding)
@@ -57,7 +57,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
UvVertMap *vmap;
UvMapVert *buf;
const MPoly *mp;
- unsigned int a;
+ uint a;
int i, totuv, nverts;
bool *winding = NULL;
@@ -115,7 +115,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
}
if (use_winding) {
- winding[a] = cross_poly_v2(tf_uv, (unsigned int)nverts) > 0;
+ winding[a] = cross_poly_v2(tf_uv, (uint)nverts) > 0;
}
}
}
@@ -176,7 +176,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
return vmap;
}
-UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v)
+UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, uint v)
{
return vmap->vert[v];
}
@@ -239,7 +239,7 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
const MPoly *p = &mpoly[i];
for (j = 0; j < p->totloop; j++) {
- unsigned int v = mloop[p->loopstart + j].v;
+ uint v = mloop[p->loopstart + j].v;
map[v].indices[map[v].count] = do_loops ? p->loopstart + j : i;
map[v].count++;
@@ -362,7 +362,7 @@ void BKE_mesh_vert_edge_map_create(
/* Find the users */
for (i = 0; i < totedge; i++) {
- const unsigned int v[2] = {medge[i].v1, medge[i].v2};
+ const uint v[2] = {medge[i].v1, medge[i].v2};
map[v[0]].indices[map[v[0]].count] = i;
map[v[1]].indices[map[v[1]].count] = i;
@@ -405,7 +405,7 @@ void BKE_mesh_vert_edge_vert_map_create(
/* Find the users */
for (i = 0; i < totedge; i++) {
- const unsigned int v[2] = {medge[i].v1, medge[i].v2};
+ const uint v[2] = {medge[i].v1, medge[i].v2};
map[v[0]].indices[map[v[0]].count] = (int)v[1];
map[v[1]].indices[map[v[1]].count] = (int)v[0];
@@ -1025,8 +1025,8 @@ static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
- const unsigned int v1 = loops[edge_to_loops->indices[0]].v;
- const unsigned int v2 = loops[edge_to_loops->indices[1]].v;
+ const uint v1 = loops[edge_to_loops->indices[0]].v;
+ const uint v2 = loops[edge_to_loops->indices[1]].v;
const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv;
const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv;
for (int i = 2; i < edge_to_loops->count; i += 2) {
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
index e3b5e5ea434..fb73152cb8e 100644
--- a/source/blender/blenkernel/intern/mesh_merge.c
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -179,13 +179,13 @@ static int cddm_poly_compare(MLoop *mloop_array,
/* Utility stuff for using GHash with polys, used by vertex merging. */
typedef struct PolyKey {
- int poly_index; /* index of the MPoly within the derived mesh */
- int totloops; /* number of loops in the poly */
- unsigned int hash_sum; /* Sum of all vertices indices */
- unsigned int hash_xor; /* Xor of all vertices indices */
+ int poly_index; /* index of the MPoly within the derived mesh */
+ int totloops; /* number of loops in the poly */
+ uint hash_sum; /* Sum of all vertices indices */
+ uint hash_xor; /* Xor of all vertices indices */
} PolyKey;
-static unsigned int poly_gset_hash_fn(const void *key)
+static uint poly_gset_hash_fn(const void *key)
{
const PolyKey *pk = key;
return pk->hash_sum;
@@ -331,8 +331,8 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh,
med = mesh->medge;
c = 0;
for (i = 0; i < totedge; i++, med++) {
- const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ const uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ const uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
if (LIKELY(v1 != v2)) {
void **val_p;
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 58d2a24f15b..b7cff624a04 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -787,7 +787,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
int j = 2;
while (j--) {
- const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2;
+ const uint vidx_dst = j ? e_dst->v1 : e_dst->v2;
/* Compute closest verts only once! */
if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
@@ -813,7 +813,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
/* Now, check all source edges of closest sources vertices,
* and select the one giving the smallest total verts-to-verts distance. */
for (j = 2; j--;) {
- const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2;
+ const uint vidx_dst = j ? e_dst->v1 : e_dst->v2;
const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist;
const int vidx_src = v_dst_to_src_map[vidx_dst].index;
int *eidx_src, k;
@@ -1542,7 +1542,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
mp_src = &polys_src[isld->indices[i]];
for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop;
lidx_src++) {
- const unsigned int vidx_src = loops_src[lidx_src].v;
+ const uint vidx_src = loops_src[lidx_src].v;
if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
num_verts_active++;
@@ -2418,8 +2418,7 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
tri_vidx_2d[1][2] = 3;
}
else {
- BLI_polyfill_calc(
- poly_vcos_2d, (unsigned int)mp->totloop, -1, (unsigned int(*)[3])tri_vidx_2d);
+ BLI_polyfill_calc(poly_vcos_2d, (uint)mp->totloop, -1, (uint(*)[3])tri_vidx_2d);
}
for (j = 0; j < tris_num; j++) {
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index 0a5aa360553..5a90d1f6ea5 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -67,20 +67,19 @@ struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
BKE_mesh_runtime_verttri_from_looptri(
verttri, mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(mesh));
- unsigned int totfaces = BKE_mesh_runtime_looptri_len(mesh);
- unsigned int totverts = mesh->totvert;
+ uint totfaces = BKE_mesh_runtime_looptri_len(mesh);
+ uint totverts = mesh->totvert;
float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts");
- unsigned int *faces = (unsigned int *)MEM_malloc_arrayN(
- totfaces * 3, sizeof(unsigned int), "remesh_input_faces");
+ uint *faces = (uint *)MEM_malloc_arrayN(totfaces * 3, sizeof(uint), "remesh_input_faces");
- for (unsigned int i = 0; i < totverts; i++) {
+ for (uint i = 0; i < totverts; i++) {
MVert *mvert = &mesh->mvert[i];
verts[i * 3] = mvert->co[0];
verts[i * 3 + 1] = mvert->co[1];
verts[i * 3 + 2] = mvert->co[2];
}
- for (unsigned int i = 0; i < totfaces; i++) {
+ for (uint i = 0; i < totfaces; i++) {
MVertTri *vt = &verttri[i];
faces[i * 3] = vt->tri[0];
faces[i * 3 + 1] = vt->tri[1];
@@ -171,20 +170,19 @@ static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh,
BKE_mesh_runtime_verttri_from_looptri(
verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh));
- unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
- unsigned int totverts = input_mesh->totvert;
+ uint totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
+ uint totverts = input_mesh->totvert;
float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts");
- unsigned int *faces = (unsigned int *)MEM_malloc_arrayN(
- totfaces * 3, sizeof(unsigned int), "remesh_input_faces");
+ uint *faces = (uint *)MEM_malloc_arrayN(totfaces * 3, sizeof(uint), "remesh_input_faces");
- for (unsigned int i = 0; i < totverts; i++) {
+ for (uint i = 0; i < totverts; i++) {
MVert *mvert = &input_mesh->mvert[i];
verts[i * 3] = mvert->co[0];
verts[i * 3 + 1] = mvert->co[1];
verts[i * 3 + 2] = mvert->co[2];
}
- for (unsigned int i = 0; i < totfaces; i++) {
+ for (uint i = 0; i < totfaces; i++) {
MVertTri *vt = &verttri[i];
faces[i * 3] = vt->tri[0];
faces[i * 3 + 1] = vt->tri[1];
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 22f29bef97e..011dd7e25ee 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -30,6 +30,7 @@
#include "DNA_object_types.h"
#include "BLI_math_geom.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BKE_bvhutils.h"
@@ -98,7 +99,7 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
*/
static void mesh_ensure_looptri_data(Mesh *mesh)
{
- const unsigned int totpoly = mesh->totpoly;
+ const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
BLI_assert(mesh->runtime.looptris.array_wip == NULL);
@@ -151,6 +152,12 @@ int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
return looptri_len;
}
+static void mesh_runtime_looptri_recalc_isolated(void *userdata)
+{
+ Mesh *mesh = userdata;
+ BKE_mesh_runtime_looptri_recalc(mesh);
+}
+
/* This is a ported copy of dm_getLoopTriArray(dm). */
const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
{
@@ -163,7 +170,8 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
}
else {
- BKE_mesh_runtime_looptri_recalc(mesh);
+ /* Must isolate multithreaded tasks while holding a mutex lock. */
+ BLI_task_isolate(mesh_runtime_looptri_recalc_isolated, mesh);
looptri = mesh->runtime.looptris.array;
}
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index 91c9951ae89..bd46407d060 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -14,6 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
@@ -23,7 +24,7 @@
namespace blender::bke::mesh_surface_sample {
-static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
+Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
{
/* This only updates a cache and can be considered to be logically const. */
const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
@@ -155,4 +156,117 @@ void sample_face_attribute(const Mesh &mesh,
});
}
+MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh,
+ const Span<float3> positions,
+ const Span<int> looptri_indices)
+ : mesh_(mesh), positions_(positions), looptri_indices_(looptri_indices)
+{
+ BLI_assert(positions.size() == looptri_indices.size());
+}
+
+Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
+{
+ if (!bary_coords_.is_empty()) {
+ BLI_assert(bary_coords_.size() == positions_.size());
+ return bary_coords_;
+ }
+ bary_coords_.reinitialize(positions_.size());
+
+ Span<MLoopTri> looptris = get_mesh_looptris(*mesh_);
+
+ for (const int i : bary_coords_.index_range()) {
+ const int looptri_index = looptri_indices_[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+
+ const int v0_index = mesh_->mloop[looptri.tri[0]].v;
+ const int v1_index = mesh_->mloop[looptri.tri[1]].v;
+ const int v2_index = mesh_->mloop[looptri.tri[2]].v;
+
+ interp_weights_tri_v3(bary_coords_[i],
+ mesh_->mvert[v0_index].co,
+ mesh_->mvert[v1_index].co,
+ mesh_->mvert[v2_index].co,
+ positions_[i]);
+ }
+ return bary_coords_;
+}
+
+Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
+{
+ if (!nearest_weights_.is_empty()) {
+ BLI_assert(nearest_weights_.size() == positions_.size());
+ return nearest_weights_;
+ }
+ nearest_weights_.reinitialize(positions_.size());
+
+ Span<MLoopTri> looptris = get_mesh_looptris(*mesh_);
+
+ for (const int i : nearest_weights_.index_range()) {
+ const int looptri_index = looptri_indices_[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+
+ const int v0_index = mesh_->mloop[looptri.tri[0]].v;
+ const int v1_index = mesh_->mloop[looptri.tri[1]].v;
+ const int v2_index = mesh_->mloop[looptri.tri[2]].v;
+
+ const float d0 = len_squared_v3v3(positions_[i], mesh_->mvert[v0_index].co);
+ const float d1 = len_squared_v3v3(positions_[i], mesh_->mvert[v1_index].co);
+ const float d2 = len_squared_v3v3(positions_[i], mesh_->mvert[v2_index].co);
+
+ nearest_weights_[i] = MIN3_PAIR(d0, d1, d2, float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
+ }
+ return nearest_weights_;
+}
+
+void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute,
+ OutputAttribute &dst_attribute,
+ eAttributeMapMode mode)
+{
+ if (!src_attribute || !dst_attribute) {
+ return;
+ }
+ const GVArray &src_varray = *src_attribute.varray;
+ GMutableSpan dst_span = dst_attribute.as_span();
+ if (src_varray.is_empty() || dst_span.is_empty()) {
+ return;
+ }
+
+ /* Compute barycentric coordinates only when they are needed. */
+ Span<float3> weights;
+ if (ELEM(src_attribute.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
+ switch (mode) {
+ case eAttributeMapMode::INTERPOLATED:
+ weights = ensure_barycentric_coords();
+ break;
+ case eAttributeMapMode::NEAREST:
+ weights = ensure_nearest_weights();
+ break;
+ }
+ }
+
+ /* Interpolate the source attributes on the surface. */
+ switch (src_attribute.domain) {
+ case ATTR_DOMAIN_POINT: {
+ sample_point_attribute(*mesh_, looptri_indices_, weights, src_varray, dst_span);
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ sample_face_attribute(*mesh_, looptri_indices_, src_varray, dst_span);
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ sample_corner_attribute(*mesh_, looptri_indices_, weights, src_varray, dst_span);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* Not yet supported. */
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index 6a7ff0851f5..2e22e521a13 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -656,7 +656,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
/* Calculation */
if (looptri_len != 0) {
- TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
new file mode 100644
index 00000000000..213f2929d63
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -0,0 +1,760 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * This file contains code for polygon tessellation
+ * (creating triangles from polygons).
+ *
+ * \see bmesh_mesh_tessellate.c for the #BMesh equivalent of this file.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h" /* Own include. */
+
+#include "BLI_strict_flags.h"
+
+/** Compared against total loops. */
+#define MESH_FACE_TESSELLATE_THREADED_LIMIT 4096
+
+/* -------------------------------------------------------------------- */
+/** \name MFace Tessellation
+ *
+ * #MFace is a legacy data-structure that should be avoided, use #MLoopTri instead.
+ * \{ */
+
+/**
+ * Convert all CD layers from loop/poly to tessface data.
+ *
+ * \param loopindices: is an array of an int[4] per tessface,
+ * mapping tessface's verts to loops indices.
+ *
+ * \note when mface is not NULL, mface[face_index].v4
+ * is used to test quads, else, loopindices[face_index][3] is used.
+ */
+static void mesh_loops_to_tessdata(CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ const int *polyindices,
+ uint (*loopindices)[4],
+ const int num_faces)
+{
+ /* NOTE(mont29): performances are sub-optimal when we get a NULL #MFace,
+ * we could be ~25% quicker with dedicated code.
+ * The issue is, unless having two different functions with nearly the same code,
+ * there's not much ways to solve this. Better IMHO to live with it for now (sigh). */
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
+ const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
+ const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
+ const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
+ int findex, i, j;
+ const int *pidx;
+ uint(*lidx)[4];
+
+ for (i = 0; i < numUV; i++) {
+ MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
+ MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++, texface++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
+ MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasPCol) {
+ MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
+ MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
+ OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ if (hasLoopNormal) {
+ short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
+ float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
+ }
+ }
+ }
+
+ if (hasLoopTangent) {
+ /* Need to do for all UV maps at some point. */
+ float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
+ float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++) {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
+ }
+ }
+}
+
+/**
+ * Recreate #MFace Tessellation.
+ *
+ * \param do_face_nor_copy: Controls whether the normals from the poly
+ * are copied to the tessellated faces.
+ *
+ * \return number of tessellation faces.
+ *
+ * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
+ * it's not used in many places and #MFace should be phased out.
+ */
+int BKE_mesh_tessface_calc_ex(CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ MVert *mvert,
+ int totface,
+ int totloop,
+ int totpoly,
+ const bool do_face_nor_copy)
+{
+#define USE_TESSFACE_SPEEDUP
+#define USE_TESSFACE_QUADS
+
+/* We abuse #MFace.edcode to tag quad faces. See below for details. */
+#define TESSFACE_IS_QUAD 1
+
+ const int looptri_num = poly_to_tri_count(totpoly, totloop);
+
+ MPoly *mp, *mpoly;
+ MLoop *ml, *mloop;
+ MFace *mface, *mf;
+ MemArena *arena = NULL;
+ int *mface_to_poly_map;
+ uint(*lindices)[4];
+ int poly_index, mface_index;
+ uint j;
+
+ mpoly = CustomData_get_layer(pdata, CD_MPOLY);
+ mloop = CustomData_get_layer(ldata, CD_MLOOP);
+
+ /* Allocate the length of `totfaces`, avoid many small reallocation's,
+ * if all faces are triangles it will be correct, `quads == 2x` allocations. */
+ /* Take care since memory is _not_ zeroed so be sure to initialize each field. */
+ mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
+ mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
+ lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
+
+ mface_index = 0;
+ mp = mpoly;
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ const uint mp_loopstart = (uint)mp->loopstart;
+ const uint mp_totloop = (uint)mp->totloop;
+ uint l1, l2, l3, l4;
+ uint *lidx;
+ if (mp_totloop < 3) {
+ /* Do nothing. */
+ }
+
+#ifdef USE_TESSFACE_SPEEDUP
+
+# define ML_TO_MF(i1, i2, i3) \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* Set loop indices, transformed to vert indices later. */ \
+ l1 = mp_loopstart + i1; \
+ l2 = mp_loopstart + i2; \
+ l3 = mp_loopstart + i3; \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = 0; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = 0; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = 0; \
+ (void)0
+
+/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
+# define ML_TO_MF_QUAD() \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* Set loop indices, transformed to vert indices later. */ \
+ l1 = mp_loopstart + 0; /* EXCEPTION */ \
+ l2 = mp_loopstart + 1; /* EXCEPTION */ \
+ l3 = mp_loopstart + 2; /* EXCEPTION */ \
+ l4 = mp_loopstart + 3; /* EXCEPTION */ \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = mloop[l4].v; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = l4; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = TESSFACE_IS_QUAD; \
+ (void)0
+
+ else if (mp_totloop == 3) {
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ }
+ else if (mp_totloop == 4) {
+# ifdef USE_TESSFACE_QUADS
+ ML_TO_MF_QUAD();
+ mface_index++;
+# else
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ ML_TO_MF(0, 2, 3);
+ mface_index++;
+# endif
+ }
+#endif /* USE_TESSFACE_SPEEDUP */
+ else {
+ const float *co_curr, *co_prev;
+
+ float normal[3];
+
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ uint(*tris)[3];
+
+ const uint totfilltri = mp_totloop - 2;
+
+ if (UNLIKELY(arena == NULL)) {
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
+ projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
+
+ zero_v3(normal);
+
+ /* Calculate the normal, flipped: to get a positive 2D cross product. */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
+
+ /* Project verts to 2D. */
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
+
+ ml = mloop + mp_loopstart;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
+
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
+
+ /* Apply fill. */
+ for (j = 0; j < totfilltri; j++) {
+ uint *tri = tris[j];
+ lidx = lindices[mface_index];
+
+ mface_to_poly_map[mface_index] = poly_index;
+ mf = &mface[mface_index];
+
+ /* Set loop indices, transformed to vert indices later. */
+ l1 = mp_loopstart + tri[0];
+ l2 = mp_loopstart + tri[1];
+ l3 = mp_loopstart + tri[2];
+
+ mf->v1 = mloop[l1].v;
+ mf->v2 = mloop[l2].v;
+ mf->v3 = mloop[l3].v;
+ mf->v4 = 0;
+
+ lidx[0] = l1;
+ lidx[1] = l2;
+ lidx[2] = l3;
+ lidx[3] = 0;
+
+ mf->mat_nr = mp->mat_nr;
+ mf->flag = mp->flag;
+ mf->edcode = 0;
+
+ mface_index++;
+ }
+
+ BLI_memarena_clear(arena);
+ }
+ }
+
+ if (arena) {
+ BLI_memarena_free(arena);
+ arena = NULL;
+ }
+
+ CustomData_free(fdata, totface);
+ totface = mface_index;
+
+ BLI_assert(totface <= looptri_num);
+
+ /* Not essential but without this we store over-allocated memory in the #CustomData layers. */
+ if (LIKELY(looptri_num != totface)) {
+ mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
+ mface_to_poly_map = MEM_reallocN(mface_to_poly_map,
+ sizeof(*mface_to_poly_map) * (size_t)totface);
+ }
+
+ CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
+
+ /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons
+ * they are directly tessellated from. */
+ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
+
+ if (do_face_nor_copy) {
+ /* If polys have a normals layer, copying that to faces can help
+ * avoid the need to recalculate normals later. */
+ if (CustomData_has_layer(pdata, CD_NORMAL)) {
+ float(*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
+ float(*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
+ for (mface_index = 0; mface_index < totface; mface_index++) {
+ copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
+ }
+ }
+ }
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Polygons take care of their loops ordering, hence not of their vertices ordering.
+ * Currently, our tfaces' fourth vertex index might be 0 even for a quad.
+ * However, we know our fourth loop index is never 0 for quads
+ * (because they are sorted for polygons, and our quads are still mere copies of their polygons).
+ * So we pass NULL as MFace pointer, and #mesh_loops_to_tessdata
+ * will use the fourth loop index as quad test. */
+ mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
+ * BKE_mesh_mface_index_validate() will check this and rotate the tessellated face if needed.
+ */
+#ifdef USE_TESSFACE_QUADS
+ mf = mface;
+ for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
+ if (mf->edcode == TESSFACE_IS_QUAD) {
+ BKE_mesh_mface_index_validate(mf, fdata, mface_index, 4);
+ mf->edcode = 0;
+ }
+ }
+#endif
+
+ MEM_freeN(lindices);
+
+ return totface;
+
+#undef USE_TESSFACE_SPEEDUP
+#undef USE_TESSFACE_QUADS
+
+#undef ML_TO_MF
+#undef ML_TO_MF_QUAD
+}
+
+void BKE_mesh_tessface_calc(Mesh *mesh)
+{
+ mesh->totface = BKE_mesh_tessface_calc_ex(
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->mvert,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ /* Calculate normals right after, don't copy from polys here. */
+ false);
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Tessellation
+ *
+ * Fill in #MLoopTri data-structure.
+ * \{ */
+
+/**
+ * \param face_normal: This will be optimized out as a constant.
+ */
+BLI_INLINE void mesh_calc_tessellation_for_face_impl(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ uint poly_index,
+ MLoopTri *mlt,
+ MemArena **pf_arena_p,
+ const bool face_normal,
+ const float normal_precalc[3])
+{
+ const uint mp_loopstart = (uint)mpoly[poly_index].loopstart;
+ const uint mp_totloop = (uint)mpoly[poly_index].totloop;
+
+#define ML_TO_MLT(i1, i2, i3) \
+ { \
+ ARRAY_SET_ITEMS(mlt->tri, mp_loopstart + i1, mp_loopstart + i2, mp_loopstart + i3); \
+ mlt->poly = poly_index; \
+ } \
+ ((void)0)
+
+ switch (mp_totloop) {
+ case 3: {
+ ML_TO_MLT(0, 1, 2);
+ break;
+ }
+ case 4: {
+ ML_TO_MLT(0, 1, 2);
+ MLoopTri *mlt_a = mlt++;
+ ML_TO_MLT(0, 2, 3);
+ MLoopTri *mlt_b = mlt;
+
+ if (UNLIKELY(face_normal ? is_quad_flip_v3_first_third_fast_with_normal(
+ /* Simpler calculation (using the normal). */
+ mvert[mloop[mlt_a->tri[0]].v].co,
+ mvert[mloop[mlt_a->tri[1]].v].co,
+ mvert[mloop[mlt_a->tri[2]].v].co,
+ mvert[mloop[mlt_b->tri[2]].v].co,
+ normal_precalc) :
+ is_quad_flip_v3_first_third_fast(
+ /* Expensive calculation (no normal). */
+ mvert[mloop[mlt_a->tri[0]].v].co,
+ mvert[mloop[mlt_a->tri[1]].v].co,
+ mvert[mloop[mlt_a->tri[2]].v].co,
+ mvert[mloop[mlt_b->tri[2]].v].co))) {
+ /* Flip out of degenerate 0-2 state. */
+ mlt_a->tri[2] = mlt_b->tri[2];
+ mlt_b->tri[0] = mlt_a->tri[1];
+ }
+ break;
+ }
+ default: {
+ const MLoop *ml;
+ float axis_mat[3][3];
+
+ /* Calculate `axis_mat` to project verts to 2D. */
+ if (face_normal == false) {
+ float normal[3];
+ const float *co_curr, *co_prev;
+
+ zero_v3(normal);
+
+ /* Calc normal, flipped: to get a positive 2D cross product. */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (uint j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
+ }
+ else {
+ axis_dominant_v3_to_m3_negate(axis_mat, normal_precalc);
+ }
+
+ const uint totfilltri = mp_totloop - 2;
+
+ MemArena *pf_arena = *pf_arena_p;
+ if (UNLIKELY(pf_arena == NULL)) {
+ pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ uint(*tris)[3] = tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * (size_t)totfilltri);
+ float(*projverts)[2] = projverts = BLI_memarena_alloc(
+ pf_arena, sizeof(*projverts) * (size_t)mp_totloop);
+
+ ml = mloop + mp_loopstart;
+ for (uint j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
+
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, pf_arena);
+
+ /* Apply fill. */
+ for (uint j = 0; j < totfilltri; j++, mlt++) {
+ const uint *tri = tris[j];
+ ML_TO_MLT(tri[0], tri[1], tri[2]);
+ }
+
+ BLI_memarena_clear(pf_arena);
+
+ break;
+ }
+ }
+#undef ML_TO_MLT
+}
+
+static void mesh_calc_tessellation_for_face(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ uint poly_index,
+ MLoopTri *mlt,
+ MemArena **pf_arena_p)
+{
+ mesh_calc_tessellation_for_face_impl(
+ mloop, mpoly, mvert, poly_index, mlt, pf_arena_p, false, NULL);
+}
+
+static void mesh_calc_tessellation_for_face_with_normal(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ uint poly_index,
+ MLoopTri *mlt,
+ MemArena **pf_arena_p,
+ const float normal_precalc[3])
+{
+ mesh_calc_tessellation_for_face_impl(
+ mloop, mpoly, mvert, poly_index, mlt, pf_arena_p, true, normal_precalc);
+}
+
+static void mesh_recalc_looptri__single_threaded(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ int totloop,
+ int totpoly,
+ MLoopTri *mlooptri,
+ const float (*poly_normals)[3])
+{
+ MemArena *pf_arena = NULL;
+ const MPoly *mp = mpoly;
+ uint tri_index = 0;
+
+ if (poly_normals != NULL) {
+ for (uint poly_index = 0; poly_index < (uint)totpoly; poly_index++, mp++) {
+ mesh_calc_tessellation_for_face_with_normal(mloop,
+ mpoly,
+ mvert,
+ poly_index,
+ &mlooptri[tri_index],
+ &pf_arena,
+ poly_normals[poly_index]);
+ tri_index += (uint)(mp->totloop - 2);
+ }
+ }
+ else {
+ for (uint poly_index = 0; poly_index < (uint)totpoly; poly_index++, mp++) {
+ mesh_calc_tessellation_for_face(
+ mloop, mpoly, mvert, poly_index, &mlooptri[tri_index], &pf_arena);
+ tri_index += (uint)(mp->totloop - 2);
+ }
+ }
+
+ if (pf_arena) {
+ BLI_memarena_free(pf_arena);
+ pf_arena = NULL;
+ }
+ BLI_assert(tri_index == (uint)poly_to_tri_count(totpoly, totloop));
+ UNUSED_VARS_NDEBUG(totloop);
+}
+
+struct TessellationUserData {
+ const MLoop *mloop;
+ const MPoly *mpoly;
+ const MVert *mvert;
+
+ /** Output array. */
+ MLoopTri *mlooptri;
+
+ /** Optional pre-calculated polygon normals array. */
+ const float (*poly_normals)[3];
+};
+
+struct TessellationUserTLS {
+ MemArena *pf_arena;
+};
+
+static void mesh_calc_tessellation_for_face_fn(void *__restrict userdata,
+ const int index,
+ const TaskParallelTLS *__restrict tls)
+{
+ const struct TessellationUserData *data = userdata;
+ struct TessellationUserTLS *tls_data = tls->userdata_chunk;
+ const int tri_index = poly_to_tri_count(index, data->mpoly[index].loopstart);
+ mesh_calc_tessellation_for_face_impl(data->mloop,
+ data->mpoly,
+ data->mvert,
+ (uint)index,
+ &data->mlooptri[tri_index],
+ &tls_data->pf_arena,
+ false,
+ NULL);
+}
+
+static void mesh_calc_tessellation_for_face_with_normal_fn(void *__restrict userdata,
+ const int index,
+ const TaskParallelTLS *__restrict tls)
+{
+ const struct TessellationUserData *data = userdata;
+ struct TessellationUserTLS *tls_data = tls->userdata_chunk;
+ const int tri_index = poly_to_tri_count(index, data->mpoly[index].loopstart);
+ mesh_calc_tessellation_for_face_impl(data->mloop,
+ data->mpoly,
+ data->mvert,
+ (uint)index,
+ &data->mlooptri[tri_index],
+ &tls_data->pf_arena,
+ true,
+ data->poly_normals[index]);
+}
+
+static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
+{
+ struct TessellationUserTLS *tls_data = tls_v;
+ if (tls_data->pf_arena) {
+ BLI_memarena_free(tls_data->pf_arena);
+ }
+}
+
+static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ int UNUSED(totloop),
+ int totpoly,
+ MLoopTri *mlooptri,
+ const float (*poly_normals)[3])
+{
+ struct TessellationUserTLS tls_data_dummy = {NULL};
+
+ struct TessellationUserData data = {
+ .mloop = mloop,
+ .mpoly = mpoly,
+ .mvert = mvert,
+ .mlooptri = mlooptri,
+ .poly_normals = poly_normals,
+ };
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+
+ settings.userdata_chunk = &tls_data_dummy;
+ settings.userdata_chunk_size = sizeof(tls_data_dummy);
+
+ settings.func_free = mesh_calc_tessellation_for_face_free_fn;
+
+ BLI_task_parallel_range(0,
+ totpoly,
+ &data,
+ poly_normals ? mesh_calc_tessellation_for_face_with_normal_fn :
+ mesh_calc_tessellation_for_face_fn,
+ &settings);
+}
+
+/**
+ * Calculate tessellation into #MLoopTri which exist only for this purpose.
+ */
+void BKE_mesh_recalc_looptri(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ int totloop,
+ int totpoly,
+ MLoopTri *mlooptri)
+{
+ if (totloop < MESH_FACE_TESSELLATE_THREADED_LIMIT) {
+ mesh_recalc_looptri__single_threaded(mloop, mpoly, mvert, totloop, totpoly, mlooptri, NULL);
+ }
+ else {
+ mesh_recalc_looptri__multi_threaded(mloop, mpoly, mvert, totloop, totpoly, mlooptri, NULL);
+ }
+}
+
+/**
+ * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
+ * (used to avoid having to calculate the face normal for NGON tessellation).
+ *
+ * \note Only use this function if normals have already been calculated, there is no need
+ * to calculate normals just to use this function as it will cause the normals for triangles
+ * to be calculated which aren't needed for tessellation.
+ */
+void BKE_mesh_recalc_looptri_with_normals(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ int totloop,
+ int totpoly,
+ MLoopTri *mlooptri,
+ const float (*poly_normals)[3])
+{
+ BLI_assert(poly_normals != NULL);
+ if (totloop < MESH_FACE_TESSELLATE_THREADED_LIMIT) {
+ mesh_recalc_looptri__single_threaded(
+ mloop, mpoly, mvert, totloop, totpoly, mlooptri, poly_normals);
+ }
+ else {
+ mesh_recalc_looptri__multi_threaded(
+ mloop, mpoly, mvert, totloop, totpoly, mlooptri, poly_normals);
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index b3c53df2d5f..df84cf6607f 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -63,7 +63,7 @@ typedef union {
typedef struct SortFace {
EdgeUUID es[4];
- unsigned int index;
+ uint index;
} SortFace;
/* Used to detect polys (faces) using exactly the same vertices. */
@@ -72,7 +72,7 @@ typedef struct SortPoly {
int *verts;
int numverts;
int loopstart;
- unsigned int index;
+ uint index;
bool invalid; /* Poly index. */
} SortPoly;
@@ -217,19 +217,29 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
* Validate the mesh, \a do_fixes requires \a mesh to be non-null.
*
* \return false if no changes needed to be made.
+ *
+ * Vertex Normals
+ * ==============
+ *
+ * While zeroed normals are checked, these checks aren't comprehensive.
+ * Technically, to detect errors here a normal recalculation and comparison is necessary.
+ * However this function is mainly to prevent severe errors in geometry
+ * (invalid data that will crash Blender, or cause some features to behave incorrectly),
+ * not to detect subtle differences in the resulting normals which could be caused
+ * by importers that load normals (for example).
*/
/* NOLINTNEXTLINE: readability-function-size */
bool BKE_mesh_validate_arrays(Mesh *mesh,
MVert *mverts,
- unsigned int totvert,
+ uint totvert,
MEdge *medges,
- unsigned int totedge,
+ uint totedge,
MFace *mfaces,
- unsigned int totface,
+ uint totface,
MLoop *mloops,
- unsigned int totloop,
+ uint totloop,
MPoly *mpolys,
- unsigned int totpoly,
+ uint totpoly,
MDeformVert *dverts, /* assume totvert length */
const bool do_verbose,
const bool do_fixes,
@@ -260,7 +270,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
MEdge *me;
MLoop *ml;
MPoly *mp;
- unsigned int i, j;
+ uint i, j;
int *v;
bool is_valid = true;
@@ -328,10 +338,21 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
if (fix_normal) {
- PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
- if (do_fixes) {
- mv->no[2] = SHRT_MAX;
- fix_flag.verts = true;
+ /* If the vertex normal accumulates to zero or isn't part of a face, the location is used.
+ * When the location is also zero, a zero normal warning should not be raised.
+ * since this is the expected behavior of normal calculation.
+ *
+ * This avoids false positives but isn't foolproof as it's possible the vertex
+ * is part of a polygon that has a normal which this vertex should be using,
+ * although it's also possible degenerate/opposite faces accumulate to a zero vector.
+ * To detect this a full normal recalculation would be needed, which is out of scope
+ * for a basic validity check (see "Vertex Normal" in the doc-string). */
+ if (!is_zero_v3(mv->co)) {
+ PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
+ if (do_fixes) {
+ mv->no[2] = SHRT_MAX;
+ fix_flag.verts = true;
+ }
}
}
}
@@ -398,14 +419,14 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces");
SortFace *sf;
SortFace *sf_prev;
- unsigned int totsortface = 0;
+ uint totsortface = 0;
PRINT_ERR("No Polys, only tessellated Faces");
for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
bool remove = false;
int fidx;
- unsigned int fv[4];
+ uint fv[4];
fidx = mf->v4 ? 3 : 2;
do {
@@ -815,7 +836,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
/* Not technically incorrect since this is unsigned, however,
- * a value over INT_MAX is almost certainly caused by wrapping an unsigned int. */
+ * a value over INT_MAX is almost certainly caused by wrapping an uint. */
if (dw->def_nr >= INT_MAX) {
PRINT_ERR("\tVertex deform %u, has invalid group %u", i, dw->def_nr);
if (do_fixes) {
@@ -1279,7 +1300,7 @@ void BKE_mesh_strip_loose_edges(Mesh *me)
MEdge *e;
MLoop *l;
int a, b;
- unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__);
+ uint *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__);
for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) {
if (e->v1 != e->v2) {
@@ -1317,13 +1338,12 @@ void BKE_mesh_strip_loose_edges(Mesh *me)
/* make edges in a Mesh, for outside of editmode */
struct EdgeSort {
- unsigned int v1, v2;
+ uint v1, v2;
char is_loose, is_draw;
};
/* edges have to be added with lowest index first for sorting */
-static void to_edgesort(
- struct EdgeSort *ed, unsigned int v1, unsigned int v2, char is_loose, short is_draw)
+static void to_edgesort(struct EdgeSort *ed, uint v1, uint v2, char is_loose, short is_draw)
{
if (v1 < v2) {
ed->v1 = v1;
@@ -1378,8 +1398,8 @@ static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
EdgeHash *hash;
struct EdgeSort *edsort, *ed;
int a, totedge = 0;
- unsigned int totedge_final = 0;
- unsigned int edge_index;
+ uint totedge_final = 0;
+ uint edge_index;
/* we put all edges in array, sort them, and detect doubles that way */
@@ -1442,10 +1462,10 @@ static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
med->flag |= ME_LOOSEEDGE;
}
- /* order is swapped so extruding this edge as a surface wont flip face normals
+ /* order is swapped so extruding this edge as a surface won't flip face normals
* with cyclic curves */
if (ed->v1 + 1 != ed->v2) {
- SWAP(unsigned int, med->v1, med->v2);
+ SWAP(uint, med->v1, med->v2);
}
med++;
}
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index 0b0aeb50d37..574ab785445 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -87,7 +87,7 @@ static void reserve_hash_maps(const Mesh *mesh,
MutableSpan<EdgeMap> edge_maps)
{
const int totedge_guess = std::max(keep_existing_edges ? mesh->totedge : 0, mesh->totpoly * 2);
- parallel_for_each(
+ threading::parallel_for_each(
edge_maps, [&](EdgeMap &edge_map) { edge_map.reserve(totedge_guess / edge_maps.size()); });
}
@@ -96,7 +96,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh,
uint32_t parallel_mask)
{
/* Assume existing edges are valid. */
- parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
+ threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - &edge_maps[0];
for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) {
OrderedEdge ordered_edge{edge.v1, edge.v2};
@@ -113,7 +113,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
uint32_t parallel_mask)
{
const Span<MLoop> loops{mesh->mloop, mesh->totloop};
- parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
+ threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - &edge_maps[0];
for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) {
Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
@@ -146,7 +146,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
edge_index_offsets[i + 1] = edge_index_offsets[i] + edge_maps[i].size();
}
- parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
+ threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - &edge_maps[0];
int new_edge_index = edge_index_offsets[task_index];
@@ -174,7 +174,7 @@ static void update_edge_indices_in_poly_loops(Mesh *mesh,
uint32_t parallel_mask)
{
const MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) {
for (const int poly_index : range) {
MPoly &poly = mesh->mpoly[poly_index];
MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
@@ -215,7 +215,7 @@ static int get_parallel_maps_count(const Mesh *mesh)
static void clear_hash_tables(MutableSpan<EdgeMap> edge_maps)
{
- parallel_for_each(edge_maps, [](EdgeMap &edge_map) { edge_map.clear(); });
+ threading::parallel_for_each(edge_maps, [](EdgeMap &edge_map) { edge_map.clear(); });
}
} // namespace blender::bke::calc_edges
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c
index 5df9f7816e3..fe6af432314 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.c
+++ b/source/blender/blenkernel/intern/mesh_wrapper.c
@@ -40,6 +40,7 @@
#include "BLI_ghash.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -58,7 +59,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
const Mesh *me_settings)
{
Mesh *me = BKE_id_new_nomain(ID_ME, NULL);
- BKE_mesh_copy_settings(me, me_settings);
+ BKE_mesh_copy_parameters_for_eval(me, me_settings);
BKE_mesh_runtime_ensure_edit_data(me);
me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
@@ -95,15 +96,9 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings);
}
-void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
+static void mesh_wrapper_ensure_mdata_isolated(void *userdata)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
-
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
- BLI_mutex_unlock(mesh_eval_mutex);
- return;
- }
+ Mesh *me = userdata;
const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type;
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
@@ -136,6 +131,20 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
if (me->runtime.wrapper_type_finalize) {
BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
}
+}
+
+void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
+{
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
+ BLI_mutex_lock(mesh_eval_mutex);
+
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return;
+ }
+
+ /* Must isolate multithreaded tasks while holding a mutex lock. */
+ BLI_task_isolate(mesh_wrapper_ensure_mdata_isolated, me);
BLI_mutex_unlock(mesh_eval_mutex);
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 3b67237f5eb..e60f0102b9a 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -729,7 +729,6 @@ Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
ArmatureGpencilModifierData *agmd = NULL;
GpencilModifierData *gmd = BKE_gpencil_modifiers_get_virtual_modifierlist(
ob, &gpencilvirtualModifierData);
- gmd = ob->greasepencil_modifiers.first;
/* return the first selected armature, this lets us use multiple armatures */
for (; gmd; gmd = gmd->next) {
@@ -749,7 +748,6 @@ Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
VirtualModifierData virtualModifierData;
ArmatureModifierData *amd = NULL;
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
- md = ob->modifiers.first;
/* return the first selected armature, this lets us use multiple armatures */
for (; md; md = md->next) {
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index a3eb55d8c4a..4e0e784a5b8 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -3342,8 +3342,6 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
const char *name)
{
bNodeSocketType *stype = nodeSocketTypeFind(idname);
- int own_index = ntree->cur_index++;
-
if (stype == nullptr) {
return nullptr;
}
@@ -3355,7 +3353,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
sock->type = SOCK_CUSTOM; /* int type undefined by default */
/* assign new unique index */
- own_index = ntree->cur_index++;
+ const int own_index = ntree->cur_index++;
/* use the own_index as socket identifier */
if (in_out == SOCK_IN) {
BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index);
@@ -5058,7 +5056,10 @@ static void registerGeometryNodes()
register_node_type_geo_curve_deform();
register_node_type_geo_curve_length();
register_node_type_geo_curve_to_mesh();
+ register_node_type_geo_curve_to_points();
register_node_type_geo_curve_resample();
+ register_node_type_geo_curve_reverse();
+ register_node_type_geo_curve_subdivide();
register_node_type_geo_delete_geometry();
register_node_type_geo_edge_split();
register_node_type_geo_input_material();
@@ -5083,8 +5084,10 @@ static void registerGeometryNodes()
register_node_type_geo_point_separate();
register_node_type_geo_point_translate();
register_node_type_geo_points_to_volume();
+ register_node_type_geo_raycast();
register_node_type_geo_sample_texture();
register_node_type_geo_select_by_material();
+ register_node_type_geo_separate_components();
register_node_type_geo_subdivide();
register_node_type_geo_subdivision_surface();
register_node_type_geo_switch();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index b73f6a5b78c..8cfd75b015c 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -957,8 +957,8 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
ob, eModifierType_Fluidsim);
if (fluidmd && fluidmd->fss) {
- BLO_read_id_address(
- reader, ob->id.lib, &fluidmd->fss->ipo); /* XXX deprecated - old animation system */
+ /* XXX: deprecated - old animation system. */
+ BLO_read_id_address(reader, ob->id.lib, &fluidmd->fss->ipo);
}
}
@@ -2890,7 +2890,7 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
/* copy transform
* - cob means this proxy comes from a collection, just apply the matrix
- * so the object wont move from its dupli-transform.
+ * so the object won't move from its dupli-transform.
*
* - no cob means this is being made from a linked object,
* this is closer to making a copy of the object - in-place. */
@@ -4447,7 +4447,7 @@ bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc
}
/** Get evaluated mesh for given object. */
-Mesh *BKE_object_get_evaluated_mesh(Object *object)
+Mesh *BKE_object_get_evaluated_mesh(const Object *object)
{
ID *data_eval = object->runtime.data_eval;
return (data_eval && GS(data_eval->name) == ID_ME) ? (Mesh *)data_eval : NULL;
@@ -4460,7 +4460,7 @@ Mesh *BKE_object_get_evaluated_mesh(Object *object)
* - For copied-on-write objects it will give pointer to a copied-on-write
* mesh which corresponds to original object's mesh.
*/
-Mesh *BKE_object_get_pre_modified_mesh(Object *object)
+Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
{
if (object->type == OB_MESH && object->runtime.data_orig != NULL) {
BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
@@ -4481,7 +4481,7 @@ Mesh *BKE_object_get_pre_modified_mesh(Object *object)
* - For evaluated objects it will be same mesh as corresponding original
* object uses as data.
*/
-Mesh *BKE_object_get_original_mesh(Object *object)
+Mesh *BKE_object_get_original_mesh(const Object *object)
{
Mesh *result = NULL;
if (object->id.orig_id == NULL) {
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index e6909127503..b1afd968bdc 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -349,38 +349,45 @@ void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object)
BKE_object_eval_proxy_copy(depsgraph, object);
}
-void BKE_object_batch_cache_dirty_tag(Object *ob)
+void BKE_object_data_batch_cache_dirty_tag(ID *object_data)
{
- switch (ob->type) {
- case OB_MESH:
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ switch (GS(object_data->name)) {
+ case ID_ME:
+ BKE_mesh_batch_cache_dirty_tag((struct Mesh *)object_data, BKE_MESH_BATCH_DIRTY_ALL);
break;
- case OB_LATTICE:
- BKE_lattice_batch_cache_dirty_tag(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
+ case ID_LT:
+ BKE_lattice_batch_cache_dirty_tag((struct Lattice *)object_data,
+ BKE_LATTICE_BATCH_DIRTY_ALL);
break;
- case OB_CURVE:
- case OB_FONT:
- case OB_SURF:
- BKE_curve_batch_cache_dirty_tag(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
+ case ID_CU:
+ BKE_curve_batch_cache_dirty_tag((struct Curve *)object_data, BKE_CURVE_BATCH_DIRTY_ALL);
break;
- case OB_MBALL:
- BKE_mball_batch_cache_dirty_tag(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
+ case ID_MB:
+ BKE_mball_batch_cache_dirty_tag((struct MetaBall *)object_data, BKE_MBALL_BATCH_DIRTY_ALL);
break;
- case OB_GPENCIL:
- BKE_gpencil_batch_cache_dirty_tag(ob->data);
+ case ID_GD:
+ BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)object_data);
break;
- case OB_HAIR:
- BKE_hair_batch_cache_dirty_tag(ob->data, BKE_HAIR_BATCH_DIRTY_ALL);
+ case ID_HA:
+ BKE_hair_batch_cache_dirty_tag((struct Hair *)object_data, BKE_HAIR_BATCH_DIRTY_ALL);
break;
- case OB_POINTCLOUD:
- BKE_pointcloud_batch_cache_dirty_tag(ob->data, BKE_POINTCLOUD_BATCH_DIRTY_ALL);
+ case ID_PT:
+ BKE_pointcloud_batch_cache_dirty_tag((struct PointCloud *)object_data,
+ BKE_POINTCLOUD_BATCH_DIRTY_ALL);
break;
- case OB_VOLUME:
- BKE_volume_batch_cache_dirty_tag(ob->data, BKE_VOLUME_BATCH_DIRTY_ALL);
+ case ID_VO:
+ BKE_volume_batch_cache_dirty_tag((struct Volume *)object_data, BKE_VOLUME_BATCH_DIRTY_ALL);
+ break;
+ default:
break;
}
}
+void BKE_object_batch_cache_dirty_tag(Object *ob)
+{
+ BKE_object_data_batch_cache_dirty_tag(ob->data);
+}
+
void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 9b9ed0adcf4..9d53dad8d03 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -663,7 +663,7 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
osd.scale = scale;
osd.chop_amount = chop_amount;
- pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH);
BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 3ae5d039125..021121034f1 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -384,8 +384,9 @@ void BKE_particle_partdeflect_blend_read_lib(BlendLibReader *reader, ID *id, Par
static void particle_settings_blend_read_lib(BlendLibReader *reader, ID *id)
{
ParticleSettings *part = (ParticleSettings *)id;
- BLO_read_id_address(
- reader, part->id.lib, &part->ipo); /* XXX deprecated - old animation system */
+
+ /* XXX: deprecated - old animation system. */
+ BLO_read_id_address(reader, part->id.lib, &part->ipo);
BLO_read_id_address(reader, part->id.lib, &part->instance_object);
BLO_read_id_address(reader, part->id.lib, &part->instance_collection);
@@ -1437,7 +1438,7 @@ static void do_particle_interpolation(ParticleSystem *psys,
int point_vel = (point && point->keys->vel);
float real_t, dfra, keytime, invdt = 1.0f;
- /* billboards wont fill in all of these, so start cleared */
+ /* billboards won't fill in all of these, so start cleared */
memset(keys, 0, sizeof(keys));
/* interpret timing and find keys */
@@ -3179,7 +3180,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
return;
}
- task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totchild = ctx.totchild;
totparent = ctx.totparent;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 6cae6cd6fa2..13f0cb28428 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -481,7 +481,7 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
mface = ctx->mesh->mface;
- int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls won't need skipping */
/* TODO_PARTICLE - use original index */
pa->num = ctx->index[p];
@@ -538,7 +538,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
float randu, randv;
int distr = ctx->distr;
int i;
- int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls won't need skipping */
MFace *mface;
@@ -587,7 +587,7 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
float cur_d, min_d, randu, randv;
int distr = ctx->distr;
int i, intersect, tot;
- int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls won't need skipping */
MFace *mface;
MVert *mvert = mesh->mvert;
@@ -692,7 +692,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
float randu, randv;
int cfrom = ctx->cfrom;
int i;
- int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls won't need skipping */
MFace *mf;
@@ -1330,7 +1330,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
return;
}
- task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index ce4be411c9a..d236dbbf101 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -1007,7 +1007,7 @@ void psys_get_birth_coords(
mul_qt_v3(q_imat, rot_vec_local);
/* vtan_local */
- copy_v3_v3(vtan_local, vtan); /* flips, cant use */
+ copy_v3_v3(vtan_local, vtan); /* flips, can't use */
mul_qt_v3(q_imat, vtan_local);
/* ensure orthogonal matrix (rot_vec aligned) */
@@ -1320,6 +1320,14 @@ void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra
*efra = min_ii((int)(part->end + part->lifetime + 1.0f), max_ii(scene->r.pefra, scene->r.efra));
}
+/* BVH tree balancing inside a mutex lock must be run in isolation. Balancing
+ * is multithreaded, and we do not want the current thread to start another task
+ * that may involve acquiring the same mutex lock that it is waiting for. */
+static void bvhtree_balance_isolated(void *userdata)
+{
+ BLI_bvhtree_balance((BVHTree *)userdata);
+}
+
/************************************************/
/* Effectors */
/************************************************/
@@ -1356,7 +1364,8 @@ static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
}
}
}
- BLI_bvhtree_balance(psys->bvhtree);
+
+ BLI_task_isolate(bvhtree_balance_isolated, psys->bvhtree);
psys->bvhtree_frame = cfra;
@@ -3312,13 +3321,11 @@ static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
static void hair_create_input_mesh(ParticleSimulationData *sim,
int totpoint,
int totedge,
- Mesh **r_mesh,
- ClothHairData **r_hairdata)
+ Mesh **r_mesh)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
Mesh *mesh;
- ClothHairData *hairdata;
MVert *mvert;
MEdge *medge;
MDeformVert *dvert;
@@ -3339,9 +3346,8 @@ static void hair_create_input_mesh(ParticleSimulationData *sim,
medge = mesh->medge;
dvert = mesh->dvert;
- hairdata = *r_hairdata;
- if (!hairdata) {
- *r_hairdata = hairdata = MEM_mallocN(sizeof(ClothHairData) * totpoint, "hair data");
+ if (psys->clmd->hairdata == NULL) {
+ psys->clmd->hairdata = MEM_mallocN(sizeof(ClothHairData) * totpoint, "hair data");
}
/* calculate maximum segment length */
@@ -3493,7 +3499,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
}
}
- hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
+ hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh);
if (psys->hair_out_mesh) {
BKE_id_free(NULL, psys->hair_out_mesh);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 77dde3a921a..9f316ec60c0 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -2056,7 +2056,7 @@ bool ray_face_intersection_tri(const float ray_start[3],
return false;
}
-/* Take advantage of the fact we know this wont be an intersection.
+/* Take advantage of the fact we know this won't be an intersection.
* Just handle ray-tri edges. */
static float dist_squared_ray_to_tri_v3_fast(const float ray_origin[3],
const float ray_direction[3],
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index 43ab1a71647..c877ec6b6b0 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -107,7 +107,7 @@ void BKE_report(ReportList *reports, ReportType type, const char *_message)
int len;
const char *message = TIP_(_message);
- /* in background mode always print otherwise there are cases the errors wont be displayed,
+ /* in background mode always print otherwise there are cases the errors won't be displayed,
* but still add to the report list since this is used for python exception handling */
if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
printf("%s: %s\n", BKE_report_type_str(type), message);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 86d4c03d51a..41f70db3fba 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1145,6 +1145,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &ed->act_seq);
ed->cache = NULL;
ed->prefetch_job = NULL;
+ ed->runtime.sequence_lookup = NULL;
/* recursive link sequences, lb will be correctly initialized */
link_recurs_seq(reader, &ed->seqbase);
@@ -1465,8 +1466,8 @@ static void scene_blend_read_lib(BlendLibReader *reader, ID *id)
IDP_BlendReadLib(reader, seq->prop);
if (seq->ipo) {
- BLO_read_id_address(
- reader, sce->id.lib, &seq->ipo); /* XXX deprecated - old animation system */
+ /* XXX: deprecated - old animation system. */
+ BLO_read_id_address(reader, sce->id.lib, &seq->ipo);
}
seq->scene_sound = NULL;
if (seq->scene) {
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index d0d63192ebf..7a5892baaf6 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -467,7 +467,7 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb)
Panel *panel = lb->first;
for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
new_panel->activedata = NULL;
- new_panel->runtime.custom_data_ptr = NULL;
+ memset(&new_panel->runtime, 0x0, sizeof(new_panel->runtime));
panel_list_copy(&new_panel->children, &panel->children);
}
}
@@ -476,6 +476,8 @@ ARegion *BKE_area_region_copy(const SpaceType *st, const ARegion *region)
{
ARegion *newar = MEM_dupallocN(region);
+ memset(&newar->runtime, 0x0, sizeof(newar->runtime));
+
newar->prev = newar->next = NULL;
BLI_listbase_clear(&newar->handlers);
BLI_listbase_clear(&newar->uiblocks);
@@ -1355,12 +1357,21 @@ static void write_area(BlendWriter *writer, ScrArea *area)
}
else if (sl->spacetype == SPACE_SPREADSHEET) {
BLO_write_struct(writer, SpaceSpreadsheet, sl);
-
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+
+ LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
+ BLO_write_struct(writer, SpreadsheetRowFilter, row_filter);
+ BLO_write_string(writer, row_filter->value_string);
+ }
+
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
BLO_write_struct(writer, SpreadsheetColumn, column);
BLO_write_struct(writer, SpreadsheetColumnID, column->id);
BLO_write_string(writer, column->id->name);
+ /* While the display name is technically runtime data, we write it here, otherwise the row
+ * filters might not now their type if their region draws before the main region.
+ * This would ideally be cleared here. */
+ BLO_write_string(writer, column->display_name);
}
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
switch (context->type) {
@@ -1419,6 +1430,8 @@ static void direct_link_panel_list(BlendDataReader *reader, ListBase *lb)
static void direct_link_region(BlendDataReader *reader, ARegion *region, int spacetype)
{
+ memset(&region->runtime, 0x0, sizeof(region->runtime));
+
direct_link_panel_list(reader, &region->panels);
BLO_read_list(reader, &region->panels_category_active);
@@ -1454,7 +1467,6 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
BLO_read_data_address(reader, &rv3d->localvd);
BLO_read_data_address(reader, &rv3d->clipbb);
- rv3d->depths = NULL;
rv3d->render_engine = NULL;
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
@@ -1560,16 +1572,15 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
+
+ memset(&v3d->runtime, 0x0, sizeof(v3d->runtime));
+
if (v3d->gpd) {
BLO_read_data_address(reader, &v3d->gpd);
BKE_gpencil_blend_read_data(reader, v3d->gpd);
}
BLO_read_data_address(reader, &v3d->localvd);
- /* Runtime data */
- v3d->runtime.properties_storage = NULL;
- v3d->runtime.flag = 0;
-
/* render can be quite heavy, set to solid on load */
if (v3d->shading.type == OB_RENDER) {
v3d->shading.type = OB_SOLID;
@@ -1584,7 +1595,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
SpaceGraph *sipo = (SpaceGraph *)sl;
BLO_read_data_address(reader, &sipo->ads);
- BLI_listbase_clear(&sipo->runtime.ghost_curves);
+ memset(&sipo->runtime, 0x0, sizeof(sipo->runtime));
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
@@ -1652,7 +1663,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
- memset(&st->runtime, 0, sizeof(st->runtime));
+ memset(&st->runtime, 0x0, sizeof(st->runtime));
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
@@ -1724,6 +1735,11 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
BLO_read_data_address(reader, &sfile->params);
BLO_read_data_address(reader, &sfile->asset_params);
}
+ else if (sl->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)sl;
+
+ memset(&saction->runtime, 0x0, sizeof(saction->runtime));
+ }
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
@@ -1735,11 +1751,18 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
sspreadsheet->runtime = NULL;
-
+ BLO_read_list(reader, &sspreadsheet->row_filters);
+ LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
+ BLO_read_data_address(reader, &row_filter->value_string);
+ }
BLO_read_list(reader, &sspreadsheet->columns);
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
BLO_read_data_address(reader, &column->id);
BLO_read_data_address(reader, &column->id->name);
+ /* While the display name is technically runtime data, it is loaded here, otherwise the row
+ * filters might not now their type if their region draws before the main region.
+ * This would ideally be cleared here. */
+ BLO_read_data_address(reader, &column->display_name);
}
BLO_read_list(reader, &sspreadsheet->context_path);
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 3727ec866ca..60f0b744e59 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -165,6 +165,18 @@ const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
}
/**
+ * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
+ */
+bool BKE_shaderfx_is_nonlocal_in_liboverride(const Object *ob, const ShaderFxData *shaderfx)
+{
+ return (ID_IS_OVERRIDE_LIBRARY(ob) &&
+ ((shaderfx == NULL) || (shaderfx->flag & eShaderFxFlag_OverrideLibrary_Local) == 0));
+}
+
+/**
* Get an effect's panel type, which was defined in the #panelRegister callback.
*
* \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 6dd1f66f6b5..f4a9d328d86 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -187,8 +187,8 @@ static void sound_blend_read_data(BlendDataReader *reader, ID *id)
static void sound_blend_read_lib(BlendLibReader *reader, ID *id)
{
bSound *sound = (bSound *)id;
- BLO_read_id_address(
- reader, sound->id.lib, &sound->ipo); /* XXX deprecated - old animation system */
+ /* XXX: deprecated - old animation system. */
+ BLO_read_id_address(reader, sound->id.lib, &sound->ipo);
}
static void sound_blend_read_expand(BlendExpander *expander, ID *id)
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 8956ba6adae..584156ea40f 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -40,6 +40,60 @@ Spline::Type Spline::type() const
return type_;
}
+void Spline::copy_base_settings(const Spline &src, Spline &dst)
+{
+ dst.normal_mode = src.normal_mode;
+ dst.is_cyclic_ = src.is_cyclic_;
+}
+
+static SplinePtr create_spline(const Spline::Type type)
+{
+ switch (type) {
+ case Spline::Type::Poly:
+ return std::make_unique<PolySpline>();
+ case Spline::Type::Bezier:
+ return std::make_unique<BezierSpline>();
+ case Spline::Type::NURBS:
+ return std::make_unique<NURBSpline>();
+ }
+ BLI_assert_unreachable();
+ return {};
+}
+
+/**
+ * Return a new spline with the same data, settings, and attributes.
+ */
+SplinePtr Spline::copy() const
+{
+ SplinePtr dst = this->copy_without_attributes();
+ dst->attributes = this->attributes;
+ return dst;
+}
+
+/**
+ * Return a new spline with the same type and settings like "cyclic", but without any data.
+ */
+SplinePtr Spline::copy_only_settings() const
+{
+ SplinePtr dst = create_spline(type_);
+ this->copy_base_settings(*this, *dst);
+ this->copy_settings(*dst);
+ return dst;
+}
+
+/**
+ * The same as #copy, but skips copying dynamic attributes to the new spline.
+ */
+SplinePtr Spline::copy_without_attributes() const
+{
+ SplinePtr dst = this->copy_only_settings();
+ this->copy_data(*dst);
+
+ /* Though the attributes storage is empty, it still needs to know the correct size. */
+ dst->attributes.reallocate(dst->size());
+ return dst;
+}
+
void Spline::translate(const blender::float3 &translation)
{
for (float3 &position : this->positions()) {
@@ -74,9 +128,9 @@ float Spline::length() const
int Spline::segments_size() const
{
- const int points_len = this->size();
+ const int size = this->size();
- return is_cyclic_ ? points_len : points_len - 1;
+ return is_cyclic_ ? size : size - 1;
}
bool Spline::is_cyclic() const
@@ -209,10 +263,86 @@ static float3 rotate_direction_around_axis(const float3 &direction,
return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
}
-static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> normals)
+static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> r_normals)
{
- for (const int i : normals.index_range()) {
- normals[i] = float3::cross(tangents[i], float3(0.0f, 0.0f, 1.0f)).normalized();
+ BLI_assert(r_normals.size() == tangents.size());
+
+ /* Same as in `vec_to_quat`. */
+ const float epsilon = 1e-4f;
+ for (const int i : r_normals.index_range()) {
+ const float3 &tangent = tangents[i];
+ if (fabsf(tangent.x) + fabsf(tangent.y) < epsilon) {
+ r_normals[i] = {1.0f, 0.0f, 0.0f};
+ }
+ else {
+ r_normals[i] = float3(tangent.y, -tangent.x, 0.0f).normalized();
+ }
+ }
+}
+
+/**
+ * Rotate the last normal in the same way the tangent has been rotated.
+ */
+static float3 calculate_next_normal(const float3 &last_normal,
+ const float3 &last_tangent,
+ const float3 &current_tangent)
+{
+ if (last_tangent.is_zero() || current_tangent.is_zero()) {
+ return last_normal;
+ }
+ const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
+ if (angle != 0.0) {
+ const float3 axis = float3::cross(last_tangent, current_tangent).normalized();
+ return rotate_direction_around_axis(last_normal, axis, angle);
+ }
+ return last_normal;
+}
+
+static void calculate_normals_minimum(Span<float3> tangents,
+ const bool cyclic,
+ MutableSpan<float3> r_normals)
+{
+ BLI_assert(r_normals.size() == tangents.size());
+
+ if (r_normals.is_empty()) {
+ return;
+ }
+
+ const float epsilon = 1e-4f;
+
+ /* Set initial normal. */
+ const float3 &first_tangent = tangents[0];
+ if (fabs(first_tangent.x) + fabs(first_tangent.y) < epsilon) {
+ r_normals[0] = {1.0f, 0.0f, 0.0f};
+ }
+ else {
+ r_normals[0] = float3(first_tangent.y, -first_tangent.x, 0.0f).normalized();
+ }
+
+ /* Forward normal with minimum twist along the entire spline. */
+ for (const int i : IndexRange(1, r_normals.size() - 1)) {
+ r_normals[i] = calculate_next_normal(r_normals[i - 1], tangents[i - 1], tangents[i]);
+ }
+
+ if (!cyclic) {
+ return;
+ }
+
+ /* Compute how much the first normal deviates from the normal that has been forwarded along the
+ * entire cyclic spline. */
+ const float3 uncorrected_last_normal = calculate_next_normal(
+ r_normals.last(), tangents.last(), tangents[0]);
+ float correction_angle = angle_signed_on_axis_v3v3_v3(
+ r_normals[0], uncorrected_last_normal, tangents[0]);
+ if (correction_angle > M_PI) {
+ correction_angle = correction_angle - 2 * M_PI;
+ }
+
+ /* Gradually apply correction by rotating all normals slightly. */
+ const float angle_step = correction_angle / r_normals.size();
+ for (const int i : r_normals.index_range()) {
+ const float angle = angle_step * i;
+ r_normals[i] = rotate_direction_around_axis(r_normals[i], tangents[i], angle);
}
}
@@ -234,14 +364,28 @@ Span<float3> Spline::evaluated_normals() const
const int eval_size = this->evaluated_points_size();
evaluated_normals_cache_.resize(eval_size);
- Span<float3> tangents = evaluated_tangents();
+ Span<float3> tangents = this->evaluated_tangents();
MutableSpan<float3> normals = evaluated_normals_cache_;
/* Only Z up normals are supported at the moment. */
- calculate_normals_z_up(tangents, normals);
+ switch (this->normal_mode) {
+ case ZUp: {
+ calculate_normals_z_up(tangents, normals);
+ break;
+ }
+ case Minimum: {
+ calculate_normals_minimum(tangents, is_cyclic_, normals);
+ break;
+ }
+ case Tangent: {
+ /* Tangent mode is not yet supported. */
+ calculate_normals_z_up(tangents, normals);
+ break;
+ }
+ }
/* Rotate the generated normals with the interpolated tilt data. */
- GVArray_Typed<float> tilts = this->interpolate_to_evaluated_points(this->tilts());
+ GVArray_Typed<float> tilts = this->interpolate_to_evaluated(this->tilts());
for (const int i : normals.index_range()) {
normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]);
}
@@ -380,23 +524,23 @@ void Spline::sample_length_parameters_to_index_factors(MutableSpan<float> parame
Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const
{
- const int points_len = this->evaluated_points_size();
+ const int eval_size = this->evaluated_points_size();
if (is_cyclic_) {
- if (index_factor < points_len) {
+ if (index_factor < eval_size) {
const int index = std::floor(index_factor);
- const int next_index = (index < points_len - 1) ? index + 1 : 0;
+ const int next_index = (index < eval_size - 1) ? index + 1 : 0;
return LookupResult{index, next_index, index_factor - index};
}
- return LookupResult{points_len - 1, 0, 1.0f};
+ return LookupResult{eval_size - 1, 0, 1.0f};
}
- if (index_factor < points_len - 1) {
+ if (index_factor < eval_size - 1) {
const int index = std::floor(index_factor);
const int next_index = index + 1;
return LookupResult{index, next_index, index_factor - index};
}
- return LookupResult{points_len - 2, points_len - 1, 1.0f};
+ return LookupResult{eval_size - 2, eval_size - 1, 1.0f};
}
void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
@@ -407,9 +551,9 @@ void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated)
}
}
-GVArrayPtr Spline::interpolate_to_evaluated_points(GSpan data) const
+GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const
{
- return this->interpolate_to_evaluated_points(GVArray_For_GSpan(data));
+ return this->interpolate_to_evaluated(GVArray_For_GSpan(data));
}
/**
@@ -417,9 +561,9 @@ GVArrayPtr Spline::interpolate_to_evaluated_points(GSpan data) const
* points) to arbitrary parameters in between the evaluated points. The interpolation is quite
* simple, but this handles the cyclic and end point special cases.
*/
-void Spline::sample_based_on_index_factors(const GVArray &src,
- Span<float> index_factors,
- GMutableSpan dst) const
+void Spline::sample_with_index_factors(const GVArray &src,
+ Span<float> index_factors,
+ GMutableSpan dst) const
{
BLI_assert(src.size() == this->evaluated_points_size());
@@ -427,7 +571,7 @@ void Spline::sample_based_on_index_factors(const GVArray &src,
using T = decltype(dummy);
const GVArray_Typed<T> src_typed = src.typed<T>();
MutableSpan<T> dst_typed = dst.typed<T>();
- blender::parallel_for(dst_typed.index_range(), 1024, [&](IndexRange range) {
+ blender::threading::parallel_for(dst_typed.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const LookupResult interp = this->lookup_data_from_index_factor(index_factors[i]);
dst_typed[i] = blender::attribute_math::mix2(interp.factor,
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 3e421dcfc13..02d26ac715b 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -25,18 +25,26 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::fn::GVArray;
+using blender::fn::GVArray_For_ArrayContainer;
+using blender::fn::GVArrayPtr;
-SplinePtr BezierSpline::copy() const
+void BezierSpline::copy_settings(Spline &dst) const
{
- return std::make_unique<BezierSpline>(*this);
+ BezierSpline &bezier = static_cast<BezierSpline &>(dst);
+ bezier.resolution_ = resolution_;
}
-SplinePtr BezierSpline::copy_settings() const
+void BezierSpline::copy_data(Spline &dst) const
{
- std::unique_ptr<BezierSpline> copy = std::make_unique<BezierSpline>();
- copy_base_settings(*this, *copy);
- copy->resolution_ = resolution_;
- return copy;
+ BezierSpline &bezier = static_cast<BezierSpline &>(dst);
+ bezier.positions_ = positions_;
+ bezier.handle_types_left_ = handle_types_left_;
+ bezier.handle_positions_left_ = handle_positions_left_;
+ bezier.handle_types_right_ = handle_types_right_;
+ bezier.handle_positions_right_ = handle_positions_right_;
+ bezier.radii_ = radii_;
+ bezier.tilts_ = tilts_;
}
int BezierSpline::size() const
@@ -352,9 +360,9 @@ static void bezier_forward_difference_3d(const float3 &point_0,
}
}
-void BezierSpline::evaluate_bezier_segment(const int index,
- const int next_index,
- MutableSpan<float3> positions) const
+void BezierSpline::evaluate_segment(const int index,
+ const int next_index,
+ MutableSpan<float3> positions) const
{
if (this->segment_is_vector(index)) {
BLI_assert(positions.size() == 1);
@@ -389,13 +397,13 @@ Span<int> BezierSpline::control_point_offsets() const
return offset_cache_;
}
- const int points_len = this->size();
- offset_cache_.resize(points_len + 1);
+ const int size = this->size();
+ offset_cache_.resize(size + 1);
MutableSpan<int> offsets = offset_cache_;
int offset = 0;
- for (const int i : IndexRange(points_len)) {
+ for (const int i : IndexRange(size)) {
offsets[i] = offset;
offset += this->segment_is_vector(i) ? 1 : resolution_;
}
@@ -417,7 +425,7 @@ static void calculate_mappings_linear_resolution(Span<int> offsets,
}
const int grain_size = std::max(2048 / resolution, 1);
- parallel_for(IndexRange(1, size - 2), grain_size, [&](IndexRange range) {
+ blender::threading::parallel_for(IndexRange(1, size - 2), grain_size, [&](IndexRange range) {
for (const int i_control_point : range) {
const int segment_len = offsets[i_control_point + 1] - offsets[i_control_point];
const float segment_len_inv = 1.0f / segment_len;
@@ -497,14 +505,13 @@ Span<float3> BezierSpline::evaluated_positions() const
Span<int> offsets = this->control_point_offsets();
const int grain_size = std::max(512 / resolution_, 1);
- parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) {
+ blender::threading::parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) {
for (const int i : range) {
- this->evaluate_bezier_segment(
- i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i]));
+ this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i]));
}
});
if (is_cyclic_) {
- this->evaluate_bezier_segment(
+ this->evaluate_segment(
size - 1, 0, positions.slice(offsets[size - 1], offsets[size] - offsets[size - 1]));
}
else {
@@ -525,66 +532,66 @@ Span<float3> BezierSpline::evaluated_positions() const
BezierSpline::InterpolationData BezierSpline::interpolation_data_from_index_factor(
const float index_factor) const
{
- const int points_len = this->size();
+ const int size = this->size();
if (is_cyclic_) {
- if (index_factor < points_len) {
+ if (index_factor < size) {
const int index = std::floor(index_factor);
- const int next_index = (index < points_len - 1) ? index + 1 : 0;
+ const int next_index = (index < size - 1) ? index + 1 : 0;
return InterpolationData{index, next_index, index_factor - index};
}
- return InterpolationData{points_len - 1, 0, 1.0f};
+ return InterpolationData{size - 1, 0, 1.0f};
}
- if (index_factor < points_len - 1) {
+ if (index_factor < size - 1) {
const int index = std::floor(index_factor);
const int next_index = index + 1;
return InterpolationData{index, next_index, index_factor - index};
}
- return InterpolationData{points_len - 2, points_len - 1, 1.0f};
+ return InterpolationData{size - 2, size - 1, 1.0f};
}
/* Use a spline argument to avoid adding this to the header. */
template<typename T>
-static void interpolate_to_evaluated_points_impl(const BezierSpline &spline,
- const blender::VArray<T> &source_data,
- MutableSpan<T> result_data)
+static void interpolate_to_evaluated_impl(const BezierSpline &spline,
+ const blender::VArray<T> &src,
+ MutableSpan<T> dst)
{
+ BLI_assert(src.size() == spline.size());
+ BLI_assert(dst.size() == spline.evaluated_points_size());
Span<float> mappings = spline.evaluated_mappings();
- for (const int i : result_data.index_range()) {
+ for (const int i : dst.index_range()) {
BezierSpline::InterpolationData interp = spline.interpolation_data_from_index_factor(
mappings[i]);
- const T &value = source_data[interp.control_point_index];
- const T &next_value = source_data[interp.next_control_point_index];
+ const T &value = src[interp.control_point_index];
+ const T &next_value = src[interp.next_control_point_index];
- result_data[i] = blender::attribute_math::mix2(interp.factor, value, next_value);
+ dst[i] = blender::attribute_math::mix2(interp.factor, value, next_value);
}
}
-blender::fn::GVArrayPtr BezierSpline::interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const
+GVArrayPtr BezierSpline::interpolate_to_evaluated(const GVArray &src) const
{
- BLI_assert(source_data.size() == this->size());
+ BLI_assert(src.size() == this->size());
- if (source_data.is_single()) {
- return source_data.shallow_copy();
+ if (src.is_single()) {
+ return src.shallow_copy();
}
const int eval_size = this->evaluated_points_size();
if (eval_size == 1) {
- return source_data.shallow_copy();
+ return src.shallow_copy();
}
- blender::fn::GVArrayPtr new_varray;
- blender::attribute_math::convert_to_static_type(source_data.type(), [&](auto dummy) {
+ GVArrayPtr new_varray;
+ blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
Array<T> values(eval_size);
- interpolate_to_evaluated_points_impl<T>(*this, source_data.typed<T>(), values);
- new_varray = std::make_unique<blender::fn::GVArray_For_ArrayContainer<Array<T>>>(
- std::move(values));
+ interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values);
+ new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index bfb0d652b1a..85fb9730e83 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -26,21 +26,28 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::fn::GVArray;
+using blender::fn::GVArray_For_ArrayContainer;
using blender::fn::GVArray_Typed;
+using blender::fn::GVArrayPtr;
-SplinePtr NURBSpline::copy() const
+void NURBSpline::copy_settings(Spline &dst) const
{
- return std::make_unique<NURBSpline>(*this);
+ NURBSpline &nurbs = static_cast<NURBSpline &>(dst);
+ nurbs.knots_mode = knots_mode;
+ nurbs.resolution_ = resolution_;
+ nurbs.order_ = order_;
}
-SplinePtr NURBSpline::copy_settings() const
+void NURBSpline::copy_data(Spline &dst) const
{
- std::unique_ptr<NURBSpline> copy = std::make_unique<NURBSpline>();
- copy_base_settings(*this, *copy);
- copy->knots_mode = knots_mode;
- copy->resolution_ = resolution_;
- copy->order_ = order_;
- return copy;
+ NURBSpline &nurbs = static_cast<NURBSpline &>(dst);
+ nurbs.positions_ = positions_;
+ nurbs.weights_ = weights_;
+ nurbs.knots_ = knots_;
+ nurbs.knots_dirty_ = false;
+ nurbs.radii_ = radii_;
+ nurbs.tilts_ = tilts_;
}
int NURBSpline::size() const
@@ -268,18 +275,18 @@ Span<float> NURBSpline::knots() const
}
static void calculate_basis_for_point(const float parameter,
- const int points_len,
+ const int size,
const int order,
Span<float> knots,
MutableSpan<float> basis_buffer,
NURBSpline::BasisCache &basis_cache)
{
/* Clamp parameter due to floating point inaccuracy. */
- const float t = std::clamp(parameter, knots[0], knots[points_len + order - 1]);
+ const float t = std::clamp(parameter, knots[0], knots[size + order - 1]);
int start = 0;
int end = 0;
- for (const int i : IndexRange(points_len + order - 1)) {
+ for (const int i : IndexRange(size + order - 1)) {
const bool knots_equal = knots[i] == knots[i + 1];
if (knots_equal || t < knots[i] || t > knots[i + 1]) {
basis_buffer[i] = 0.0f;
@@ -289,14 +296,14 @@ static void calculate_basis_for_point(const float parameter,
basis_buffer[i] = 1.0f;
start = std::max(i - order - 1, 0);
end = i;
- basis_buffer.slice(i + 1, points_len + order - 1 - i).fill(0.0f);
+ basis_buffer.slice(i + 1, size + order - 1 - i).fill(0.0f);
break;
}
- basis_buffer[points_len + order - 1] = 0.0f;
+ basis_buffer[size + order - 1] = 0.0f;
for (const int i_order : IndexRange(2, order - 1)) {
- if (end + i_order >= points_len + order) {
- end = points_len + order - 1 - i_order;
+ if (end + i_order >= size + order) {
+ end = size + order - 1 - i_order;
}
for (const int i : IndexRange(start, end - start + 1)) {
float new_basis = 0.0f;
@@ -326,18 +333,18 @@ static void calculate_basis_for_point(const float parameter,
basis_cache.start_index = start;
}
-void NURBSpline::calculate_basis_cache() const
+Span<NURBSpline::BasisCache> NURBSpline::calculate_basis_cache() const
{
if (!basis_cache_dirty_) {
- return;
+ return basis_cache_;
}
std::lock_guard lock{basis_cache_mutex_};
if (!basis_cache_dirty_) {
- return;
+ return basis_cache_;
}
- const int points_len = this->size();
+ const int size = this->size();
const int eval_size = this->evaluated_points_size();
BLI_assert(this->evaluated_edges_size() > 0);
basis_cache_.resize(eval_size);
@@ -353,17 +360,17 @@ void NURBSpline::calculate_basis_cache() const
Array<float> basis_buffer(this->knots_size());
const float start = knots[order - 1];
- const float end = is_cyclic_ ? knots[points_len + order - 1] : knots[points_len];
+ const float end = is_cyclic_ ? knots[size + order - 1] : knots[size];
const float step = (end - start) / this->evaluated_edges_size();
float parameter = start;
for (const int i : IndexRange(eval_size)) {
BasisCache &basis = basis_cache[i];
calculate_basis_for_point(
- parameter, points_len + (is_cyclic_ ? order - 1 : 0), order, knots, basis_buffer, basis);
+ parameter, size + (is_cyclic_ ? order - 1 : 0), order, knots, basis_buffer, basis);
BLI_assert(basis.weights.size() <= order);
for (const int j : basis.weights.index_range()) {
- const int point_index = (basis.start_index + j) % points_len;
+ const int point_index = (basis.start_index + j) % size;
basis.weights[j] *= control_weights[point_index];
}
@@ -371,50 +378,47 @@ void NURBSpline::calculate_basis_cache() const
}
basis_cache_dirty_ = false;
+ return basis_cache_;
}
template<typename T>
-void interpolate_to_evaluated_points_impl(Span<NURBSpline::BasisCache> weights,
- const blender::VArray<T> &source_data,
- MutableSpan<T> result_data)
+void interpolate_to_evaluated_impl(Span<NURBSpline::BasisCache> weights,
+ const blender::VArray<T> &src,
+ MutableSpan<T> dst)
{
- const int points_len = source_data.size();
- BLI_assert(result_data.size() == weights.size());
- blender::attribute_math::DefaultMixer<T> mixer(result_data);
+ const int size = src.size();
+ BLI_assert(dst.size() == weights.size());
+ blender::attribute_math::DefaultMixer<T> mixer(dst);
- for (const int i : result_data.index_range()) {
+ for (const int i : dst.index_range()) {
Span<float> point_weights = weights[i].weights;
const int start_index = weights[i].start_index;
-
for (const int j : point_weights.index_range()) {
- const int point_index = (start_index + j) % points_len;
- mixer.mix_in(i, source_data[point_index], point_weights[j]);
+ const int point_index = (start_index + j) % size;
+ mixer.mix_in(i, src[point_index], point_weights[j]);
}
}
mixer.finalize();
}
-blender::fn::GVArrayPtr NURBSpline::interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const
+GVArrayPtr NURBSpline::interpolate_to_evaluated(const GVArray &src) const
{
- BLI_assert(source_data.size() == this->size());
+ BLI_assert(src.size() == this->size());
- if (source_data.is_single()) {
- return source_data.shallow_copy();
+ if (src.is_single()) {
+ return src.shallow_copy();
}
- this->calculate_basis_cache();
- Span<BasisCache> weights(basis_cache_);
+ Span<BasisCache> basis_cache = this->calculate_basis_cache();
- blender::fn::GVArrayPtr new_varray;
- blender::attribute_math::convert_to_static_type(source_data.type(), [&](auto dummy) {
+ GVArrayPtr new_varray;
+ blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
Array<T> values(this->evaluated_points_size());
- interpolate_to_evaluated_points_impl<T>(weights, source_data.typed<T>(), values);
- new_varray = std::make_unique<blender::fn::GVArray_For_ArrayContainer<Array<T>>>(
- std::move(values));
+ interpolate_to_evaluated_impl<T>(basis_cache, src.typed<T>(), values);
+ new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
@@ -436,7 +440,7 @@ Span<float3> NURBSpline::evaluated_positions() const
evaluated_position_cache_.resize(eval_size);
/* TODO: Avoid copying the evaluated data from the temporary array. */
- GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated_points(positions_.as_span());
+ GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span());
evaluated->materialize(evaluated_position_cache_);
position_cache_dirty_ = false;
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index 5f8e81d5ad0..dfd24b2566e 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -22,17 +22,20 @@
using blender::float3;
using blender::MutableSpan;
using blender::Span;
+using blender::fn::GVArray;
+using blender::fn::GVArrayPtr;
-SplinePtr PolySpline::copy() const
+void PolySpline::copy_settings(Spline &UNUSED(dst)) const
{
- return std::make_unique<PolySpline>(*this);
+ /* Poly splines have no settings not covered by the base class. */
}
-SplinePtr PolySpline::copy_settings() const
+void PolySpline::copy_data(Spline &dst) const
{
- std::unique_ptr<PolySpline> copy = std::make_unique<PolySpline>();
- copy_base_settings(*this, *copy);
- return copy;
+ PolySpline &poly = static_cast<PolySpline &>(dst);
+ poly.positions_ = positions_;
+ poly.radii_ = radii_;
+ poly.tilts_ = tilts_;
}
int PolySpline::size() const
@@ -115,10 +118,9 @@ Span<float3> PolySpline::evaluated_positions() const
* the original data. Therefore the lifetime of the returned virtual array must not be longer than
* the source data.
*/
-blender::fn::GVArrayPtr PolySpline::interpolate_to_evaluated_points(
- const blender::fn::GVArray &source_data) const
+GVArrayPtr PolySpline::interpolate_to_evaluated(const GVArray &src) const
{
- BLI_assert(source_data.size() == this->size());
+ BLI_assert(src.size() == this->size());
- return source_data.shallow_copy();
+ return src.shallow_copy();
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 5f732ba91ab..4ca6f93b014 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -1042,7 +1042,7 @@ typedef struct AverageGridsBoundariesData {
CCGKey *key;
/* Optional lookup table. Maps task index to index in `subdiv_ccg->adjacent_vertices`. */
- int *adjacent_edge_index_map;
+ const int *adjacent_edge_index_map;
} AverageGridsBoundariesData;
typedef struct AverageGridsBoundariesTLSData {
@@ -1117,7 +1117,7 @@ typedef struct AverageGridsCornerData {
CCGKey *key;
/* Optional lookup table. Maps task range index to index in subdiv_ccg->adjacent_vertices*/
- int *adjacent_vert_index_map;
+ const int *adjacent_vert_index_map;
} AverageGridsCornerData;
static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg,
@@ -1161,7 +1161,7 @@ static void subdiv_ccg_average_grids_corners_task(void *__restrict userdata_v,
static void subdiv_ccg_average_boundaries(SubdivCCG *subdiv_ccg,
CCGKey *key,
- int *adjacent_edge_index_map,
+ const int *adjacent_edge_index_map,
int num_adjacent_edges)
{
TaskParallelSettings parallel_range_settings;
@@ -1186,7 +1186,7 @@ static void subdiv_ccg_average_all_boundaries(SubdivCCG *subdiv_ccg, CCGKey *key
static void subdiv_ccg_average_corners(SubdivCCG *subdiv_ccg,
CCGKey *key,
- int *adjacent_vert_index_map,
+ const int *adjacent_vert_index_map,
int num_adjacent_vertices)
{
TaskParallelSettings parallel_range_settings;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a28136f8527..23eccbfba9b 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1879,12 +1879,11 @@ static const MeshElemMap *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm)
/* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */
static void ccgDM_recalcLoopTri(DerivedMesh *dm)
{
- MLoopTri *mlooptri = dm->looptris.array;
const int tottri = dm->numPolyData * 2;
int i, poly_index;
DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array_wip;
+ MLoopTri *mlooptri = dm->looptris.array_wip;
BLI_assert(tottri == 0 || mlooptri != NULL);
BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 5cf76bb6452..c2fb5ef4238 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -152,7 +152,7 @@ static struct bUnitDef buMetricLenDef[] = {
{"micrometer", "micrometers", "µm", "um", "Micrometers", "MICROMETERS", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
/* These get displayed because of float precision problems in the transform header,
- * could work around, but for now probably people wont use these. */
+ * could work around, but for now probably people won't use these. */
#if 0
{"nanometer", "Nanometers", "nm", NULL, 0.000000001, 0.0, B_UNIT_DEF_NONE},
{"picometer", "Picometers", "pm", NULL, 0.000000000001, 0.0, B_UNIT_DEF_NONE},
@@ -988,7 +988,7 @@ static int unit_scale_str(char *str,
memcpy(str_found, str_tmp, len_num); /* Without the string terminator. */
}
- /* Since the null terminator wont be moved if the stringlen_max
+ /* Since the null terminator won't be moved if the stringlen_max
* was not long enough to fit everything in it. */
str[len_max - 1] = '\0';
return found_ofs + len_num;
@@ -1136,8 +1136,8 @@ bool BKE_unit_replace_string(
strncpy(str, str_tmp, len_max);
}
else {
- /* BLI_snprintf would not fit into str_tmp, cant do much in this case.
- * Check for this because otherwise BKE_unit_replace_string could call its self forever. */
+ /* BLI_snprintf would not fit into str_tmp, can't do much in this case.
+ * Check for this because otherwise BKE_unit_replace_string could call itself forever. */
return changed;
}
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index c0ce57818d1..5fc55aad6a2 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
@@ -324,15 +325,19 @@ struct VolumeGrid {
openvdb::io::File file(filepath);
- try {
- file.setCopyMaxBytes(0);
- file.open();
- openvdb::GridBase::Ptr vdb_grid = file.readGrid(name());
- entry->grid->setTree(vdb_grid->baseTreePtr());
- }
- catch (const openvdb::IoError &e) {
- entry->error_msg = e.what();
- }
+ /* Isolate file loading since that's potentially multithreaded and we are
+ * holding a mutex lock. */
+ blender::threading::isolate_task([&] {
+ try {
+ file.setCopyMaxBytes(0);
+ file.open();
+ openvdb::GridBase::Ptr vdb_grid = file.readGrid(name());
+ entry->grid->setTree(vdb_grid->baseTreePtr());
+ }
+ catch (const openvdb::IoError &e) {
+ entry->error_msg = e.what();
+ }
+ });
std::atomic_thread_fence(std::memory_order_release);
entry->is_loaded = true;
@@ -740,7 +745,7 @@ static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volum
}
}
- /* Important to apply after, else we cant loop on e.g. frames 100 - 110. */
+ /* Important to apply after, else we can't loop on e.g. frames 100 - 110. */
frame += frame_offset;
return frame;
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
index e91726991ca..d42bd6af637 100644
--- a/source/blender/blenlib/BLI_delaunay_2d.h
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -178,6 +178,8 @@ typedef enum CDT_output_type {
CDT_FULL,
/** All triangles fully enclosed by constraint edges or faces. */
CDT_INSIDE,
+ /** Like previous, but detect holes and omit those from output. */
+ CDT_INSIDE_WITH_HOLES,
/** Only point, edge, and face constraints, and their intersections. */
CDT_CONSTRAINTS,
/**
@@ -186,7 +188,9 @@ typedef enum CDT_output_type {
* #BMesh faces in Blender: that is,
* no vertex appears more than once and no isolated holes in faces.
*/
- CDT_CONSTRAINTS_VALID_BMESH
+ CDT_CONSTRAINTS_VALID_BMESH,
+ /** Like previous, but detect holes and omit those from output. */
+ CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES,
} CDT_output_type;
/**
diff --git a/source/blender/blenlib/BLI_enumerable_thread_specific.hh b/source/blender/blenlib/BLI_enumerable_thread_specific.hh
index 89be4cad848..a05f7724dd2 100644
--- a/source/blender/blenlib/BLI_enumerable_thread_specific.hh
+++ b/source/blender/blenlib/BLI_enumerable_thread_specific.hh
@@ -26,7 +26,7 @@
#include "BLI_map.hh"
#include "BLI_utility_mixins.hh"
-namespace blender {
+namespace blender::threading {
namespace enumerable_thread_specific_utils {
inline std::atomic<int> next_id = 0;
@@ -70,4 +70,4 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
#endif /* WITH_TBB */
};
-} // namespace blender
+} // namespace blender::threading
diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h
index f6075367ac5..3b61c0feb51 100644
--- a/source/blender/blenlib/BLI_math.h
+++ b/source/blender/blenlib/BLI_math.h
@@ -70,4 +70,5 @@
#include "BLI_math_rotation.h"
#include "BLI_math_solvers.h"
#include "BLI_math_statistics.h"
+#include "BLI_math_time.h"
#include "BLI_math_vector.h"
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 46219ad5493..88dc20a64f2 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -237,6 +237,7 @@ float ceil_power_of_10(float f);
#ifndef NDEBUG
/** \note 0.0001 is too small because normals may be converted from short's: see T34322. */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f
+# define BLI_ASSERT_UNIT_EPSILON_DB 0.0002
/**
* \note Checks are flipped so NAN doesn't assert.
* This is done because we're making sure the value was normalized and in the case we
@@ -253,8 +254,8 @@ float ceil_power_of_10(float f);
# define BLI_ASSERT_UNIT_V3_DB(v) \
{ \
const double _test_unit = len_squared_v3_db(v); \
- BLI_assert(!(fabs(_test_unit - 1.0) >= BLI_ASSERT_UNIT_EPSILON) || \
- !(fabs(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \
+ BLI_assert(!(fabs(_test_unit - 1.0) >= BLI_ASSERT_UNIT_EPSILON_DB) || \
+ !(fabs(_test_unit) >= BLI_ASSERT_UNIT_EPSILON_DB)); \
} \
(void)0
@@ -295,6 +296,7 @@ float ceil_power_of_10(float f);
#else
# define BLI_ASSERT_UNIT_V2(v) (void)(v)
# define BLI_ASSERT_UNIT_V3(v) (void)(v)
+# define BLI_ASSERT_UNIT_V3_DB(v) (void)(v)
# define BLI_ASSERT_UNIT_QUAT(v) (void)(v)
# define BLI_ASSERT_ZERO_M3(m) (void)(m)
# define BLI_ASSERT_ZERO_M4(m) (void)(m)
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index c744c5d13d3..43b31d76bb0 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -105,6 +105,11 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float v4[3],
+ const float normal[3]);
/********************************* Distance **********************************/
@@ -672,8 +677,8 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
- float top[4],
float bottom[4],
+ float top[4],
float near[4],
float far[4]);
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index fe995b2e46e..ef10d02f10f 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -164,6 +164,9 @@ void compatible_eul(float eul[3], const float old[3]);
void rotate_eul(float eul[3], const char axis, const float angle);
+void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
+void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
+
/************************** Arbitrary Order Eulers ***************************/
/* warning: must match the eRotationModes in DNA_action_types.h
diff --git a/source/blender/blenlib/BLI_math_time.h b/source/blender/blenlib/BLI_math_time.h
new file mode 100644
index 00000000000..671ec6f857f
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_time.h
@@ -0,0 +1,51 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/************************ Time constants definitions***************************/
+#define SECONDS_IN_MILLISECONDS 0.001
+#define SECONDS_IN_MINUTE 60.0
+#define MINUTES_IN_HOUR 60.0
+#define HOURS_IN_DAY 24.0
+
+#define MINUTES_IN_DAY (MINUTES_IN_HOUR * HOURS_IN_DAY)
+#define SECONDS_IN_DAY (MINUTES_IN_DAY * SECONDS_IN_MINUTE)
+#define SECONDS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE)
+
+void BLI_math_time_seconds_decompose(double seconds,
+ double *r_days,
+ double *r_hours,
+ double *r_minutes,
+ double *r_seconds,
+ double *r_milliseconds);
+
+/**************************** Inline Definitions ******************************/
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index b43f86af670..556a216bb89 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -163,6 +163,7 @@ MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f);
MINLINE void madd_v3_v3v3(float r[3], const float a[3], const float b[3]);
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f);
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f);
+MINLINE void madd_v3_v3v3db_db(double r[3], const double a[3], const double b[3], double f);
MINLINE void madd_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f);
MINLINE void madd_v4_v4v4(float r[4], const float a[4], const float b[4]);
@@ -327,6 +328,10 @@ MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool is_zero_v2_db(const double a[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool is_zero_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool is_zero_v4_db(const double a[4]) ATTR_WARN_UNUSED_RESULT;
+
bool is_finite_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
index 87a320e336d..d7798f12fcc 100644
--- a/source/blender/blenlib/BLI_memarena.h
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -38,7 +38,8 @@ extern "C" {
struct MemArena;
typedef struct MemArena MemArena;
-struct MemArena *BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT
+struct MemArena *BLI_memarena_new(const size_t bufsize,
+ const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
ATTR_NONNULL(2) ATTR_MALLOC;
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1);
void BLI_memarena_use_malloc(struct MemArena *ma) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_memiter.h b/source/blender/blenlib/BLI_memiter.h
index c7a715309e1..abb1bec809d 100644
--- a/source/blender/blenlib/BLI_memiter.h
+++ b/source/blender/blenlib/BLI_memiter.h
@@ -36,15 +36,14 @@ struct BLI_memiter;
typedef struct BLI_memiter BLI_memiter;
/* warning, ATTR_MALLOC flag on BLI_memiter_alloc causes crash, see: D2756 */
-BLI_memiter *BLI_memiter_create(unsigned int chunk_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-void *BLI_memiter_alloc(BLI_memiter *mi,
- unsigned int size) ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL(1);
+BLI_memiter *BLI_memiter_create(unsigned int chunk_size)
+ ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
+void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size)
+ ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
ATTR_NONNULL(1, 3);
-void *BLI_memiter_calloc(BLI_memiter *mi,
- unsigned int size) ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL(1);
+void *BLI_memiter_calloc(BLI_memiter *mi, unsigned int size)
+ ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_memiter_destroy(BLI_memiter *mi) ATTR_NONNULL(1);
void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1);
unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
@@ -59,11 +58,11 @@ typedef struct BLI_memiter_handle {
uint elem_left;
} BLI_memiter_handle;
-void BLI_memiter_iter_init(BLI_memiter *mi, BLI_memiter_handle *iter) ATTR_NONNULL();
-bool BLI_memiter_iter_done(const BLI_memiter_handle *iter) ATTR_NONNULL();
-void *BLI_memiter_iter_step(BLI_memiter_handle *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BLI_memiter_iter_init(BLI_memiter *mi, BLI_memiter_handle *iter) ATTR_NONNULL(1, 2);
+bool BLI_memiter_iter_done(const BLI_memiter_handle *iter) ATTR_NONNULL(1);
+void *BLI_memiter_iter_step(BLI_memiter_handle *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_memiter_iter_step_size(BLI_memiter_handle *iter, uint *r_size) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ ATTR_NONNULL(1, 2);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index c11802d6270..4d9381093c7 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -38,9 +38,12 @@ typedef struct BLI_mempool BLI_mempool;
BLI_mempool *BLI_mempool_create(unsigned int esize,
unsigned int totelem,
unsigned int pchunk,
- unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-void *BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ unsigned int flag)
+ ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
+void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
+ ATTR_NONNULL(1);
+void *BLI_mempool_calloc(BLI_mempool *pool)
+ ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2);
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) ATTR_NONNULL(1);
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 83ccfda7e38..d6b068c3889 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -67,55 +67,17 @@ typedef enum TaskPriority {
TASK_PRIORITY_HIGH,
} TaskPriority;
-/**
- * Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong
- * assumptions were made. Typically that happens when doing "nested threading", i.e. one thread
- * schedules a bunch of main-tasks and those spawn new sub-tasks.
- *
- * What can happen is that when a main-task waits for its sub-tasks to complete on other threads,
- * another main-task is scheduled within the already running main-task. Generally, this is good,
- * because it leads to better performance. However, sometimes code (often unintentionally) makes
- * the assumption that at most one main-task runs on a thread at a time.
- *
- * The bugs often show themselves in two ways:
- * - Deadlock, when a main-task holds a mutex while waiting for its sub-tasks to complete.
- * - Data corruption, when a main-task makes wrong assumptions about a thread-local variable.
- *
- * Task isolation can avoid these bugs by making sure that a main-task does not start executing
- * another main-task while waiting for its sub-tasks. More precisely, a function that runs in an
- * isolated region is only allowed to run sub-tasks that were spawned in the same isolated region.
- *
- * Unfortunately, incorrect use of task isolation can lead to deadlocks itself. This can happen
- * when threading primitives are used that separate spawning tasks from executing them. The problem
- * occurs when a task is spawned in one isolated region while the tasks are waited for in another
- * isolated region. In this setup, the thread that is waiting for the spawned tasks to complete
- * cannot run the tasks itself. On a single thread, that causes a deadlock already. When there are
- * multiple threads, another thread will typically run the task and avoid the deadlock. However, if
- * this situation happens on all threads at the same time, all threads will deadlock. This happened
- * in T88598.
- */
-typedef enum TaskIsolation {
- /* Do not use task isolation. Always use this when tasks are pushed recursively. */
- TASK_ISOLATION_OFF,
- /* Run each task in its own isolated region. */
- TASK_ISOLATION_ON,
-} TaskIsolation;
-
typedef struct TaskPool TaskPool;
typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
/* Regular task pool that immediately starts executing tasks as soon as they
* are pushed, either on the current or another thread. */
-TaskPool *BLI_task_pool_create(void *userdata,
- TaskPriority priority,
- TaskIsolation task_isolation);
+TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority);
/* Background: always run tasks in a background thread, never immediately
* execute them. For running background jobs. */
-TaskPool *BLI_task_pool_create_background(void *userdata,
- TaskPriority priority,
- TaskIsolation task_isolation);
+TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority);
/* Background Serial: run tasks one after the other in the background,
* without parallelization between the tasks. */
@@ -125,9 +87,7 @@ TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority pr
* as threads can't immediately start working. But it can be used if the data
* structures the threads operate on are not fully initialized until all tasks
* are created. */
-TaskPool *BLI_task_pool_create_suspended(void *userdata,
- TaskPriority priority,
- TaskIsolation task_isolation);
+TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority);
/* No threads: immediately executes tasks on the same thread. For debugging. */
TaskPool *BLI_task_pool_create_no_threads(void *userdata);
@@ -365,6 +325,36 @@ struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
bool BLI_task_graph_node_push_work(struct TaskNode *task_node);
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node);
+/* Task Isolation
+ *
+ * Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong
+ * assumptions were made. Typically that happens when doing "nested threading", i.e. one thread
+ * schedules a bunch of main-tasks and those spawn new sub-tasks.
+ *
+ * What can happen is that when a main-task waits for its sub-tasks to complete on other threads,
+ * another main-task is scheduled within the already running main-task. Generally, this is good,
+ * because it leads to better performance. However, sometimes code (often unintentionally) makes
+ * the assumption that at most one main-task runs on a thread at a time.
+ *
+ * The bugs often show themselves in two ways:
+ * - Deadlock, when a main-task holds a mutex while waiting for its sub-tasks to complete.
+ * - Data corruption, when a main-task makes wrong assumptions about a thread-local variable.
+ *
+ * Task isolation can avoid these bugs by making sure that a main-task does not start executing
+ * another main-task while waiting for its sub-tasks. More precisely, a function that runs in an
+ * isolated region is only allowed to run sub-tasks that were spawned in the same isolated region.
+ *
+ * Unfortunately, incorrect use of task isolation can lead to deadlocks itself. This can happen
+ * when threading primitives are used that separate spawning tasks from executing them. The problem
+ * occurs when a task is spawned in one isolated region while the tasks are waited for in another
+ * isolated region. In this setup, the thread that is waiting for the spawned tasks to complete
+ * cannot run the tasks itself. On a single thread, that causes a deadlock already. When there are
+ * multiple threads, another thread will typically run the task and avoid the deadlock. However, if
+ * this situation happens on all threads at the same time, all threads will deadlock. This happened
+ * in T88598.
+ */
+void BLI_task_isolate(void (*func)(void *userdata), void *userdata);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh
index 8e963c958b2..5f5a17f6b58 100644
--- a/source/blender/blenlib/BLI_task.hh
+++ b/source/blender/blenlib/BLI_task.hh
@@ -31,6 +31,7 @@
# include <tbb/blocked_range.h>
# include <tbb/parallel_for.h>
# include <tbb/parallel_for_each.h>
+# include <tbb/task_arena.h>
# ifdef WIN32
/* We cannot keep this defined, since other parts of the code deal with this on their own, leading
* to multiple define warnings unless we un-define this, however we can only undefine this if we
@@ -44,7 +45,7 @@
#include "BLI_index_range.hh"
#include "BLI_utildefines.h"
-namespace blender {
+namespace blender::threading {
template<typename Range, typename Function>
void parallel_for_each(Range &range, const Function &function)
@@ -75,4 +76,14 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
#endif
}
-} // namespace blender
+/** See #BLI_task_isolate for a description of what isolating a task means. */
+template<typename Function> void isolate_task(const Function &function)
+{
+#ifdef WITH_TBB
+ tbb::this_task_arena::isolate(function);
+#else
+ function();
+#endif
+}
+
+} // namespace blender::threading
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 1c6e6ffe578..0bf117df43b 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -785,6 +785,7 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
* To use after the enum declaration. */
/* If any enumerator `C` is set to say `A|B`, then `C` would be the max enum value. */
# define ENUM_OPERATORS(_enum_type, _max_enum_value) \
+ extern "C++" { \
inline constexpr _enum_type operator|(_enum_type a, _enum_type b) \
{ \
return static_cast<_enum_type>(static_cast<int>(a) | b); \
@@ -804,7 +805,8 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
inline _enum_type &operator&=(_enum_type &a, _enum_type b) \
{ \
return a = static_cast<_enum_type>(static_cast<int>(a) & b); \
- }
+ } \
+ } /* extern "C++" */
#else
/* Output nothing. */
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index f771d26baab..0953e3f1946 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -105,7 +105,7 @@ int closedir(DIR *dp);
const char *dirname(char *path);
/* Windows utility functions. */
-void BLI_windows_register_blend_extension(const bool background);
+bool BLI_windows_register_blend_extension(const bool background);
void BLI_windows_get_default_root_dir(char *root_dir);
int BLI_windows_get_executable_dir(char *str);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e04f3c1b19d..677df9db026 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -20,7 +20,7 @@
set(INC
.
- # ../blenkernel # dont add this back!
+ # ../blenkernel # don't add this back!
../makesdna
../../../intern/atomic
../../../intern/eigen
@@ -103,6 +103,7 @@ set(SRC
intern/math_rotation.c
intern/math_solvers.c
intern/math_statistics.c
+ intern/math_time.c
intern/math_vec.cc
intern/math_vector.c
intern/math_vector_inline.c
@@ -241,6 +242,7 @@ set(SRC
BLI_math_rotation.h
BLI_math_solvers.h
BLI_math_statistics.h
+ BLI_math_time.h
BLI_math_vector.h
BLI_memarena.h
BLI_memblock.h
@@ -419,6 +421,7 @@ if(WITH_GTESTS)
tests/BLI_math_matrix_test.cc
tests/BLI_math_rotation_test.cc
tests/BLI_math_solvers_test.cc
+ tests/BLI_math_time_test.cc
tests/BLI_math_vector_test.cc
tests/BLI_memiter_test.cc
tests/BLI_memory_utils_test.cc
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 7b25fecfa45..5255e8b9902 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -166,7 +166,7 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, v
message = MEM_callocN(sizeof(char) * len, "BLI_dynstr_appendf");
}
- /* cant reuse the same args, so work on a copy */
+ /* can't reuse the same args, so work on a copy */
va_copy(args_cpy, args);
retval = vsnprintf(message, len, format, args_cpy);
va_end(args_cpy);
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index b694f9c7fc0..250915383cf 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -192,7 +192,7 @@
/* Disallow chunks bigger than the regular chunk size scaled by this value
* note: must be at least 2!
- * however, this code runs wont run in tests unless its ~1.1 ugh.
+ * however, this code runs won't run in tests unless it's ~1.1 ugh.
* so lower only to check splitting works.
*/
# define BCHUNK_SIZE_MAX_MUL 2
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index 9444d1a29cb..eb3e64c49e6 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -226,6 +226,8 @@ template<typename Arith_t> struct CDTFace {
int visit_index{0};
/** Marks this face no longer used. */
bool deleted{false};
+ /** Marks this face as part of a hole. */
+ bool hole{false};
CDTFace() = default;
};
@@ -481,9 +483,9 @@ template<typename T> void cdt_draw(const std::string &label, const CDTArrangemen
* This is just for developer debugging anyway, and should never be called in production Blender.
*/
# ifdef _WIN32
- const char *drawfile = "./debug_draw.html";
+ const char *drawfile = "./cdt_debug_draw.html";
# else
- const char *drawfile = "/tmp/debug_draw.html";
+ const char *drawfile = "/tmp/cdt_debug_draw.html";
# endif
constexpr int max_draw_width = 1800;
constexpr int max_draw_height = 1600;
@@ -2364,9 +2366,6 @@ template<typename T> void remove_non_constraint_edges_leave_valid_bmesh(CDT_stat
template<typename T> void remove_outer_edges_until_constraints(CDT_state<T> *cdt_state)
{
- // LinkNode *fstack = NULL;
- // SymEdge *se, *se_start;
- // CDTFace *f, *fsym;
int visit = ++cdt_state->visit_count;
cdt_state->cdt.outer_face->visit_index = visit;
@@ -2415,6 +2414,137 @@ template<typename T> void remove_outer_edges_until_constraints(CDT_state<T> *cdt
}
}
+template<typename T> void remove_faces_in_holes(CDT_state<T> *cdt_state)
+{
+ CDTArrangement<T> *cdt = &cdt_state->cdt;
+ for (int i : cdt->faces.index_range()) {
+ CDTFace<T> *f = cdt->faces[i];
+ if (!f->deleted && f->hole) {
+ f->deleted = true;
+ SymEdge<T> *se = f->symedge;
+ SymEdge<T> *se_start = se;
+ SymEdge<T> *se_next = nullptr;
+ do {
+ BLI_assert(se != nullptr);
+ se_next = se->next; /* In case we delete this edge. */
+ if (se->edge && !is_constrained_edge(se->edge)) {
+ /* Invalidate one half of this edge. The other has will be or has been
+ * handled with the adjacent triangle is processed: it should be part of the same hole.
+ */
+ se->next = nullptr;
+ }
+ se = se_next;
+ } while (se != se_start);
+ }
+ }
+}
+
+/**
+ * Set the hole member of each CDTFace to true for each face that is detected to be part of a
+ * hole. A hole face is define as one for which, when a ray is shot from a point inside the face
+ * to infinity, it crosses an even number of constraint edges. We'll choose a ray direction that
+ * is extremely unlikely to exactly superimpose some edge, so avoiding the need to be careful
+ * about such overlaps.
+ *
+ * To improve performance, we gather together faces that should have the same winding number, and
+ * only shoot rays once.
+ */
+template<typename T> void detect_holes(CDT_state<T> *cdt_state)
+{
+ CDTArrangement<T> *cdt = &cdt_state->cdt;
+
+ /* Make it so that each face with the same visit_index is connected through a path of
+ * non-constraint edges. */
+ Vector<CDTFace<T> *> fstack;
+ Vector<CDTFace<T> *> region_rep_face;
+ for (int i : cdt->faces.index_range()) {
+ cdt->faces[i]->visit_index = -1;
+ }
+ int cur_region = -1;
+ cdt->outer_face->visit_index = -2; /* Don't visit this one. */
+ for (int i : cdt->faces.index_range()) {
+ CDTFace<T> *f = cdt->faces[i];
+ if (!f->deleted && f->symedge && f->visit_index == -1) {
+ fstack.append(f);
+ ++cur_region;
+ region_rep_face.append(f);
+ while (!fstack.is_empty()) {
+ CDTFace<T> *f = fstack.pop_last();
+ if (f->visit_index != -1) {
+ continue;
+ }
+ f->visit_index = cur_region;
+ SymEdge<T> *se_start = f->symedge;
+ SymEdge<T> *se = se_start;
+ do {
+ if (se->edge && !is_constrained_edge(se->edge)) {
+ CDTFace<T> *fsym = sym(se)->face;
+ if (fsym && !fsym->deleted && fsym->visit_index == -1) {
+ fstack.append(fsym);
+ }
+ }
+ se = se->next;
+ } while (se != se_start);
+ }
+ }
+ }
+ cdt_state->visit_count = ++cur_region; /* Good start for next use of visit_count. */
+
+ /* Now get hole status for each region_rep_face. */
+
+ /* Pick a ray end almost certain to be outside everything and in direction
+ * that is unlikely to hit a vertex or overlap an edge exactly. */
+ FatCo<T> ray_end;
+ ray_end.exact = vec2<T>(123456, 654321);
+ for (int i : region_rep_face.index_range()) {
+ CDTFace<T> *f = region_rep_face[i];
+ FatCo<T> mid;
+ mid.exact[0] = (f->symedge->vert->co.exact[0] + f->symedge->next->vert->co.exact[0] +
+ f->symedge->next->next->vert->co.exact[0]) /
+ 3;
+ mid.exact[1] = (f->symedge->vert->co.exact[1] + f->symedge->next->vert->co.exact[1] +
+ f->symedge->next->next->vert->co.exact[1]) /
+ 3;
+ int hits = 0;
+ /* TODO: Use CDT data structure here to greatly reduce search for intersections! */
+ for (const CDTEdge<T> *e : cdt->edges) {
+ if (!is_deleted_edge(e) && is_constrained_edge(e)) {
+ if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
+ continue; /* Don't count hits on edges between faces in same region. */
+ }
+ auto isect = vec2<T>::isect_seg_seg(ray_end.exact,
+ mid.exact,
+ e->symedges[0].vert->co.exact,
+ e->symedges[1].vert->co.exact);
+ switch (isect.kind) {
+ case vec2<T>::isect_result::LINE_LINE_CROSS: {
+ hits++;
+ break;
+ }
+ case vec2<T>::isect_result::LINE_LINE_EXACT:
+ case vec2<T>::isect_result::LINE_LINE_NONE:
+ case vec2<T>::isect_result::LINE_LINE_COLINEAR:
+ break;
+ }
+ }
+ }
+ f->hole = (hits % 2) == 0;
+ }
+
+ /* Finally, propagate hole status to all holes of a region. */
+ for (int i : cdt->faces.index_range()) {
+ CDTFace<T> *f = cdt->faces[i];
+ int region = f->visit_index;
+ if (region < 0) {
+ continue;
+ }
+ CDTFace<T> *f_region_rep = region_rep_face[region];
+ if (i >= 0) {
+ f->hole = f_region_rep->hole;
+ }
+ }
+}
+
/**
* Remove edges and merge faces to get desired output, as per options.
* \note the cdt cannot be further changed after this.
@@ -2439,6 +2569,13 @@ void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type outpu
}
}
+ bool need_holes = output_type == CDT_INSIDE_WITH_HOLES ||
+ output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES;
+
+ if (need_holes) {
+ detect_holes(cdt_state);
+ }
+
if (output_type == CDT_CONSTRAINTS) {
remove_non_constraint_edges(cdt_state);
}
@@ -2448,6 +2585,14 @@ void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type outpu
else if (output_type == CDT_INSIDE) {
remove_outer_edges_until_constraints(cdt_state);
}
+ else if (output_type == CDT_INSIDE_WITH_HOLES) {
+ remove_outer_edges_until_constraints(cdt_state);
+ remove_faces_in_holes(cdt_state);
+ }
+ else if (output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES) {
+ remove_non_constraint_edges_leave_valid_bmesh(cdt_state);
+ remove_faces_in_holes(cdt_state);
+ }
}
template<typename T>
diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h
index c92dc2e95a3..2a0e8b3ec68 100644
--- a/source/blender/blenlib/intern/kdtree_impl.h
+++ b/source/blender/blenlib/intern/kdtree_impl.h
@@ -882,7 +882,7 @@ static void deduplicate_recursive(const struct DeDuplicateParams *p, uint i)
* although it can still be used as a target.
* \returns The number of merges found (includes any merges already in the \a duplicates array).
*
- * \note Merging is always a single step (target indices wont be marked for merging).
+ * \note Merging is always a single step (target indices won't be marked for merging).
*/
int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
const float range,
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 508de506ae8..de50ae27b94 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -3344,6 +3344,13 @@ float closest_to_ray_v3(float r_close[3],
const float ray_dir[3])
{
float h[3], lambda;
+
+ if (UNLIKELY(is_zero_v3(ray_dir))) {
+ lambda = 0.0f;
+ copy_v3_v3(r_close, ray_orig);
+ return lambda;
+ }
+
sub_v3_v3v3(h, p, ray_orig);
lambda = dot_v3v3(ray_dir, h) / dot_v3v3(ray_dir, ray_dir);
madd_v3_v3v3fl(r_close, ray_orig, ray_dir, lambda);
@@ -4467,7 +4474,7 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[
d_curr = d_next;
DIR_V2_SET(&d_next, v_next, co);
ht = mean_value_half_tan_v2_db(&d_curr, &d_next);
- w[i_curr] = (float)((ht_prev + ht) / d_curr.len);
+ w[i_curr] = (d_curr.len == 0.0) ? 0.0f : (float)((ht_prev + ht) / d_curr.len);
totweight += w[i_curr];
/* step */
@@ -4904,8 +4911,8 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
- float top[4],
float bottom[4],
+ float top[4],
float near[4],
float far[4])
{
@@ -6211,6 +6218,19 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
return dot_v3v3(cross_a, cross_b) > 0.0f;
}
+bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float v4[3],
+ const float normal[3])
+{
+ float dir_v3v1[3], tangent[3];
+ sub_v3_v3v3(dir_v3v1, v3, v1);
+ cross_v3_v3v3(tangent, dir_v3v1, normal);
+ const float dot = dot_v3v3(v1, tangent);
+ return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
+}
+
/**
* Return the value which the distance between points will need to be scaled by,
* to define a handle, given both points are on a perfect circle.
@@ -6229,7 +6249,7 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
const float tan_dot = dot_v3v3(tan_l, tan_r);
if (tan_dot > 1.0f - eps) {
- /* no angle difference (use fallback, length wont make any difference) */
+ /* no angle difference (use fallback, length won't make any difference) */
return (1.0f / 3.0f) * 0.75f;
}
if (tan_dot < -1.0f + eps) {
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index 23c351026f2..655d3fcc4c0 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -244,10 +244,13 @@ MINLINE int min_axis_v3(const float vec[3])
}
/**
- * Simple method to find how many tri's we need when we already know the corner+poly count.
+ * Simple function to either:
+ * - Calculate how many triangles needed from the total number of polygons + loops.
+ * - Calculate the first triangle index from the polygon index & that polygons loop-start.
*
- * \param poly_count: The number of ngon's/tris (1-2 sided faces will give incorrect results)
- * \param corner_count: also known as loops in BMesh/DNA
+ * \param poly_count: The number of polygons or polygon-index
+ * (3+ sided faces, 1-2 sided give incorrect results).
+ * \param corner_count: The number of corners (also called loop-index).
*/
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
{
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 57fe99ce019..469cd573372 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1924,6 +1924,31 @@ void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order
gmat[R->axis[2]][R->axis[2]] = 1;
}
+void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order)
+{
+ float quat[4], quat_b[4];
+
+ eulO_to_quat(quat, a, order);
+ eulO_to_quat(quat_b, b, order);
+
+ mul_qt_qtqt(quat, quat_b, quat);
+
+ quat_to_eulO(r_eul, order, quat);
+}
+
+void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order)
+{
+ float quat[4], quat_b[4];
+
+ eulO_to_quat(quat, a, order);
+ eulO_to_quat(quat_b, b, order);
+
+ invert_qt_normalized(quat_b);
+ mul_qt_qtqt(quat, quat_b, quat);
+
+ quat_to_eulO(r_eul, order, quat);
+}
+
/******************************* Dual Quaternions ****************************/
/**
diff --git a/source/blender/blenlib/intern/math_time.c b/source/blender/blenlib/intern/math_time.c
new file mode 100644
index 00000000000..b85de7817dd
--- /dev/null
+++ b/source/blender/blenlib/intern/math_time.c
@@ -0,0 +1,70 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_math.h"
+
+/** Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
+ * and/or milliseconds (depending on which return parameters are not NULL).
+ *
+ * \note The smallest given return parameter will get the potential fractional remaining time
+ * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
+ * `r_minutes` will be set to `1.5`.
+ */
+void BLI_math_time_seconds_decompose(double seconds,
+ double *r_days,
+ double *r_hours,
+ double *r_minutes,
+ double *r_seconds,
+ double *r_milliseconds)
+{
+ BLI_assert(r_days != NULL || r_hours != NULL || r_minutes != NULL || r_seconds != NULL ||
+ r_milliseconds != NULL);
+
+ if (r_days != NULL) {
+ seconds = modf(seconds / SECONDS_IN_DAY, r_days) * SECONDS_IN_DAY;
+ }
+ if (r_hours != NULL) {
+ seconds = modf(seconds / SECONDS_IN_HOUR, r_hours) * SECONDS_IN_HOUR;
+ }
+ if (r_minutes != NULL) {
+ seconds = modf(seconds / SECONDS_IN_MINUTE, r_minutes) * SECONDS_IN_MINUTE;
+ }
+ if (r_seconds != NULL) {
+ seconds = modf(seconds, r_seconds);
+ }
+ if (r_milliseconds != NULL) {
+ *r_milliseconds = seconds / SECONDS_IN_MILLISECONDS;
+ }
+ else if (r_seconds != NULL) {
+ *r_seconds += seconds;
+ }
+ else if (r_minutes != NULL) {
+ *r_minutes += seconds / SECONDS_IN_MINUTE;
+ }
+ else if (r_hours != NULL) {
+ *r_hours += seconds / SECONDS_IN_HOUR;
+ }
+ else if (r_days != NULL) {
+ *r_days = seconds / SECONDS_IN_DAY;
+ }
+}
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index fb7b96fde78..35dfe421cf0 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -657,10 +657,13 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
*/
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
{
- const float mul = dot_v2v2(p, v_proj) / dot_v2v2(v_proj, v_proj);
+ if (UNLIKELY(is_zero_v2(v_proj))) {
+ zero_v2(out);
+ return;
+ }
- out[0] = mul * v_proj[0];
- out[1] = mul * v_proj[1];
+ const float mul = dot_v2v2(p, v_proj) / dot_v2v2(v_proj, v_proj);
+ mul_v2_v2fl(out, v_proj, mul);
}
/**
@@ -668,20 +671,24 @@ void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
*/
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
{
- const float mul = dot_v3v3(p, v_proj) / dot_v3v3(v_proj, v_proj);
+ if (UNLIKELY(is_zero_v3(v_proj))) {
+ zero_v3(out);
+ return;
+ }
- out[0] = mul * v_proj[0];
- out[1] = mul * v_proj[1];
- out[2] = mul * v_proj[2];
+ const float mul = dot_v3v3(p, v_proj) / dot_v3v3(v_proj, v_proj);
+ mul_v3_v3fl(out, v_proj, mul);
}
void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3])
{
- const double mul = dot_v3v3_db(p, v_proj) / dot_v3v3_db(v_proj, v_proj);
+ if (UNLIKELY(is_zero_v3_db(v_proj))) {
+ zero_v3_db(out);
+ return;
+ }
- out[0] = mul * v_proj[0];
- out[1] = mul * v_proj[1];
- out[2] = mul * v_proj[2];
+ const double mul = dot_v3v3_db(p, v_proj) / dot_v3v3_db(v_proj, v_proj);
+ mul_v3_v3db_db(out, v_proj, mul);
}
/**
@@ -690,10 +697,9 @@ void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2])
{
BLI_ASSERT_UNIT_V2(v_proj);
- const float mul = dot_v2v2(p, v_proj);
- out[0] = mul * v_proj[0];
- out[1] = mul * v_proj[1];
+ const float mul = dot_v2v2(p, v_proj);
+ mul_v2_v2fl(out, v_proj, mul);
}
/**
@@ -702,11 +708,9 @@ void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_pr
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
{
BLI_ASSERT_UNIT_V3(v_proj);
- const float mul = dot_v3v3(p, v_proj);
- out[0] = mul * v_proj[0];
- out[1] = mul * v_proj[1];
- out[2] = mul * v_proj[2];
+ const float mul = dot_v3v3(p, v_proj);
+ mul_v3_v3fl(out, v_proj, mul);
}
/**
@@ -725,37 +729,31 @@ void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_pr
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane);
-
- out[0] = p[0] - (mul * v_plane[0]);
- out[1] = p[1] - (mul * v_plane[1]);
- out[2] = p[2] - (mul * v_plane[2]);
+ /* out[x] = p[x] - (mul * v_plane[x]) */
+ madd_v3_v3v3fl(out, p, v_plane, -mul);
}
void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2])
{
const float mul = dot_v2v2(p, v_plane) / dot_v2v2(v_plane, v_plane);
-
- out[0] = p[0] - (mul * v_plane[0]);
- out[1] = p[1] - (mul * v_plane[1]);
+ /* out[x] = p[x] - (mul * v_plane[x]) */
+ madd_v2_v2v2fl(out, p, v_plane, -mul);
}
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
BLI_ASSERT_UNIT_V3(v_plane);
const float mul = dot_v3v3(p, v_plane);
-
- out[0] = p[0] - (mul * v_plane[0]);
- out[1] = p[1] - (mul * v_plane[1]);
- out[2] = p[2] - (mul * v_plane[2]);
+ /* out[x] = p[x] - (mul * v_plane[x]) */
+ madd_v3_v3v3fl(out, p, v_plane, -mul);
}
void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2])
{
BLI_ASSERT_UNIT_V2(v_plane);
const float mul = dot_v2v2(p, v_plane);
-
- out[0] = p[0] - (mul * v_plane[0]);
- out[1] = p[1] - (mul * v_plane[1]);
+ /* out[x] = p[x] - (mul * v_plane[x]) */
+ madd_v2_v2v2fl(out, p, v_plane, -mul);
}
/* project a vector on a plane defined by normal and a plane point p */
@@ -767,9 +765,8 @@ void project_v3_plane(float out[3], const float plane_no[3], const float plane_c
sub_v3_v3v3(vector, out, plane_co);
mul = dot_v3v3(vector, plane_no) / len_squared_v3(plane_no);
- mul_v3_v3fl(vector, plane_no, mul);
-
- sub_v3_v3(out, vector);
+ /* out[x] = out[x] - (mul * plane_no[x]) */
+ madd_v3_v3fl(out, plane_no, -mul);
}
/* Returns a vector bisecting the angle at b formed by a, b and c */
@@ -802,24 +799,18 @@ void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const floa
*/
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
- const float dot2 = 2.0f * dot_v3v3(v, normal);
-
BLI_ASSERT_UNIT_V3(normal);
-
- out[0] = v[0] - (dot2 * normal[0]);
- out[1] = v[1] - (dot2 * normal[1]);
- out[2] = v[2] - (dot2 * normal[2]);
+ const float dot2 = 2.0f * dot_v3v3(v, normal);
+ /* out[x] = v[x] - (dot2 * normal[x]) */
+ madd_v3_v3v3fl(out, v, normal, -dot2);
}
void reflect_v3_v3v3_db(double out[3], const double v[3], const double normal[3])
{
+ BLI_ASSERT_UNIT_V3_DB(normal);
const double dot2 = 2.0 * dot_v3v3_db(v, normal);
-
- /* BLI_ASSERT_UNIT_V3_DB(normal); this assert is not known? */
-
- out[0] = v[0] - (dot2 * normal[0]);
- out[1] = v[1] - (dot2 * normal[1]);
- out[2] = v[2] - (dot2 * normal[2]);
+ /* out[x] = v[x] - (dot2 * normal[x]) */
+ madd_v3_v3v3db_db(out, v, normal, -dot2);
}
/**
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index ead354c2d87..db9ece81c59 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -722,6 +722,13 @@ MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], floa
r[2] = a[2] + b[2] * f;
}
+MINLINE void madd_v3_v3v3db_db(double r[3], const double a[3], const double b[3], double f)
+{
+ r[0] = a[0] + b[0] * f;
+ r[1] = a[1] + b[1] * f;
+ r[2] = a[2] + b[2] * f;
+}
+
MINLINE void madd_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
{
r[0] = a[0] + b[0] * c[0];
@@ -1282,6 +1289,21 @@ MINLINE bool is_zero_v4(const float v[4])
return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f && v[3] == 0.0f);
}
+MINLINE bool is_zero_v2_db(const double v[2])
+{
+ return (v[0] == 0.0 && v[1] == 0.0);
+}
+
+MINLINE bool is_zero_v3_db(const double v[3])
+{
+ return (v[0] == 0.0 && v[1] == 0.0 && v[2] == 0.0);
+}
+
+MINLINE bool is_zero_v4_db(const double v[4])
+{
+ return (v[0] == 0.0 && v[1] == 0.0 && v[2] == 0.0 && v[3] == 0.0);
+}
+
MINLINE bool is_one_v3(const float v[3])
{
return (v[0] == 1.0f && v[1] == 1.0f && v[2] == 1.0f);
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 25aeae519c1..9f7824a0029 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -1406,9 +1406,9 @@ static int find_cell_for_point_near_edge(mpq3 p,
int dummy_index = p_sorted_dummy - sorted_tris.begin();
int prev_tri = (dummy_index == 0) ? sorted_tris[sorted_tris.size() - 1] :
sorted_tris[dummy_index - 1];
- int next_tri = (dummy_index == sorted_tris.size() - 1) ? sorted_tris[0] :
- sorted_tris[dummy_index + 1];
if (dbg_level > 0) {
+ int next_tri = (dummy_index == sorted_tris.size() - 1) ? sorted_tris[0] :
+ sorted_tris[dummy_index + 1];
std::cout << "prev tri to dummy = " << prev_tri << "; next tri to dummy = " << next_tri
<< "\n";
}
@@ -1983,7 +1983,7 @@ static void populate_comp_bbs(const Vector<Vector<int>> &components,
* absolute value of any coordinate. Do it first per component,
* then get the overall max. */
Array<double> max_abs(components.size(), 0.0);
- parallel_for(components.index_range(), comp_grainsize, [&](IndexRange comp_range) {
+ threading::parallel_for(components.index_range(), comp_grainsize, [&](IndexRange comp_range) {
for (int c : comp_range) {
BoundingBox &bb = comp_bb[c];
double &maxa = max_abs[c];
@@ -2691,7 +2691,7 @@ static IMesh raycast_tris_boolean(const IMesh &tm,
tbb::spin_mutex mtx;
# endif
const int grainsize = 256;
- parallel_for(IndexRange(tm.face_size()), grainsize, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(tm.face_size()), grainsize, [&](IndexRange range) {
Array<float> in_shape(nshapes, 0);
Array<int> winding(nshapes, 0);
for (int t : range) {
@@ -3391,7 +3391,7 @@ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out,
}
/* For now: need plane normals for all triangles. */
const int grainsize = 1024;
- parallel_for(tm_out.face_index_range(), grainsize, [&](IndexRange range) {
+ threading::parallel_for(tm_out.face_index_range(), grainsize, [&](IndexRange range) {
for (int i : range) {
Face *tri = tm_out.face(i);
tri->populate_plane(false);
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index cb6cce30f92..f3c348b2b44 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -180,7 +180,7 @@ void BLI_path_normalize(const char *relabase, char *path)
else {
if (path[0] == '/' && path[1] == '/') {
if (path[2] == '\0') {
- return; /* path is "//" - cant clean it */
+ return; /* path is "//" - can't clean it */
}
path = path + 2; /* leave the initial "//" untouched */
}
@@ -236,7 +236,7 @@ void BLI_path_normalize(const char *relabase, char *path)
}
else {
/* support for odd paths: eg /../home/me --> /home/me
- * this is a valid path in blender but we cant handle this the usual way below
+ * this is a valid path in blender but we can't handle this the usual way below
* simply strip this prefix then evaluate the path as usual.
* pythons os.path.normpath() does this */
@@ -1646,8 +1646,8 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
/**
* Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
*
- * - Wont change \a string.
- * - Wont create any directories.
+ * - Won't change \a string.
+ * - Won't create any directories.
* - Doesn't use CWD, or deal with relative paths.
* - Only fill's in \a dir and \a file when they are non NULL.
*/
@@ -2013,9 +2013,9 @@ void BLI_path_slash_native(char *path)
{
#ifdef WIN32
if (path && BLI_strnlen(path, 3) > 2) {
- BLI_str_replace_char(path + 2, '/', '\\');
+ BLI_str_replace_char(path + 2, ALTSEP, SEP);
}
#else
- BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/');
+ BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), ALTSEP, SEP);
#endif
}
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index 98fa5c872b0..7425bab885c 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -320,7 +320,7 @@ static void polyedge_rotate(struct HalfEdge *edges, struct HalfEdge *e)
* The intention is that this calculates the output of #BLI_polyfill_calc
* \note assumes the \a coords form a boundary,
* so any edges running along contiguous (wrapped) indices,
- * are ignored since the edges wont share 2 faces.
+ * are ignored since the edges won't share 2 faces.
*/
void BLI_polyfill_beautify(const float (*coords)[2],
const uint coords_tot,
diff --git a/source/blender/blenlib/intern/storage_apple.mm b/source/blender/blenlib/intern/storage_apple.mm
index 2a4bbffa60e..8af98d61ecb 100644
--- a/source/blender/blenlib/intern/storage_apple.mm
+++ b/source/blender/blenlib/intern/storage_apple.mm
@@ -24,10 +24,15 @@
*/
#import <Foundation/Foundation.h>
+#include <string>
+#include <sys/xattr.h>
#include "BLI_fileops.h"
#include "BLI_path_util.h"
+/* Extended file attribute used by OneDrive to mark placeholder files. */
+static const char *ONEDRIVE_RECALLONOPEN_ATTRIBUTE = "com.microsoft.OneDrive.RecallOnOpen";
+
/**
* \param r_targetpath: Buffer for the target path an alias points to.
* \return Whether the file at the input path is an alias.
@@ -66,6 +71,67 @@ bool BLI_file_alias_target(const char *filepath, char r_targetpath[FILE_MAXDIR])
return true;
}
+/**
+ * Checks if the given string of listxattr() attributes contains a specific attribute.
+ *
+ * \param attributes: a string of null-terminated listxattr() attributes.
+ * \param search_attribute: the attribute to search for.
+ * \return 'true' when the attribute is found, otherwise 'false'.
+ */
+static bool find_attribute(const std::string &attributes, const char *search_attribute)
+{
+ /* Attributes is a list of consecutive null-terminated strings. */
+ const char *end = attributes.data() + attributes.size();
+ for (const char *item = attributes.data(); item < end; item += strlen(item) + 1) {
+ if (STREQ(item, search_attribute)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Checks if the file is merely a placeholder for a OneDrive file that hasn't yet been downloaded.
+ *
+ * \param path: the path of the file.
+ * \return 'true' when the file is a OneDrive placeholder, otherwise 'false'.
+ */
+static bool test_onedrive_file_is_placeholder(const char *path)
+{
+ /* Note: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
+ * attribute. In theory this attribute can also be set on files that aren't located inside a
+ * OneDrive folder. Maybe additional checks are required? */
+
+ /* Get extended file attributes */
+ ssize_t size = listxattr(path, nullptr, 0, XATTR_NOFOLLOW);
+ if (size < 1) {
+ return false;
+ }
+
+ std::string attributes(size, '\0');
+ size = listxattr(path, attributes.data(), size, XATTR_NOFOLLOW);
+ /* In case listxattr() has failed the second time it's called. */
+ if (size < 1) {
+ return false;
+ }
+
+ /* Check for presence of 'com.microsoft.OneDrive.RecallOnOpen' attribute. */
+ return find_attribute(attributes, ONEDRIVE_RECALLONOPEN_ATTRIBUTE);
+}
+
+/**
+ * Checks if the file is marked as offline and not immediately available.
+ *
+ * \param path: the path of the file.
+ * \return 'true' when the file is a placeholder, otherwise 'false'.
+ */
+static bool test_file_is_offline(const char *path)
+{
+ /* Logic for additional cloud storage providers could be added in the future. */
+ return test_onedrive_file_is_placeholder(path);
+}
+
eFileAttributes BLI_file_attributes(const char *path)
{
int ret = 0;
@@ -76,15 +142,28 @@ eFileAttributes BLI_file_attributes(const char *path)
const NSURL *fileURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:path
isDirectory:NO
relativeToURL:nil];
- NSArray *resourceKeys =
- @[ NSURLIsAliasFileKey, NSURLIsHiddenKey, NSURLIsReadableKey, NSURLIsWritableKey ];
+
+ /* Querying NSURLIsReadableKey and NSURLIsWritableKey keys for OneDrive placeholder files
+ * triggers their unwanted download. */
+ NSArray *resourceKeys = nullptr;
+ const bool is_offline = test_file_is_offline(path);
+
+ if (is_offline) {
+ resourceKeys = @[ NSURLIsAliasFileKey, NSURLIsHiddenKey ];
+ }
+ else {
+ resourceKeys =
+ @[ NSURLIsAliasFileKey, NSURLIsHiddenKey, NSURLIsReadableKey, NSURLIsWritableKey ];
+ }
const NSDictionary *resourceKeyValues = [fileURL resourceValuesForKeys:resourceKeys error:nil];
const bool is_alias = [resourceKeyValues[(void)(@"@%"), NSURLIsAliasFileKey] boolValue];
const bool is_hidden = [resourceKeyValues[(void)(@"@%"), NSURLIsHiddenKey] boolValue];
- const bool is_readable = [resourceKeyValues[(void)(@"@%"), NSURLIsReadableKey] boolValue];
- const bool is_writable = [resourceKeyValues[(void)(@"@%"), NSURLIsWritableKey] boolValue];
+ const bool is_readable = is_offline ||
+ [resourceKeyValues[(void)(@"@%"), NSURLIsReadableKey] boolValue];
+ const bool is_writable = is_offline ||
+ [resourceKeyValues[(void)(@"@%"), NSURLIsWritableKey] boolValue];
if (is_alias) {
ret |= FILE_ATTR_ALIAS;
@@ -98,6 +177,9 @@ eFileAttributes BLI_file_attributes(const char *path)
if (!is_readable) {
ret |= FILE_ATTR_SYSTEM;
}
+ if (is_offline) {
+ ret |= FILE_ATTR_OFFLINE;
+ }
}
return (eFileAttributes)ret;
diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc
index 32450c16630..ff7d0ecb4c4 100644
--- a/source/blender/blenlib/intern/task_graph.cc
+++ b/source/blender/blenlib/intern/task_graph.cc
@@ -91,7 +91,7 @@ struct TaskNode {
#ifdef WITH_TBB
tbb::flow::continue_msg run(const tbb::flow::continue_msg UNUSED(input))
{
- tbb::this_task_arena::isolate([this] { run_func(task_data); });
+ run_func(task_data);
return tbb::flow::continue_msg();
}
#endif
diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c
index ee41c277b34..f67671c65e0 100644
--- a/source/blender/blenlib/intern/task_iterator.c
+++ b/source/blender/blenlib/intern/task_iterator.c
@@ -237,7 +237,7 @@ static void task_parallel_iterator_do(const TaskParallelSettings *settings,
void *userdata_chunk_array = NULL;
const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
- TaskPool *task_pool = BLI_task_pool_create(state, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ TaskPool *task_pool = BLI_task_pool_create(state, TASK_PRIORITY_HIGH);
if (use_userdata_chunk) {
userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
@@ -442,7 +442,7 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool,
return;
}
- task_pool = BLI_task_pool_create(&state, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ task_pool = BLI_task_pool_create(&state, TASK_PRIORITY_HIGH);
num_threads = BLI_task_scheduler_num_threads();
/* The idea here is to prevent creating task for each of the loop iterations
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
index d72674c1c00..6250c1b9986 100644
--- a/source/blender/blenlib/intern/task_pool.cc
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -22,7 +22,6 @@
#include <cstdlib>
#include <memory>
-#include <thread>
#include <utility>
#include "MEM_guardedalloc.h"
@@ -156,7 +155,6 @@ enum TaskPoolType {
struct TaskPool {
TaskPoolType type;
bool use_threads;
- TaskIsolation task_isolation;
ThreadMutex user_mutex;
void *userdata;
@@ -164,8 +162,6 @@ struct TaskPool {
#ifdef WITH_TBB
/* TBB task pool. */
TBBTaskGroup tbb_group;
- /* This is used to detect a common way to accidentally create a deadlock with task isolation. */
- std::thread::id task_pool_create_thread_id;
#endif
volatile bool is_suspended;
BLI_mempool *suspended_mempool;
@@ -179,33 +175,9 @@ struct TaskPool {
/* Execute task. */
void Task::operator()() const
{
-#ifdef WITH_TBB
- if (pool->task_isolation == TASK_ISOLATION_ON) {
- tbb::this_task_arena::isolate([this] { run(pool, taskdata); });
- return;
- }
-#endif
run(pool, taskdata);
}
-static void assert_on_valid_thread(TaskPool *pool)
-{
- /* TODO: Remove this `return` to enable the check. */
- return;
-#ifdef DEBUG
-# ifdef WITH_TBB
- if (pool->task_isolation == TASK_ISOLATION_ON) {
- const std::thread::id current_id = std::this_thread::get_id();
- /* This task pool is modified from different threads. To avoid deadlocks, `TASK_ISOLATION_OFF`
- * has to be used. Task isolation can still be used in a more fine-grained way within the
- * tasks, but should not be enabled for the entire task pool. */
- BLI_assert(pool->task_pool_create_thread_id == current_id);
- }
-# endif
-#endif
- UNUSED_VARS_NDEBUG(pool);
-}
-
/* TBB Task Pool.
*
* Task pool using the TBB scheduler for tasks. When building without TBB
@@ -391,10 +363,7 @@ static void background_task_pool_free(TaskPool *pool)
/* Task Pool */
-static TaskPool *task_pool_create_ex(void *userdata,
- TaskPoolType type,
- TaskPriority priority,
- TaskIsolation task_isolation)
+static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPriority priority)
{
const bool use_threads = BLI_task_scheduler_num_threads() > 1 && type != TASK_POOL_NO_THREADS;
@@ -410,11 +379,6 @@ static TaskPool *task_pool_create_ex(void *userdata,
pool->type = type;
pool->use_threads = use_threads;
- pool->task_isolation = task_isolation;
-
-#ifdef WITH_TBB
- pool->task_pool_create_thread_id = std::this_thread::get_id();
-#endif
pool->userdata = userdata;
BLI_mutex_init(&pool->user_mutex);
@@ -437,9 +401,9 @@ static TaskPool *task_pool_create_ex(void *userdata,
/**
* Create a normal task pool. Tasks will be executed as soon as they are added.
*/
-TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority, TaskIsolation task_isolation)
+TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(userdata, TASK_POOL_TBB, priority, task_isolation);
+ return task_pool_create_ex(userdata, TASK_POOL_TBB, priority);
}
/**
@@ -454,11 +418,9 @@ TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority, TaskIsolat
* they could end never being executed, since the 'fallback' background thread is already
* busy with parent task in single-threaded context).
*/
-TaskPool *BLI_task_pool_create_background(void *userdata,
- TaskPriority priority,
- TaskIsolation task_isolation)
+TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND, priority, task_isolation);
+ return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND, priority);
}
/**
@@ -466,11 +428,9 @@ TaskPool *BLI_task_pool_create_background(void *userdata,
* for until BLI_task_pool_work_and_wait() is called. This helps reducing threading
* overhead when pushing huge amount of small initial tasks from the main thread.
*/
-TaskPool *BLI_task_pool_create_suspended(void *userdata,
- TaskPriority priority,
- TaskIsolation task_isolation)
+TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(userdata, TASK_POOL_TBB_SUSPENDED, priority, task_isolation);
+ return task_pool_create_ex(userdata, TASK_POOL_TBB_SUSPENDED, priority);
}
/**
@@ -479,8 +439,7 @@ TaskPool *BLI_task_pool_create_suspended(void *userdata,
*/
TaskPool *BLI_task_pool_create_no_threads(void *userdata)
{
- return task_pool_create_ex(
- userdata, TASK_POOL_NO_THREADS, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ return task_pool_create_ex(userdata, TASK_POOL_NO_THREADS, TASK_PRIORITY_HIGH);
}
/**
@@ -489,7 +448,7 @@ TaskPool *BLI_task_pool_create_no_threads(void *userdata)
*/
TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority)
{
- return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND_SERIAL, priority, TASK_ISOLATION_ON);
+ return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND_SERIAL, priority);
}
void BLI_task_pool_free(TaskPool *pool)
@@ -517,8 +476,6 @@ void BLI_task_pool_push(TaskPool *pool,
bool free_taskdata,
TaskFreeFunction freedata)
{
- assert_on_valid_thread(pool);
-
Task task(pool, run, taskdata, free_taskdata, freedata);
switch (pool->type) {
@@ -536,8 +493,6 @@ void BLI_task_pool_push(TaskPool *pool,
void BLI_task_pool_work_and_wait(TaskPool *pool)
{
- assert_on_valid_thread(pool);
-
switch (pool->type) {
case TASK_POOL_TBB:
case TASK_POOL_TBB_SUSPENDED:
diff --git a/source/blender/blenlib/intern/task_range.cc b/source/blender/blenlib/intern/task_range.cc
index a27241e91dd..871d04c1f35 100644
--- a/source/blender/blenlib/intern/task_range.cc
+++ b/source/blender/blenlib/intern/task_range.cc
@@ -90,13 +90,11 @@ struct RangeTask {
void operator()(const tbb::blocked_range<int> &r) const
{
- tbb::this_task_arena::isolate([this, r] {
- TaskParallelTLS tls;
- tls.userdata_chunk = userdata_chunk;
- for (int i = r.begin(); i != r.end(); ++i) {
- func(userdata, i, &tls);
- }
- });
+ TaskParallelTLS tls;
+ tls.userdata_chunk = userdata_chunk;
+ for (int i = r.begin(); i != r.end(); ++i) {
+ func(userdata, i, &tls);
+ }
}
void join(const RangeTask &other)
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
index b22334a5676..69117e9dc7e 100644
--- a/source/blender/blenlib/intern/task_scheduler.cc
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -28,6 +28,7 @@
#ifdef WITH_TBB
/* Need to include at least one header to get the version define. */
# include <tbb/blocked_range.h>
+# include <tbb/task_arena.h>
# if TBB_INTERFACE_VERSION_MAJOR >= 10
# include <tbb/global_control.h>
# define WITH_TBB_GLOBAL_CONTROL
@@ -76,3 +77,12 @@ int BLI_task_scheduler_num_threads()
{
return task_scheduler_num_threads;
}
+
+void BLI_task_isolate(void (*func)(void *userdata), void *userdata)
+{
+#ifdef WITH_TBB
+ tbb::this_task_arena::isolate([&] { func(userdata); });
+#else
+ func(userdata);
+#endif
+}
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 3aa61d1fec5..d40f665ba0d 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -67,10 +67,9 @@ static void register_blend_extension_failed(HKEY root, const bool background)
if (!background) {
MessageBox(0, "Could not register file extension.", "Blender error", MB_OK | MB_ICONERROR);
}
- TerminateProcess(GetCurrentProcess(), 1);
}
-void BLI_windows_register_blend_extension(const bool background)
+bool BLI_windows_register_blend_extension(const bool background)
{
LONG lresult;
HKEY hkey = 0;
@@ -107,6 +106,7 @@ void BLI_windows_register_blend_extension(const bool background)
lresult = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Classes", 0, KEY_ALL_ACCESS, &root);
if (lresult != ERROR_SUCCESS) {
register_blend_extension_failed(0, background);
+ return false;
}
}
@@ -119,6 +119,7 @@ void BLI_windows_register_blend_extension(const bool background)
}
if (lresult != ERROR_SUCCESS) {
register_blend_extension_failed(root, background);
+ return false;
}
lresult = RegCreateKeyEx(root,
@@ -137,6 +138,7 @@ void BLI_windows_register_blend_extension(const bool background)
}
if (lresult != ERROR_SUCCESS) {
register_blend_extension_failed(root, background);
+ return false;
}
lresult = RegCreateKeyEx(root,
@@ -155,6 +157,7 @@ void BLI_windows_register_blend_extension(const bool background)
}
if (lresult != ERROR_SUCCESS) {
register_blend_extension_failed(root, background);
+ return false;
}
lresult = RegCreateKeyEx(
@@ -166,6 +169,7 @@ void BLI_windows_register_blend_extension(const bool background)
}
if (lresult != ERROR_SUCCESS) {
register_blend_extension_failed(root, background);
+ return false;
}
BLI_windows_get_executable_dir(InstallDir);
@@ -184,7 +188,7 @@ void BLI_windows_register_blend_extension(const bool background)
"all users");
MessageBox(0, MBox, "Blender", MB_OK | MB_ICONINFORMATION);
}
- TerminateProcess(GetCurrentProcess(), 0);
+ return true;
}
void BLI_windows_get_default_root_dir(char *root)
diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
index d00e8bf55fd..59c4be6d952 100644
--- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
+++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
@@ -17,6 +17,7 @@ extern "C" {
#define DO_CPP_TESTS 1
#define DO_C_TESTS 1
+#define DO_TEXT_TESTS 0
#define DO_RANDOM_TESTS 0
#include "BLI_array.hh"
@@ -267,7 +268,7 @@ template<typename T>
void graph_draw(const std::string &label,
const Array<vec2<T>> &verts,
const Array<std::pair<int, int>> &edges,
- const Array<Vector<int>> &UNUSED(faces))
+ const Array<Vector<int>> &faces)
{
/* Would like to use BKE_tempdir_base() here, but that brings in dependence on kernel library.
* This is just for developer debugging anyway, and should never be called in production Blender.
@@ -281,7 +282,7 @@ void graph_draw(const std::string &label,
constexpr int max_draw_height = 1000;
constexpr int thin_line = 1;
constexpr int vert_radius = 3;
- constexpr bool draw_vert_labels = true;
+ constexpr bool draw_vert_labels = false;
constexpr bool draw_edge_labels = false;
if (verts.size() == 0) {
@@ -339,6 +340,15 @@ void graph_draw(const std::string &label,
"xml:space=\"preserve\"\n"
<< "width=\"" << view_width << "\" height=\"" << view_height << "\">n";
+ for (const Vector<int> &fverts : faces) {
+ f << "<polygon fill=\"azure\" stroke=\"none\"\n points=\"";
+ for (int vi : fverts) {
+ const vec2<T> &co = verts[vi];
+ f << SX(co[0]) << "," << SY(co[1]) << " ";
+ }
+ f << "\"\n />\n";
+ }
+
for (const std::pair<int, int> &e : edges) {
const vec2<T> &uco = verts[e.first];
const vec2<T> &vco = verts[e.second];
@@ -642,6 +652,110 @@ template<typename T> void lineinsquare_test()
if (DO_DRAW) {
graph_draw<T>("LineInSquare - constraints", out2.vert, out2.edge, out2.face);
}
+ CDT_result<T> out3 = delaunay_2d_calc(in, CDT_INSIDE_WITH_HOLES);
+ EXPECT_EQ(out3.vert.size(), 6);
+ EXPECT_EQ(out3.face.size(), 6);
+ if (DO_DRAW) {
+ graph_draw<T>("LineInSquare - inside with holes", out3.vert, out3.edge, out3.face);
+ }
+ CDT_result<T> out4 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES);
+ EXPECT_EQ(out4.vert.size(), 6);
+ EXPECT_EQ(out4.face.size(), 2);
+ if (DO_DRAW) {
+ graph_draw<T>("LineInSquare - valid bmesh with holes", out4.vert, out4.edge, out4.face);
+ }
+}
+
+template<typename T> void lineholeinsquare_test()
+{
+ const char *spec = R"(10 1 2
+ -0.5 -0.5
+ 0.5 -0.5
+ -0.5 0.5
+ 0.5 0.5
+ -0.25 0.0
+ 0.25 0.0
+ -0.4 -0.4
+ 0.4 -0.4
+ 0.4 -0.3
+ -0.4 -0.3
+ 4 5
+ 0 1 3 2
+ 6 7 8 9
+ )";
+
+ CDT_input<T> in = fill_input_from_string<T>(spec);
+ CDT_result<T> out = delaunay_2d_calc(in, CDT_FULL);
+ EXPECT_EQ(out.vert.size(), 10);
+ EXPECT_EQ(out.face.size(), 14);
+ if (DO_DRAW) {
+ graph_draw<T>("LineHoleInSquare - full", out.vert, out.edge, out.face);
+ }
+ CDT_result<T> out2 = delaunay_2d_calc(in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out2.vert.size(), 10);
+ EXPECT_EQ(out2.face.size(), 2);
+ if (DO_DRAW) {
+ graph_draw<T>("LineHoleInSquare - constraints", out2.vert, out2.edge, out2.face);
+ }
+ CDT_result<T> out3 = delaunay_2d_calc(in, CDT_INSIDE_WITH_HOLES);
+ EXPECT_EQ(out3.vert.size(), 10);
+ EXPECT_EQ(out3.face.size(), 12);
+ if (DO_DRAW) {
+ graph_draw<T>("LineHoleInSquare - inside with holes", out3.vert, out3.edge, out3.face);
+ }
+ CDT_result<T> out4 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES);
+ EXPECT_EQ(out4.vert.size(), 10);
+ EXPECT_EQ(out4.face.size(), 2);
+ if (DO_DRAW) {
+ graph_draw<T>("LineHoleInSquare - valid bmesh with holes", out4.vert, out4.edge, out4.face);
+ }
+}
+
+template<typename T> void nestedholes_test()
+{
+ const char *spec = R"(12 0 3
+ -0.5 -0.5
+ 0.5 -0.5
+ -0.5 0.5
+ 0.5 0.5
+ -0.4 -0.4
+ 0.4 -0.4
+ 0.4 0.4
+ -0.4 0.4
+ -0.2 -0.2
+ 0.2 -0.2
+ 0.2 0.2
+ -0.2 0.2
+ 0 1 3 2
+ 4 7 6 5
+ 8 9 10 11
+ )";
+
+ CDT_input<T> in = fill_input_from_string<T>(spec);
+ CDT_result<T> out = delaunay_2d_calc(in, CDT_FULL);
+ EXPECT_EQ(out.vert.size(), 12);
+ EXPECT_EQ(out.face.size(), 18);
+ if (DO_DRAW) {
+ graph_draw<T>("NestedHoles - full", out.vert, out.edge, out.face);
+ }
+ CDT_result<T> out2 = delaunay_2d_calc(in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out2.vert.size(), 12);
+ EXPECT_EQ(out2.face.size(), 3);
+ if (DO_DRAW) {
+ graph_draw<T>("NestedHoles - constraints", out2.vert, out2.edge, out2.face);
+ }
+ CDT_result<T> out3 = delaunay_2d_calc(in, CDT_INSIDE_WITH_HOLES);
+ EXPECT_EQ(out3.vert.size(), 12);
+ EXPECT_EQ(out3.face.size(), 10);
+ if (DO_DRAW) {
+ graph_draw<T>("NestedHoles - inside with holes", out3.vert, out3.edge, out3.face);
+ }
+ CDT_result<T> out4 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES);
+ EXPECT_EQ(out4.vert.size(), 12);
+ EXPECT_EQ(out4.face.size(), 3);
+ if (DO_DRAW) {
+ graph_draw<T>("NestedHoles - valid bmesh with holes", out4.vert, out4.edge, out4.face);
+ }
}
template<typename T> void crosssegs_test()
@@ -1025,16 +1139,28 @@ template<typename T> void overlapfaces_test()
graph_draw<T>("OverlapFaces - inside", out2.vert, out2.edge, out2.face);
}
- CDT_result<T> out3 = delaunay_2d_calc(in, CDT_CONSTRAINTS);
- EXPECT_EQ(out3.face.size(), 4);
+ CDT_result<T> out3 = delaunay_2d_calc(in, CDT_INSIDE_WITH_HOLES);
+ EXPECT_EQ(out3.face.size(), 14);
+ if (DO_DRAW) {
+ graph_draw<T>("OverlapFaces - inside with holes", out3.vert, out3.edge, out3.face);
+ }
+
+ CDT_result<T> out4 = delaunay_2d_calc(in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out4.face.size(), 4);
if (DO_DRAW) {
- graph_draw<T>("OverlapFaces - constraints", out3.vert, out3.edge, out3.face);
+ graph_draw<T>("OverlapFaces - constraints", out4.vert, out4.edge, out4.face);
}
- CDT_result<T> out4 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH);
- EXPECT_EQ(out4.face.size(), 5);
+ CDT_result<T> out5 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH);
+ EXPECT_EQ(out5.face.size(), 5);
if (DO_DRAW) {
- graph_draw<T>("OverlapFaces - valid bmesh", out4.vert, out4.edge, out4.face);
+ graph_draw<T>("OverlapFaces - valid bmesh", out5.vert, out5.edge, out5.face);
+ }
+
+ CDT_result<T> out6 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES);
+ EXPECT_EQ(out6.face.size(), 3);
+ if (DO_DRAW) {
+ graph_draw<T>("OverlapFaces - valid bmesh with holes", out6.vert, out6.edge, out6.face);
}
}
@@ -1246,6 +1372,34 @@ template<typename T> void repeattri_test()
}
}
+template<typename T> void square_o_test()
+{
+ const char *spec = R"(8 0 2
+ 0.0 0.0
+ 1.0 0.0
+ 1.0 1.0
+ 0.0 1.0
+ 0.2 0.2
+ 0.2 0.8
+ 0.8 0.8
+ 0.8 0.2
+ 0 1 2 3
+ 4 5 6 7
+ )";
+ CDT_input<T> in = fill_input_from_string<T>(spec);
+ CDT_result<T> out1 = delaunay_2d_calc(in, CDT_INSIDE_WITH_HOLES);
+ EXPECT_EQ(out1.face.size(), 8);
+ if (DO_DRAW) {
+ graph_draw<T>("Square O - inside with holes", out1.vert, out1.edge, out1.face);
+ }
+
+ CDT_result<T> out2 = delaunay_2d_calc(in, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES);
+ EXPECT_EQ(out2.face.size(), 2);
+ if (DO_DRAW) {
+ graph_draw<T>("Square O - valid bmesh with holes", out2.vert, out2.edge, out2.face);
+ }
+}
+
TEST(delaunay_d, Empty)
{
empty_test<double>();
@@ -1301,6 +1455,16 @@ TEST(delaunay_d, LineInSquare)
lineinsquare_test<double>();
}
+TEST(delaunay_d, LineHoleInSquare)
+{
+ lineholeinsquare_test<double>();
+}
+
+TEST(delaunay_d, NestedHoles)
+{
+ nestedholes_test<double>();
+}
+
TEST(delaunay_d, CrossSegs)
{
crosssegs_test<double>();
@@ -1371,6 +1535,11 @@ TEST(delaunay_d, RepeatTri)
repeattri_test<double>();
}
+TEST(delaunay_d, SquareO)
+{
+ square_o_test<double>();
+}
+
# ifdef WITH_GMP
TEST(delaunay_m, Empty)
{
@@ -1426,6 +1595,16 @@ TEST(delaunay_m, LineInSquare)
lineinsquare_test<mpq_class>();
}
+TEST(delaunay_m, LineHoleInSquare)
+{
+ lineholeinsquare_test<mpq_class>();
+}
+
+TEST(delaunay_m, NestedHoles)
+{
+ nestedholes_test<mpq_class>();
+}
+
TEST(delaunay_m, CrossSegs)
{
crosssegs_test<mpq_class>();
@@ -1496,7 +1675,6 @@ TEST(delaunay_m, RepeatTri)
repeattri_test<mpq_class>();
}
# endif
-
#endif
#if DO_C_TESTS
@@ -1524,6 +1702,182 @@ TEST(delaunay_d, CintTwoFace)
}
#endif
+#if DO_TEXT_TESTS
+template<typename T>
+void text_test(int num_arc_points, int num_lets_per_line, int num_lines, CDT_output_type otype)
+{
+ constexpr bool print_timing = true;
+ /*
+ * Make something like a letter B:
+ *
+ * 4------------3
+ * | )
+ * | 12--11 )
+ * | | ) a3 ) a1
+ * | 9---10 )
+ * | )
+ * | 2
+ * | )
+ * | 8----7 )
+ * | | ) a2 ) a0
+ * | 5----6 )
+ * | )
+ * 0------------1
+ *
+ * Where the numbers are the first 13 vertices, and the rest of
+ * the vertices are in arcs a0, a1, a2, a3, each of which have
+ * num_arc_points per arc in them.
+ */
+
+ const char *b_before_arcs = R"(13 0 3
+ 0.0 0.0
+ 1.0 0.0
+ 1.0 1.5
+ 1.0 3.0
+ 0.0 3.0
+ 0.2 0.2
+ 0.6 0.2
+ 0.6 1.4
+ 0.2 1.4
+ 0.2 1.6
+ 0.6 1.6
+ 0.6 2.8
+ 0.2 2.8
+ 3 4 0 1 2
+ 6 5 8 7
+ 10 9 12 11
+ )";
+
+ CDT_input<T> b_before_arcs_in = fill_input_from_string<T>(b_before_arcs);
+ constexpr int narcs = 4;
+ int b_npts = b_before_arcs_in.vert.size() + narcs * num_arc_points;
+ constexpr int b_nfaces = 3;
+ Array<vec2<T>> b_vert(b_npts);
+ Array<Vector<int>> b_face(b_nfaces);
+ std::copy(b_before_arcs_in.vert.begin(), b_before_arcs_in.vert.end(), b_vert.begin());
+ std::copy(b_before_arcs_in.face.begin(), b_before_arcs_in.face.end(), b_face.begin());
+ if (num_arc_points > 0) {
+ b_face[0].pop_last(); // We'll add center point back between arcs for outer face.
+ for (int arc = 0; arc < narcs; ++arc) {
+ int arc_origin_vert;
+ int arc_terminal_vert;
+ bool ccw;
+ switch (arc) {
+ case 0:
+ arc_origin_vert = 1;
+ arc_terminal_vert = 2;
+ ccw = true;
+ break;
+ case 1:
+ arc_origin_vert = 2;
+ arc_terminal_vert = 3;
+ ccw = true;
+ break;
+ case 2:
+ arc_origin_vert = 7;
+ arc_terminal_vert = 6;
+ ccw = false;
+ break;
+ case 3:
+ arc_origin_vert = 11;
+ arc_terminal_vert = 10;
+ ccw = false;
+ break;
+ default:
+ BLI_assert(false);
+ }
+ vec2<T> start_co = b_vert[arc_origin_vert];
+ vec2<T> end_co = b_vert[arc_terminal_vert];
+ vec2<T> center_co = 0.5 * (start_co + end_co);
+ BLI_assert(start_co[0] == end_co[2]);
+ double radius = abs(math_to_double<T>(end_co[1] - center_co[1]));
+ double angle_delta = M_PI / (num_arc_points + 1);
+ int start_vert = b_before_arcs_in.vert.size() + arc * num_arc_points;
+ Vector<int> &face = b_face[(arc <= 1) ? 0 : arc - 1];
+ for (int i = 0; i < num_arc_points; ++i) {
+ vec2<T> delta;
+ float ang = ccw ? (-M_PI_2 + (i + 1) * angle_delta) : (M_PI_2 - (i + 1) * angle_delta);
+ delta[0] = T(radius * cos(ang));
+ delta[1] = T(radius * sin(ang));
+ b_vert[start_vert + i] = center_co + delta;
+ face.append(start_vert + i);
+ }
+ if (arc == 0) {
+ face.append(arc_terminal_vert);
+ }
+ }
+ }
+
+ CDT_input<T> in;
+ int tot_instances = num_lets_per_line * num_lines;
+ if (tot_instances == 1) {
+ in.vert = b_vert;
+ in.face = b_face;
+ }
+ else {
+ in.vert = Array<vec2<T>>(tot_instances * b_vert.size());
+ in.face = Array<Vector<int>>(tot_instances * b_face.size());
+ T cur_x = T(0);
+ T cur_y = T(0);
+ T delta_x = T(2);
+ T delta_y = T(3.25);
+ int instance = 0;
+ for (int line = 0; line < num_lines; ++line) {
+ for (int let = 0; let < num_lets_per_line; ++let) {
+ vec2<T> co_offset(cur_x, cur_y);
+ int in_v_offset = instance * b_vert.size();
+ for (int v = 0; v < b_vert.size(); ++v) {
+ in.vert[in_v_offset + v] = b_vert[v] + co_offset;
+ }
+ int in_f_offset = instance * b_face.size();
+ for (int f : b_face.index_range()) {
+ for (int fv : b_face[f]) {
+ in.face[in_f_offset + f].append(in_v_offset + fv);
+ }
+ }
+ cur_x += delta_x;
+ ++instance;
+ }
+ cur_y += delta_y;
+ cur_x = T(0);
+ }
+ }
+ in.epsilon = b_before_arcs_in.epsilon;
+ double tstart = PIL_check_seconds_timer();
+ CDT_result<T> out = delaunay_2d_calc(in, otype);
+ double tend = PIL_check_seconds_timer();
+ if (print_timing) {
+ std::cout << "time = " << tend - tstart << "\n";
+ }
+ if (DO_DRAW) {
+ std::string label = "Text arcpts=" + std::to_string(num_arc_points);
+ if (num_lets_per_line > 1) {
+ label += " linelen=" + std::to_string(num_lets_per_line);
+ }
+ if (num_lines > 1) {
+ label += " lines=" + std::to_string(num_lines);
+ }
+ graph_draw<T>(label, out.vert, out.edge, out.face);
+ }
+}
+
+TEST(delaunay_d, TextB10)
+{
+ text_test<double>(10, 1, 1, CDT_INSIDE_WITH_HOLES);
+}
+
+TEST(delaunay_d, TextB200)
+{
+ text_test<double>(200, 1, 1, CDT_INSIDE_WITH_HOLES);
+}
+
+TEST(delaunay_d, TextB10_10_10)
+{
+ text_test<double>(10, 10, 10, CDT_INSIDE_WITH_HOLES);
+}
+
+#endif
+
#if DO_RANDOM_TESTS
enum {
diff --git a/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc b/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc
index 8be89d66062..e9810aed179 100644
--- a/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc
+++ b/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc
@@ -81,7 +81,7 @@ TEST(LockfreeLinkList, InsertMultipleConcurrent)
LockfreeLinkList list;
BLI_linklist_lockfree_init(&list);
/* Initialize task scheduler and pool. */
- TaskPool *pool = BLI_task_pool_create_suspended(&list, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ TaskPool *pool = BLI_task_pool_create_suspended(&list, TASK_PRIORITY_HIGH);
/* Push tasks to the pool. */
for (int i = 0; i < num_nodes; ++i) {
BLI_task_pool_push(pool, concurrent_insert, POINTER_FROM_INT(i), false, nullptr);
diff --git a/source/blender/blenlib/tests/BLI_math_time_test.cc b/source/blender/blenlib/tests/BLI_math_time_test.cc
new file mode 100644
index 00000000000..61a504ac2d7
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_math_time_test.cc
@@ -0,0 +1,35 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_math.h"
+
+TEST(math_time, SecondsExplode)
+{
+ const double seconds = 2.0 * SECONDS_IN_DAY + 13.0 * SECONDS_IN_HOUR + 33.0 * SECONDS_IN_MINUTE +
+ 9.0 + 369.0 * SECONDS_IN_MILLISECONDS;
+ const double epsilon = 1e-8;
+
+ double r_days, r_hours, r_minutes, r_seconds, r_milliseconds;
+
+ BLI_math_time_seconds_decompose(
+ seconds, &r_days, &r_hours, &r_minutes, &r_seconds, &r_milliseconds);
+ EXPECT_NEAR(2.0, r_days, epsilon);
+ EXPECT_NEAR(13.0, r_hours, epsilon);
+ EXPECT_NEAR(33.0, r_minutes, epsilon);
+ EXPECT_NEAR(9.0, r_seconds, epsilon);
+ EXPECT_NEAR(369.0, r_milliseconds, epsilon);
+
+ BLI_math_time_seconds_decompose(seconds, nullptr, &r_hours, &r_minutes, &r_seconds, nullptr);
+ EXPECT_NEAR(61.0, r_hours, epsilon);
+ EXPECT_NEAR(33.0, r_minutes, epsilon);
+ EXPECT_NEAR(9.369, r_seconds, epsilon);
+
+ BLI_math_time_seconds_decompose(seconds, nullptr, nullptr, nullptr, &r_seconds, nullptr);
+ EXPECT_NEAR(seconds, r_seconds, epsilon);
+
+ BLI_math_time_seconds_decompose(seconds, &r_days, nullptr, &r_minutes, nullptr, &r_milliseconds);
+ EXPECT_NEAR(2.0, r_days, epsilon);
+ EXPECT_NEAR(813.0, r_minutes, epsilon);
+ EXPECT_NEAR(9369.0, r_milliseconds, epsilon);
+}
diff --git a/source/blender/blenlib/tests/BLI_stack_test.cc b/source/blender/blenlib/tests/BLI_stack_test.cc
index 1fef5998b99..a2650e5509d 100644
--- a/source/blender/blenlib/tests/BLI_stack_test.cc
+++ b/source/blender/blenlib/tests/BLI_stack_test.cc
@@ -137,7 +137,7 @@ TEST(stack, Clear)
BLI_stack_clear(stack);
EXPECT_TRUE(BLI_stack_is_empty(stack));
- /* and again, this time check its valid */
+ /* and again, this time check it is valid */
for (in = 0; in < tot; in++) {
BLI_stack_push(stack, (void *)&in);
}
@@ -150,7 +150,7 @@ TEST(stack, Clear)
EXPECT_TRUE(BLI_stack_is_empty(stack));
- /* without this, we wont test case when mixed free/used */
+ /* without this, we won't test case when mixed free/used */
tot /= 2;
}
diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc
index 88cecaa5fee..0b68ee8b93c 100644
--- a/source/blender/blenlib/tests/BLI_string_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_test.cc
@@ -421,9 +421,7 @@ TEST(string, StrFormatByteUnits)
}
struct WordInfo {
- WordInfo()
- {
- }
+ WordInfo() = default;
WordInfo(int start, int end) : start(start), end(end)
{
}
@@ -441,9 +439,7 @@ static std::ostream &operator<<(std::ostream &os, const WordInfo &word_info)
class StringFindSplitWords : public testing::Test {
protected:
- StringFindSplitWords()
- {
- }
+ StringFindSplitWords() = default;
/* If max_words is -1 it will be initialized from the number of expected
* words +1. This way there is no need to pass an explicit number of words,
@@ -807,9 +803,7 @@ TEST_F(StringCasecmpNatural, TextAndNumbers)
class StringEscape : public testing::Test {
protected:
- StringEscape()
- {
- }
+ StringEscape() = default;
using CompareWordsArray = vector<std::array<const char *, 2>>;
@@ -832,6 +826,9 @@ class StringEscape : public testing::Test {
TEST_F(StringEscape, Simple)
{
+ /* NOTE: clang-tidy `modernize-raw-string-literal` is disabled as it causes errors with MSVC.
+ * TODO: investigate resolving with `/Zc:preprocessor` flag. */
+
const CompareWordsArray equal{
{"", ""},
{"/", "/"},
@@ -845,11 +842,16 @@ TEST_F(StringEscape, Simple)
{"\\A", "\\\\A"},
{"A\\B", "A\\\\B"},
{"?", "?"},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\"\\", "\\\"\\\\"},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\\\"", "\\\\\\\""},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\"\\\"", "\\\"\\\\\\\""},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\"\"\"", "\\\"\\\"\\\""},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\\\\\\", "\\\\\\\\\\\\"},
};
@@ -868,8 +870,11 @@ TEST_F(StringEscape, Control)
{"\f", "\\f"},
{"A\n", "A\\n"},
{"\nA", "\\nA"},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\n\r\t\a\b\f", "\\n\\r\\t\\a\\b\\f"},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\n_\r_\t_\a_\b_\f", "\\n_\\r_\\t_\\a_\\b_\\f"},
+ /* NOLINTNEXTLINE: modernize-raw-string-literal. */
{"\n\\\r\\\t\\\a\\\b\\\f", "\\n\\\\\\r\\\\\\t\\\\\\a\\\\\\b\\\\\\f"},
};
diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc
index 52603428031..dd4441517a9 100644
--- a/source/blender/blenlib/tests/BLI_task_test.cc
+++ b/source/blender/blenlib/tests/BLI_task_test.cc
@@ -141,9 +141,9 @@ TEST(task, MempoolIter)
/* *** Parallel iterations over mempool items with TLS. *** */
-typedef struct TaskMemPool_Chunk {
+using TaskMemPool_Chunk = struct TaskMemPool_Chunk {
ListBase *accumulate_items;
-} TaskMemPool_Chunk;
+};
static void task_mempool_iter_tls_func(void *UNUSED(userdata),
MempoolIterData *item,
@@ -206,7 +206,7 @@ TEST(task, MempoolIterTLS)
BLI_parallel_mempool_settings_defaults(&settings);
TaskMemPool_Chunk tls_data;
- tls_data.accumulate_items = NULL;
+ tls_data.accumulate_items = nullptr;
settings.userdata_chunk = &tls_data;
settings.userdata_chunk_size = sizeof(tls_data);
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
index ea0532d884b..86c7c367816 100644
--- a/source/blender/blenloader/BLO_read_write.h
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -54,6 +54,7 @@ typedef struct BlendExpander BlendExpander;
typedef struct BlendLibReader BlendLibReader;
typedef struct BlendWriter BlendWriter;
+struct BlendFileReadReport;
struct Main;
struct ReportList;
@@ -216,7 +217,7 @@ bool BLO_read_requires_endian_switch(BlendDataReader *reader);
bool BLO_read_data_is_undo(BlendDataReader *reader);
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr);
void BLO_read_glob_list(BlendDataReader *reader, struct ListBase *list);
-struct ReportList *BLO_read_data_reports(BlendDataReader *reader);
+struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader);
/* Blend Read Lib API
* ===================
@@ -233,7 +234,7 @@ ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, str
/* Misc. */
bool BLO_read_lib_is_undo(BlendLibReader *reader);
struct Main *BLO_read_lib_get_main(BlendLibReader *reader);
-struct ReportList *BLO_read_lib_reports(BlendLibReader *reader);
+struct BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader);
/* Blend Expand API
* ===================
@@ -250,8 +251,10 @@ void BLO_expand_id(BlendExpander *expander, struct ID *id);
* ===================
*/
-void BLO_reportf_wrap(struct ReportList *reports, ReportType type, const char *format, ...)
- ATTR_PRINTF_FORMAT(3, 4);
+void BLO_reportf_wrap(struct BlendFileReadReport *reports,
+ ReportType type,
+ const char *format,
+ ...) ATTR_PRINTF_FORMAT(3, 4);
#ifdef __cplusplus
}
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 89db216aada..307c09f8ff5 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -89,6 +89,35 @@ struct BlendFileReadParams {
int undo_direction; /* eUndoStepDir */
};
+typedef struct BlendFileReadReport {
+ /* General reports handling. */
+ struct ReportList *reports;
+
+ /* Timing informations .*/
+ struct {
+ double whole;
+ double libraries;
+ double lib_overrides;
+ double lib_overrides_resync;
+ double lib_overrides_recursive_resync;
+ } duration;
+
+ /* Count informations. */
+ struct {
+ /* Some numbers of IDs that ended up in a specific state, or required some specific process
+ * during this file read. */
+ int missing_libraries;
+ int missing_linked_id;
+ /* Number of root override IDs that were resynced. */
+ int resynced_lib_overrides;
+ } count;
+
+ /* Number of libraries which had overrides that needed to be resynced, and a single linked list
+ * of those. */
+ int resynced_lib_overrides_libraries_count;
+ struct LinkNode *resynced_lib_overrides_libraries;
+} BlendFileReadReport;
+
/* skip reading some data-block types (may want to skip screen data too). */
typedef enum eBLOReadSkip {
BLO_READ_SKIP_NONE = 0,
@@ -101,7 +130,7 @@ typedef enum eBLOReadSkip {
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
- struct ReportList *reports);
+ struct BlendFileReadReport *reports);
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
@@ -125,7 +154,7 @@ struct BLODataBlockInfo {
struct AssetMetaData *asset_data;
};
-BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports);
+BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct BlendFileReadReport *reports);
BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize);
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 36802fc8842..61a00ccdaa4 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
intern/versioning_290.c
intern/versioning_300.c
intern/versioning_cycles.c
+ intern/versioning_common.cc
intern/versioning_defaults.c
intern/versioning_dna.c
intern/versioning_legacy.c
@@ -72,6 +73,7 @@ set(SRC
BLO_undofile.h
BLO_writefile.h
intern/readfile.h
+ intern/versioning_common.h
)
set(LIB
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
index f3fc1453461..0f729304128 100644
--- a/source/blender/blenloader/intern/blend_validate.c
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -83,7 +83,8 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
}
BKE_library_filepath_set(bmain, curlib, curlib->filepath);
- BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath_abs, reports);
+ BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath_abs,
+ &(BlendFileReadReport){.reports = reports});
if (bh == NULL) {
BKE_reportf(reports,
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 19033ba9bf1..1a324d56f06 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -68,7 +68,7 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp);
* \param reports: Report errors in opening the file (can be NULL).
* \return A handle on success, or NULL on failure.
*/
-BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports)
+BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
{
BlendHandle *bh;
@@ -88,7 +88,8 @@ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize)
{
BlendHandle *bh;
- bh = (BlendHandle *)blo_filedata_from_memory(mem, memsize, NULL);
+ bh = (BlendHandle *)blo_filedata_from_memory(
+ mem, memsize, &(BlendFileReadReport){.reports = NULL});
return bh;
}
@@ -366,14 +367,13 @@ void BLO_blendhandle_close(BlendHandle *bh)
*/
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
BlendFileData *bfd = NULL;
FileData *fd;
fd = blo_filedata_from_file(filepath, reports);
if (fd) {
- fd->reports = reports;
fd->skip_flags = skip_flags;
bfd = blo_read_file_internal(fd, filepath);
blo_filedata_free(fd);
@@ -399,9 +399,8 @@ BlendFileData *BLO_read_from_memory(const void *mem,
BlendFileData *bfd = NULL;
FileData *fd;
- fd = blo_filedata_from_memory(mem, memsize, reports);
+ fd = blo_filedata_from_memory(mem, memsize, &(BlendFileReadReport){.reports = reports});
if (fd) {
- fd->reports = reports;
fd->skip_flags = skip_flags;
bfd = blo_read_file_internal(fd, "");
blo_filedata_free(fd);
@@ -428,9 +427,8 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
FileData *fd;
ListBase old_mainlist;
- fd = blo_filedata_from_memfile(memfile, params, reports);
+ fd = blo_filedata_from_memfile(memfile, params, &(BlendFileReadReport){.reports = reports});
if (fd) {
- fd->reports = reports;
fd->skip_flags = params->skip_flags;
BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase));
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 47ed4e5c06f..dce5b5ebf87 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -40,6 +40,8 @@
# include <io.h> /* for open close read */
#endif
+#include "CLG_log.h"
+
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
@@ -72,6 +74,8 @@
#include "BLI_mmap.h"
#include "BLI_threads.h"
+#include "PIL_time.h"
+
#include "BLT_translation.h"
#include "BKE_anim_data.h"
@@ -186,14 +190,8 @@
/* Use GHash for restoring pointers by name */
#define USE_GHASH_RESTORE_POINTER
-/* Define this to have verbose debug prints. */
-//#define USE_DEBUG_PRINT
-
-#ifdef USE_DEBUG_PRINT
-# define DEBUG_PRINTF(...) printf(__VA_ARGS__)
-#else
-# define DEBUG_PRINTF(...)
-#endif
+static CLG_LogRef LOG = {"blo.readfile"};
+static CLG_LogRef LOG_UNDO = {"blo.readfile.undo"};
/* local prototypes */
static void read_libraries(FileData *basefd, ListBase *mainlist);
@@ -227,7 +225,7 @@ typedef struct BHeadN {
* bit kludge but better than doubling up on prints,
* we could alternatively have a versions of a report function which forces printing - campbell
*/
-void BLO_reportf_wrap(ReportList *reports, ReportType type, const char *format, ...)
+void BLO_reportf_wrap(BlendFileReadReport *reports, ReportType type, const char *format, ...)
{
char fixed_buf[1024]; /* should be long enough */
@@ -239,7 +237,7 @@ void BLO_reportf_wrap(ReportList *reports, ReportType type, const char *format,
fixed_buf[sizeof(fixed_buf) - 1] = '\0';
- BKE_report(reports, type, fixed_buf);
+ BKE_report(reports->reports, type, fixed_buf);
if (G.background == 0) {
printf("%s: %s\n", BKE_report_type_str(type), fixed_buf);
@@ -488,7 +486,7 @@ static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint li
BLI_addtail(lb_dst, id);
}
else {
- printf("%s: invalid library for '%s'\n", __func__, id->name);
+ CLOG_ERROR(&LOG, "Invalid library for '%s'", id->name);
BLI_assert(0);
}
}
@@ -635,7 +633,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
if (BLI_path_cmp(name1, libname) == 0) {
if (G.debug & G_DEBUG) {
- printf("blo_find_main: found library %s\n", libname);
+ CLOG_INFO(&LOG, 3, "Found library %s", libname);
}
return m;
}
@@ -662,7 +660,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
read_file_version(fd, m);
if (G.debug & G_DEBUG) {
- printf("blo_find_main: added new lib %s\n", filepath);
+ CLOG_INFO(&LOG, 3, "Added new lib %s", filepath);
}
return m;
}
@@ -1296,7 +1294,7 @@ static ssize_t fd_read_from_memfile(FileData *filedata,
/* debug, should never happen */
if (chunk == NULL) {
- printf("illegal read, chunk zero\n");
+ CLOG_ERROR(&LOG, "Illegal read, got a NULL chunk");
return 0;
}
@@ -1331,8 +1329,10 @@ static ssize_t fd_read_from_memfile(FileData *filedata,
return 0;
}
-static FileData *filedata_new(void)
+static FileData *filedata_new(BlendFileReadReport *reports)
{
+ BLI_assert(reports != NULL);
+
FileData *fd = MEM_callocN(sizeof(FileData), "FileData");
fd->filedes = -1;
@@ -1344,6 +1344,8 @@ static FileData *filedata_new(void)
fd->globmap = oldnewmap_new();
fd->libmap = oldnewmap_new();
+ fd->reports = reports;
+
return fd;
}
@@ -1371,7 +1373,7 @@ static FileData *blo_decode_and_check(FileData *fd, ReportList *reports)
}
static FileData *blo_filedata_from_file_descriptor(const char *filepath,
- ReportList *reports,
+ BlendFileReadReport *reports,
int file)
{
FileDataReadFn *read_fn = NULL;
@@ -1386,7 +1388,7 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
/* Regular file. */
errno = 0;
if (read(file, header, sizeof(header)) != sizeof(header)) {
- BKE_reportf(reports,
+ BKE_reportf(reports->reports,
RPT_WARNING,
"Unable to read '%s': %s",
filepath,
@@ -1416,7 +1418,7 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
(header[0] == 0x1f && header[1] == 0x8b)) {
gzfile = BLI_gzopen(filepath, "rb");
if (gzfile == (gzFile)Z_NULL) {
- BKE_reportf(reports,
+ BKE_reportf(reports->reports,
RPT_WARNING,
"Unable to open '%s': %s",
filepath,
@@ -1431,11 +1433,11 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
}
if (read_fn == NULL) {
- BKE_reportf(reports, RPT_WARNING, "Unrecognized file format '%s'", filepath);
+ BKE_reportf(reports->reports, RPT_WARNING, "Unrecognized file format '%s'", filepath);
return NULL;
}
- FileData *fd = filedata_new();
+ FileData *fd = filedata_new(reports);
fd->filedes = file;
fd->gzfiledes = gzfile;
@@ -1448,12 +1450,12 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
return fd;
}
-static FileData *blo_filedata_from_file_open(const char *filepath, ReportList *reports)
+static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileReadReport *reports)
{
errno = 0;
const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- BKE_reportf(reports,
+ BKE_reportf(reports->reports,
RPT_WARNING,
"Unable to open '%s': %s",
filepath,
@@ -1469,14 +1471,14 @@ static FileData *blo_filedata_from_file_open(const char *filepath, ReportList *r
/* cannot be called with relative paths anymore! */
/* on each new library added, it now checks for the current FileData and expands relativeness */
-FileData *blo_filedata_from_file(const char *filepath, ReportList *reports)
+FileData *blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
{
FileData *fd = blo_filedata_from_file_open(filepath, reports);
if (fd != NULL) {
/* needed for library_append and read_libraries */
BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase));
- return blo_decode_and_check(fd, reports);
+ return blo_decode_and_check(fd, reports->reports);
}
return NULL;
}
@@ -1487,7 +1489,7 @@ FileData *blo_filedata_from_file(const char *filepath, ReportList *reports)
*/
static FileData *blo_filedata_from_file_minimal(const char *filepath)
{
- FileData *fd = blo_filedata_from_file_open(filepath, NULL);
+ FileData *fd = blo_filedata_from_file_open(filepath, &(BlendFileReadReport){.reports = NULL});
if (fd != NULL) {
decode_blender_header(fd);
if (fd->flags & FD_FLAGS_FILE_OK) {
@@ -1515,7 +1517,7 @@ static ssize_t fd_read_gzip_from_memory(FileData *filedata,
return 0;
}
if (err != Z_OK) {
- printf("fd_read_gzip_from_memory: zlib error\n");
+ CLOG_ERROR(&LOG, "ZLib error (code %d)", err);
return 0;
}
@@ -1542,14 +1544,15 @@ static int fd_read_gzip_from_memory_init(FileData *fd)
return 1;
}
-FileData *blo_filedata_from_memory(const void *mem, int memsize, ReportList *reports)
+FileData *blo_filedata_from_memory(const void *mem, int memsize, BlendFileReadReport *reports)
{
if (!mem || memsize < SIZEOFBLENDERHEADER) {
- BKE_report(reports, RPT_WARNING, (mem) ? TIP_("Unable to read") : TIP_("Unable to open"));
+ BKE_report(
+ reports->reports, RPT_WARNING, (mem) ? TIP_("Unable to read") : TIP_("Unable to open"));
return NULL;
}
- FileData *fd = filedata_new();
+ FileData *fd = filedata_new(reports);
const char *cp = mem;
fd->buffer = mem;
@@ -1568,26 +1571,26 @@ FileData *blo_filedata_from_memory(const void *mem, int memsize, ReportList *rep
fd->flags |= FD_FLAGS_NOT_MY_BUFFER;
- return blo_decode_and_check(fd, reports);
+ return blo_decode_and_check(fd, reports->reports);
}
FileData *blo_filedata_from_memfile(MemFile *memfile,
const struct BlendFileReadParams *params,
- ReportList *reports)
+ BlendFileReadReport *reports)
{
if (!memfile) {
- BKE_report(reports, RPT_WARNING, "Unable to open blend <memory>");
+ BKE_report(reports->reports, RPT_WARNING, "Unable to open blend <memory>");
return NULL;
}
- FileData *fd = filedata_new();
+ FileData *fd = filedata_new(reports);
fd->memfile = memfile;
fd->undo_direction = params->undo_direction;
fd->read = fd_read_from_memfile;
fd->flags |= FD_FLAGS_NOT_MY_BUFFER;
- return blo_decode_and_check(fd, reports);
+ return blo_decode_and_check(fd, reports->reports);
}
void blo_filedata_free(FileData *fd)
@@ -1602,8 +1605,9 @@ void blo_filedata_free(FileData *fd)
}
if (fd->strm.next_in) {
- if (inflateEnd(&fd->strm) != Z_OK) {
- printf("close gzip stream error\n");
+ int err = inflateEnd(&fd->strm);
+ if (err != Z_OK) {
+ CLOG_ERROR(&LOG, "Close gzip stream error (code %d)", err);
}
}
@@ -2586,7 +2590,7 @@ static void lib_link_scenes_check_set(Main *bmain)
if (sce->flag & SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK) {
sce->flag &= ~SCE_READFILE_LIBLINK_NEED_SETSCENE_CHECK;
if (!scene_validate_setscene__liblink(sce, totscene)) {
- printf("Found cyclic background scene when linking %s\n", sce->id.name + 2);
+ CLOG_WARN(&LOG, "Found cyclic background scene when linking %s", sce->id.name + 2);
}
}
}
@@ -3420,15 +3424,17 @@ static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const I
* That means we have to carefully check whether current lib or
* libdata already exits in old main, if it does we merely copy it over into new main area,
* otherwise we have to do a full read of that bhead... */
- DEBUG_PRINTF("UNDO: restore library %s\n", id->name);
+ CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore library %s", id->name);
Main *libmain = fd->old_mainlist->first;
/* Skip oldmain itself... */
for (libmain = libmain->next; libmain; libmain = libmain->next) {
- DEBUG_PRINTF(" compare with %s -> ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) {
Main *oldmain = fd->old_mainlist->first;
- DEBUG_PRINTF("match!\n");
+ CLOG_INFO(&LOG_UNDO,
+ 2,
+ " compare with %s -> match",
+ libmain->curlib ? libmain->curlib->id.name : "<NULL>");
/* In case of a library, we need to re-add its main to fd->mainlist,
* because if we have later a missing ID_LINK_PLACEHOLDER,
* we need to get the correct lib it is linked to!
@@ -3440,7 +3446,10 @@ static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const I
BLI_addtail(&main->libraries, libmain->curlib);
return true;
}
- DEBUG_PRINTF("no match\n");
+ CLOG_INFO(&LOG_UNDO,
+ 2,
+ " compare with %s -> NO match",
+ libmain->curlib ? libmain->curlib->id.name : "<NULL>");
}
return false;
@@ -3449,14 +3458,15 @@ static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const I
/* For undo, restore existing linked datablock from the old main. */
static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead)
{
- DEBUG_PRINTF("UNDO: restore linked datablock %s\n", id->name);
- DEBUG_PRINTF(" from %s (%s): ",
- main->curlib ? main->curlib->id.name : "<NULL>",
- main->curlib ? main->curlib->filepath : "<NULL>");
+ CLOG_INFO(&LOG_UNDO, 2, "UNDO: restore linked datablock %s", id->name);
ID *id_old = BKE_libblock_find_name(main, GS(id->name), id->name + 2);
if (id_old != NULL) {
- DEBUG_PRINTF(" found!\n");
+ CLOG_INFO(&LOG_UNDO,
+ 2,
+ " from %s (%s): found",
+ main->curlib ? main->curlib->id.name : "<NULL>",
+ main->curlib ? main->curlib->filepath : "<NULL>");
/* Even though we found our linked ID, there is no guarantee its address
* is still the same. */
if (id_old != bhead->old) {
@@ -3468,7 +3478,11 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID
return true;
}
- DEBUG_PRINTF(" not found\n");
+ CLOG_INFO(&LOG_UNDO,
+ 2,
+ " from %s (%s): NOT found",
+ main->curlib ? main->curlib->id.name : "<NULL>",
+ main->curlib ? main->curlib->filepath : "<NULL>");
return false;
}
@@ -3577,8 +3591,6 @@ static bool read_libblock_undo_restore(
}
/* Restore local datablocks. */
- DEBUG_PRINTF("UNDO: read %s (uuid %u) -> ", id->name, id->session_uuid);
-
ID *id_old = NULL;
const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) {
@@ -3593,7 +3605,11 @@ static bool read_libblock_undo_restore(
if (id_old != NULL && read_libblock_is_identical(fd, bhead)) {
/* Local datablock was unchanged, restore from the old main. */
- DEBUG_PRINTF("keep identical datablock\n");
+ CLOG_INFO(&LOG_UNDO,
+ 2,
+ "UNDO: read %s (uuid %u) -> keep identical datablock",
+ id->name,
+ id->session_uuid);
/* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as
* this is only for do_version-like code), but for sake of consistency, and also because
@@ -3613,13 +3629,18 @@ static bool read_libblock_undo_restore(
}
if (id_old != NULL) {
/* Local datablock was changed. Restore at the address of the old datablock. */
- DEBUG_PRINTF("read to old existing address\n");
+ CLOG_INFO(&LOG_UNDO,
+ 2,
+ "UNDO: read %s (uuid %u) -> read to old existing address",
+ id->name,
+ id->session_uuid);
*r_id_old = id_old;
return false;
}
/* Local datablock does not exist in the undo step, so read from scratch. */
- DEBUG_PRINTF("read at new address\n");
+ CLOG_INFO(
+ &LOG_UNDO, 2, "UNDO: read %s (uuid %u) -> read at new address", id->name, id->session_uuid);
return false;
}
@@ -3664,7 +3685,7 @@ static BHead *read_libblock(FileData *fd,
ListBase *lb = which_libbase(main, idcode);
if (lb == NULL) {
/* Unknown ID type. */
- printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
+ CLOG_WARN(&LOG, "Unknown id code '%c%c'", (idcode & 0xff), (idcode >> 8));
MEM_freeN(id);
if (r_id) {
*r_id = NULL;
@@ -3856,12 +3877,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
BLI_strncpy(build_commit_datetime, "unknown", sizeof(build_commit_datetime));
}
- printf("read file %s\n Version %d sub %d date %s hash %s\n",
- fd->relabase,
- main->versionfile,
- main->subversionfile,
- build_commit_datetime,
- main->build_hash);
+ CLOG_INFO(&LOG, 0, "Read file %s", fd->relabase);
+ CLOG_INFO(&LOG,
+ 0,
+ " Version %d sub %d date %s hash %s",
+ main->versionfile,
+ main->subversionfile,
+ build_commit_datetime,
+ main->build_hash);
}
blo_do_versions_pre250(fd, lib, main);
@@ -3883,8 +3906,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
static void do_versions_after_linking(Main *main, ReportList *reports)
{
- // printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->filepath :
- // main->name, main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
+ CLOG_INFO(&LOG,
+ 2,
+ "Processing %s (%s), %d.%d",
+ main->curlib ? main->curlib->filepath : main->name,
+ main->curlib ? "LIB" : "MAIN",
+ main->versionfile,
+ main->subversionfile);
/* Don't allow versioning to create new data-blocks. */
main->is_locked_for_linking = true;
@@ -4105,7 +4133,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
ListBase mainlist = {NULL, NULL};
if (fd->memfile != NULL) {
- DEBUG_PRINTF("\nUNDO: read step\n");
+ CLOG_INFO(&LOG_UNDO, 2, "UNDO: read step");
}
bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata");
@@ -4206,6 +4234,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
}
if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
+ fd->reports->duration.libraries = PIL_check_seconds_timer();
read_libraries(fd, &mainlist);
blo_join_main(&mainlist);
@@ -4213,6 +4242,8 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
lib_link_all(fd, bfd->main);
after_liblink_merged_bmain_process(bfd->main);
+ fd->reports->duration.libraries = PIL_check_seconds_timer() - fd->reports->duration.libraries;
+
/* Skip in undo case. */
if (fd->memfile == NULL) {
/* Note that we can't recompute user-counts at this point in undo case, we play too much with
@@ -4228,7 +4259,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
blo_split_main(&mainlist, bfd->main);
LISTBASE_FOREACH (Main *, mainvar, &mainlist) {
BLI_assert(mainvar->versionfile != 0);
- do_versions_after_linking(mainvar, fd->reports);
+ do_versions_after_linking(mainvar, fd->reports->reports);
}
blo_join_main(&mainlist);
@@ -4249,8 +4280,13 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* we can re-generate overrides from their references. */
if (fd->memfile == NULL) {
/* Do not apply in undo case! */
- BKE_lib_override_library_main_validate(bfd->main, fd->reports);
+ fd->reports->duration.lib_overrides = PIL_check_seconds_timer();
+
+ BKE_lib_override_library_main_validate(bfd->main, fd->reports->reports);
BKE_lib_override_library_main_update(bfd->main);
+
+ fd->reports->duration.lib_overrides = PIL_check_seconds_timer() -
+ fd->reports->duration.lib_overrides;
}
BKE_collections_after_lib_link(bfd->main);
@@ -4908,9 +4944,7 @@ static ID *link_named_part(
}
else {
/* already linked */
- if (G.debug) {
- printf("append: already linked\n");
- }
+ CLOG_WARN(&LOG, "Append: ID '%s' is already linked", id->name);
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
id->tag &= ~LIB_TAG_INDIRECT;
@@ -5184,7 +5218,7 @@ static void library_link_end(Main *mainl,
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
- mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
+ mainl = NULL; /* blo_join_main free's mainl, can't use anymore */
lib_link_all(*fd, mainvar);
after_liblink_merged_bmain_process(mainvar);
@@ -5206,7 +5240,7 @@ static void library_link_end(Main *mainl,
* or they will go again through do_versions - bad, very bad! */
split_main_newid(mainvar, main_newid);
- do_versions_after_linking(main_newid, (*fd)->reports);
+ do_versions_after_linking(main_newid, (*fd)->reports->reports);
add_main_to_main(mainvar, main_newid);
}
@@ -5340,7 +5374,7 @@ static void read_library_linked_id(
id->name + 2,
mainvar->curlib->filepath_abs,
library_parent_filepath(mainvar->curlib));
- basefd->library_id_missing_count++;
+ basefd->reports->count.missing_linked_id++;
/* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
if (r_id) {
@@ -5414,7 +5448,7 @@ static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist,
while (id) {
ID *id_next = id->next;
if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && (id->flag & LIB_INDIRECT_WEAK_LINK)) {
- /* printf("Dropping weak link to %s\n", id->name); */
+ CLOG_INFO(&LOG, 3, "Dropping weak link to '%s'", id->name);
change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, NULL);
BLI_freelinkN(lbarray[a], id);
}
@@ -5495,7 +5529,7 @@ static FileData *read_library_file_data(FileData *basefd,
if (fd == NULL) {
BLO_reportf_wrap(
basefd->reports, RPT_INFO, TIP_("Cannot find lib '%s'"), mainptr->curlib->filepath_abs);
- basefd->library_file_missing_count++;
+ basefd->reports->count.missing_libraries++;
}
return fd;
@@ -5524,11 +5558,11 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
/* Does this library have any more linked data-blocks we need to read? */
if (has_linked_ids_to_read(mainptr)) {
-#if 0
- printf("Reading linked data-blocks from %s (%s)\n",
- mainptr->curlib->id.name,
- mainptr->curlib->filepath);
-#endif
+ CLOG_INFO(&LOG,
+ 3,
+ "Reading linked data-blocks from %s (%s)",
+ mainptr->curlib->id.name,
+ mainptr->curlib->filepath);
/* Open file if it has not been done yet. */
FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr);
@@ -5589,15 +5623,6 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
mainptr->curlib->filedata = NULL;
}
BKE_main_free(main_newid);
-
- if (basefd->library_file_missing_count != 0 || basefd->library_id_missing_count != 0) {
- BKE_reportf(basefd->reports,
- RPT_WARNING,
- "LIB: %d libraries and %d linked data-blocks are missing, please check the "
- "Info and Outliner editors for details",
- basefd->library_file_missing_count,
- basefd->library_id_missing_count);
- }
}
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
@@ -5785,7 +5810,7 @@ void BLO_read_glob_list(BlendDataReader *reader, ListBase *list)
link_glob_list(reader->fd, list);
}
-ReportList *BLO_read_data_reports(BlendDataReader *reader)
+BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader)
{
return reader->fd->reports;
}
@@ -5800,7 +5825,7 @@ Main *BLO_read_lib_get_main(BlendLibReader *reader)
return reader->main;
}
-ReportList *BLO_read_lib_reports(BlendLibReader *reader)
+BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader)
{
return reader->fd->reports;
}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index d1d4e0b3256..b04043f9641 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -145,11 +145,7 @@ typedef struct FileData {
ListBase *old_mainlist;
struct IDNameLib_Map *old_idmap;
- struct ReportList *reports;
- /* Counters for amount of missing libraries, and missing IDs in libraries.
- * Used to generate a synthetic report in the UI. */
- int library_file_missing_count;
- int library_id_missing_count;
+ struct BlendFileReadReport *reports;
} FileData;
#define SIZEOFBLENDERHEADER 12
@@ -161,11 +157,13 @@ void blo_split_main(ListBase *mainlist, struct Main *main);
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
-FileData *blo_filedata_from_file(const char *filepath, struct ReportList *reports);
-FileData *blo_filedata_from_memory(const void *mem, int memsize, struct ReportList *reports);
+FileData *blo_filedata_from_file(const char *filepath, struct BlendFileReadReport *reports);
+FileData *blo_filedata_from_memory(const void *mem,
+ int memsize,
+ struct BlendFileReadReport *reports);
FileData *blo_filedata_from_memfile(struct MemFile *memfile,
const struct BlendFileReadParams *params,
- struct ReportList *reports);
+ struct BlendFileReadReport *reports);
void blo_clear_proxy_pointers_from_lib(struct Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
diff --git a/source/blender/blenloader/intern/readfile_tempload.c b/source/blender/blenloader/intern/readfile_tempload.c
index 4566e1e9b4d..f440a06acf8 100644
--- a/source/blender/blenloader/intern/readfile_tempload.c
+++ b/source/blender/blenloader/intern/readfile_tempload.c
@@ -40,7 +40,8 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
/* Copy the file path so any path remapping is performed properly. */
STRNCPY(temp_lib_ctx->bmain_base->name, real_main->name);
- temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path, reports);
+ temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(
+ blend_file_path, &(BlendFileReadReport){.reports = reports});
BLO_library_link_params_init(
&temp_lib_ctx->liblink_params, temp_lib_ctx->bmain_base, 0, LIB_TAG_TEMP_MAIN);
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 7c5eefa60f7..fe3d7f8e98f 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -861,7 +861,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
int i;
for (i = 0; i < 3; i++) {
if ((ob->dsize[i] == 0.0f) || /* simple case, user never touched dsize */
- (ob->scale[i] == 0.0f)) /* cant scale the dsize to give a non zero result,
+ (ob->scale[i] == 0.0f)) /* can't scale the dsize to give a non zero result,
* so fallback to 1.0f */
{
ob->dscale[i] = 1.0f;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 289092f7f19..776f6c54363 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -263,8 +263,8 @@ static void do_version_action_editor_properties_region(ListBase *regionbase)
static void do_version_bones_super_bbone(ListBase *lb)
{
LISTBASE_FOREACH (Bone *, bone, lb) {
- bone->scale_in_x = bone->scale_in_y = 1.0f;
- bone->scale_out_x = bone->scale_out_y = 1.0f;
+ bone->scale_in_x = bone->scale_in_z = 1.0f;
+ bone->scale_out_x = bone->scale_out_z = 1.0f;
do_version_bones_super_bbone(&bone->childbase);
}
@@ -1268,8 +1268,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (ob->pose) {
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
/* see do_version_bones_super_bbone()... */
- pchan->scale_in_x = pchan->scale_in_y = 1.0f;
- pchan->scale_out_x = pchan->scale_out_y = 1.0f;
+ pchan->scale_in_x = pchan->scale_in_z = 1.0f;
+ pchan->scale_out_x = pchan->scale_out_z = 1.0f;
/* also make sure some legacy (unused for over a decade) flags are unset,
* so that we can reuse them for stuff that matters now...
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index cf082393803..0059074c8ad 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -709,8 +709,8 @@ static void do_versions_area_ensure_tool_region(Main *bmain,
static void do_version_bones_split_bbone_scale(ListBase *lb)
{
LISTBASE_FOREACH (Bone *, bone, lb) {
- bone->scale_in_y = bone->scale_in_x;
- bone->scale_out_y = bone->scale_out_x;
+ bone->scale_in_z = bone->scale_in_x;
+ bone->scale_out_z = bone->scale_out_x;
do_version_bones_split_bbone_scale(&bone->childbase);
}
@@ -1785,7 +1785,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep)
{
for (Sequence *seq = seqbasep->first; seq != NULL; seq = seq->next) {
- SEQ_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq);
+ SEQ_sequence_base_unique_name_recursive(sce, &sce->ed->seqbase, seq);
if (seq->seqbase.first != NULL) {
do_versions_seq_unique_name_all_strips(sce, &seq->seqbase);
}
@@ -1912,7 +1912,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_END;
if (error & NTREE_DOVERSION_NEED_OUTPUT) {
- BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+ BKE_report(fd->reports != NULL ? fd->reports->reports : NULL,
+ RPT_ERROR,
+ "Eevee material conversion problem. Error in console");
printf(
"You need to connect Principled and Eevee Specular shader nodes to new material "
"output "
@@ -1920,7 +1922,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (error & NTREE_DOVERSION_TRANSPARENCY_EMISSION) {
- BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+ BKE_report(fd->reports != NULL ? fd->reports->reports : NULL,
+ RPT_ERROR,
+ "Eevee material conversion problem. Error in console");
printf(
"You need to combine transparency and emission shaders to the converted Principled "
"shader nodes.\n");
@@ -3172,7 +3176,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
bool is_blend = false;
{
- char tool = tool_init;
+ char tool;
switch (tool_init) {
case PAINT_BLEND_MIX:
tool = VPAINT_TOOL_DRAW;
@@ -3969,8 +3973,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->pose) {
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
- pchan->scale_in_y = pchan->scale_in_x;
- pchan->scale_out_y = pchan->scale_out_x;
+ pchan->scale_in_z = pchan->scale_in_x;
+ pchan->scale_out_z = pchan->scale_out_x;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 565e62158ff..156b1f4198d 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -80,6 +80,7 @@
#include "BLO_readfile.h"
#include "readfile.h"
+#include "versioning_common.h"
/* Make preferences read-only, use versioning_userdef.c. */
#define U (*((const UserDef *)&U))
@@ -117,24 +118,38 @@ static bool can_use_proxy(const Sequence *seq, int psize)
}
/* image_size is width or height depending what RNA property is converted - X or Y. */
-static void seq_convert_transform_animation(const Scene *scene,
+static void seq_convert_transform_animation(const Sequence *seq,
+ const Scene *scene,
const char *path,
- const int image_size)
+ const int image_size,
+ const int scene_size)
{
if (scene->adt == NULL || scene->adt->action == NULL) {
return;
}
- FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0);
- if (fcu != NULL && !BKE_fcurve_is_empty(fcu)) {
- BezTriple *bezt = fcu->bezt;
- for (int i = 0; i < fcu->totvert; i++, bezt++) {
- /* Same math as with old_image_center_*, but simplified. */
- bezt->vec[0][1] = image_size / 2 + bezt->vec[0][1] - scene->r.xsch / 2;
- bezt->vec[1][1] = image_size / 2 + bezt->vec[1][1] - scene->r.xsch / 2;
- bezt->vec[2][1] = image_size / 2 + bezt->vec[2][1] - scene->r.xsch / 2;
+ /* Hardcoded legacy bit-flags which has been removed. */
+ const uint32_t use_transform_flag = (1 << 16);
+ const uint32_t use_crop_flag = (1 << 17);
+
+ /* Convert offset animation, but only if crop is not used. */
+ if ((seq->flag & use_transform_flag) != 0 && (seq->flag & use_crop_flag) == 0) {
+ FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0);
+ if (fcu != NULL && !BKE_fcurve_is_empty(fcu)) {
+ BezTriple *bezt = fcu->bezt;
+ for (int i = 0; i < fcu->totvert; i++, bezt++) {
+ /* Same math as with old_image_center_*, but simplified. */
+ bezt->vec[0][1] = (image_size - scene_size) / 2 + bezt->vec[0][1];
+ bezt->vec[1][1] = (image_size - scene_size) / 2 + bezt->vec[1][1];
+ bezt->vec[2][1] = (image_size - scene_size) / 2 + bezt->vec[2][1];
+ }
}
}
+ else { /* Else, remove offset animation. */
+ FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0);
+ BLI_remlink(&scene->adt->action->curves, fcu);
+ BKE_fcurve_free(fcu);
+ }
}
static void seq_convert_transform_crop(const Scene *scene,
@@ -231,18 +246,15 @@ static void seq_convert_transform_crop(const Scene *scene,
t->xofs = old_image_center_x - scene->r.xsch / 2;
t->yofs = old_image_center_y - scene->r.ysch / 2;
- /* Convert offset animation, but only if crop is not used. */
- if ((seq->flag & use_transform_flag) != 0 && (seq->flag & use_crop_flag) == 0) {
- char name_esc[(sizeof(seq->name) - 2) * 2], *path;
- BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
+ char name_esc[(sizeof(seq->name) - 2) * 2], *path;
+ BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
- path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_x", name_esc);
- seq_convert_transform_animation(scene, path, image_size_x);
- MEM_freeN(path);
- path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_y", name_esc);
- seq_convert_transform_animation(scene, path, image_size_y);
- MEM_freeN(path);
- }
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_x", name_esc);
+ seq_convert_transform_animation(seq, scene, path, image_size_x, scene->r.xsch);
+ MEM_freeN(path);
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_y", name_esc);
+ seq_convert_transform_animation(seq, scene, path, image_size_y, scene->r.ysch);
+ MEM_freeN(path);
seq->flag &= ~use_transform_flag;
seq->flag &= ~use_crop_flag;
@@ -861,26 +873,6 @@ static void version_node_join_geometry_for_multi_input_socket(bNodeTree *ntree)
}
}
-static ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
- int region_type,
- const char *name,
- int link_after_region_type)
-{
- ARegion *link_after_region = NULL;
- LISTBASE_FOREACH (ARegion *, region, regionbase) {
- if (region->regiontype == region_type) {
- return NULL;
- }
- if (region->regiontype == link_after_region_type) {
- link_after_region = region;
- }
- }
- ARegion *new_region = MEM_callocN(sizeof(ARegion), name);
- new_region->regiontype = region_type;
- BLI_insertlinkafter(regionbase, link_after_region, new_region);
- return new_region;
-}
-
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 93e2af1b68e..0fe1267b871 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -25,12 +25,16 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_genfile.h"
#include "DNA_listBase.h"
#include "DNA_modifier_types.h"
#include "DNA_text_types.h"
+#include "BKE_animsys.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -38,6 +42,10 @@
#include "BLO_readfile.h"
#include "readfile.h"
+#include "MEM_guardedalloc.h"
+
+#include "versioning_common.h"
+
static void sort_linked_ids(Main *bmain)
{
ListBase *lb;
@@ -186,6 +194,83 @@ static void version_node_socket_name(bNodeTree *ntree,
}
}
+static bool replace_bbone_len_scale_rnapath(char **p_old_path, int *p_index)
+{
+ char *old_path = *p_old_path;
+
+ if (old_path == NULL) {
+ return false;
+ }
+
+ int len = strlen(old_path);
+
+ if (BLI_str_endswith(old_path, ".bbone_curveiny") ||
+ BLI_str_endswith(old_path, ".bbone_curveouty")) {
+ old_path[len - 1] = 'z';
+ return true;
+ }
+
+ if (BLI_str_endswith(old_path, ".bbone_scaleinx") ||
+ BLI_str_endswith(old_path, ".bbone_scaleiny") ||
+ BLI_str_endswith(old_path, ".bbone_scaleoutx") ||
+ BLI_str_endswith(old_path, ".bbone_scaleouty")) {
+ int index = (old_path[len - 1] == 'y' ? 2 : 0);
+
+ old_path[len - 1] = 0;
+
+ if (p_index) {
+ *p_index = index;
+ }
+ else {
+ *p_old_path = BLI_sprintfN("%s[%d]", old_path, index);
+ MEM_freeN(old_path);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static void do_version_bbone_len_scale_fcurve_fix(FCurve *fcu)
+{
+ /* Update driver variable paths. */
+ if (fcu->driver) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) {
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ replace_bbone_len_scale_rnapath(&dtar->rna_path, NULL);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+
+ /* Update F-Curve's path. */
+ replace_bbone_len_scale_rnapath(&fcu->rna_path, &fcu->array_index);
+}
+
+static void do_version_bbone_len_scale_animdata_cb(ID *UNUSED(id),
+ AnimData *adt,
+ void *UNUSED(wrapper_data))
+{
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) {
+ do_version_bbone_len_scale_fcurve_fix(fcu);
+ }
+}
+
+static void do_version_bones_bbone_len_scale(ListBase *lb)
+{
+ LISTBASE_FOREACH (Bone *, bone, lb) {
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ bone->bbone_flag |= BBONE_ADD_PARENT_END_ROLL;
+ }
+
+ copy_v3_fl3(bone->scale_in, bone->scale_in_x, 1.0f, bone->scale_in_z);
+ copy_v3_fl3(bone->scale_out, bone->scale_out_x, 1.0f, bone->scale_out_z);
+
+ do_version_bones_bbone_len_scale(&bone->childbase);
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -227,6 +312,86 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 4)) {
+ /* Add a properties sidebar to the spreadsheet editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *new_sidebar = do_versions_add_region_if_not_found(
+ regionbase, RGN_TYPE_UI, "sidebar for spreadsheet", RGN_TYPE_FOOTER);
+ if (new_sidebar != NULL) {
+ new_sidebar->alignment = RGN_ALIGN_RIGHT;
+ new_sidebar->flag |= RGN_FLAG_HIDDEN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Enable spreadsheet filtering in old files without row filters. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ sspreadsheet->filter_flag |= SPREADSHEET_FILTER_ENABLE;
+ }
+ }
+ }
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_socket_name(ntree, GEO_NODE_BOUNDING_BOX, "Mesh", "Bounding Box");
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ if (!DNA_struct_elem_find(fd->filesdna, "FileAssetSelectParams", "int", "import_type")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ if (sfile->asset_params) {
+ sfile->asset_params->import_type = FILE_ASSET_IMPORT_APPEND;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Initialize length-wise scale B-Bone settings. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Bone", "int", "bbone_flag")) {
+ /* Update armature data and pose channels. */
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_bbone_len_scale(&arm->bonebase);
+ }
+
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->pose) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ copy_v3_fl3(pchan->scale_in, pchan->scale_in_x, 1.0f, pchan->scale_in_z);
+ copy_v3_fl3(pchan->scale_out, pchan->scale_out_x, 1.0f, pchan->scale_out_z);
+ }
+ }
+ }
+
+ /* Update action curves and drivers. */
+ LISTBASE_FOREACH (bAction *, act, &bmain->actions) {
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &act->curves) {
+ do_version_bbone_len_scale_fcurve_fix(fcu);
+ }
+ }
+
+ BKE_animdata_main_cb(bmain, do_version_bbone_len_scale_animdata_cb, NULL);
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -238,11 +403,5 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_BOUNDING_BOX, "Mesh", "Bounding Box");
- }
- }
- FOREACH_NODETREE_END;
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
new file mode 100644
index 00000000000..f5083b8e259
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup blenloader
+ */
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include "DNA_screen_types.h"
+
+#include "BLI_listbase.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "versioning_common.h"
+
+ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
+ int region_type,
+ const char *name,
+ int link_after_region_type)
+{
+ ARegion *link_after_region = nullptr;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == region_type) {
+ return nullptr;
+ }
+ if (region->regiontype == link_after_region_type) {
+ link_after_region = region;
+ }
+ }
+
+ ARegion *new_region = static_cast<ARegion *>(MEM_callocN(sizeof(ARegion), name));
+ new_region->regiontype = region_type;
+ BLI_insertlinkafter(regionbase, link_after_region, new_region);
+ return new_region;
+}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
new file mode 100644
index 00000000000..a1769d4639e
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup blenloader
+ */
+
+#pragma once
+
+struct ARegion;
+struct ListBase;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ARegion *do_versions_add_region_if_not_found(struct ListBase *regionbase,
+ int region_type,
+ const char *name,
+ int link_after_region_type);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 38c00b3f132..fbcf690a773 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -605,7 +605,7 @@ static void writelist_id(WriteData *wd, int filecode, const char *structname, co
* \{ */
/**
- * Take care using 'use_active_win', since we wont want the currently active window
+ * Take care using 'use_active_win', since we won't want the currently active window
* to change which scene renders (currently only used for undo).
*/
static void current_screen_compat(Main *mainvar,
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index 280a4b42b36..e93348b2158 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -123,7 +123,8 @@ bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath)
char abspath[FILENAME_MAX];
BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath, NULL);
- bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, nullptr /* reports */);
+ BlendFileReadReport bf_reports = {NULL};
+ bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, &bf_reports);
if (bfile == nullptr) {
ADD_FAILURE() << "Unable to load file '" << filepath << "' from test assets dir '"
<< test_assets_dir << "'";
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index c83fc0645c4..f60fc72f8a9 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -24,7 +24,7 @@
*/
/* disable holes for now,
- * these are ifdef'd because they use more memory and cant be saved in DNA currently */
+ * these are ifdef'd because they use more memory and can't be saved in DNA currently */
// #define USE_BMESH_HOLES
struct BMEdge;
@@ -346,7 +346,7 @@ typedef struct BMesh {
/* Should be copy of scene select mode. */
/* Stored in #BMEditMesh too, this is a bit confusing,
* make sure they're in sync!
- * Only use when the edit mesh cant be accessed - campbell */
+ * Only use when the edit mesh can't be accessed - campbell */
short selectmode;
/* ID of the shape key this bmesh came from */
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 3eab252df7a..f79f1925560 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -673,7 +673,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
ftable = MEM_mallocN(sizeof(BMFace *) * bm_old->totface, "BM_mesh_copy ftable");
BM_ITER_MESH_INDEX (v, &iter, bm_old, BM_VERTS_OF_MESH, i) {
- /* copy between meshes so cant use 'example' argument */
+ /* copy between meshes so can't use 'example' argument */
v_new = BM_vert_create(bm_new, v->co, NULL, BM_CREATE_SKIP_CD);
BM_elem_attrs_copy_ex(bm_old, bm_new, v, v_new, 0xff, 0x0);
v_new->head.hflag = v->head.hflag; /* low level! don't do this for normal api use */
diff --git a/source/blender/bmesh/intern/bmesh_inline.h b/source/blender/bmesh/intern/bmesh_inline.h
index 2888d7e7526..4350b4d04ed 100644
--- a/source/blender/bmesh/intern/bmesh_inline.h
+++ b/source/blender/bmesh/intern/bmesh_inline.h
@@ -95,7 +95,7 @@ BLI_INLINE void _bm_elem_flag_merge_into(BMHeader *head,
/**
* notes on #BM_elem_index_set(...) usage,
- * Set index is sometimes abused as temp storage, other times we cant be
+ * Set index is sometimes abused as temp storage, other times we can't be
* sure if the index values are valid because certain operations have modified
* the mesh structure.
*
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index d479a555a58..190698f504c 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -33,6 +33,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "bmesh.h"
#include "bmesh_structure.h"
@@ -40,31 +41,123 @@
/* For '_FLAG_OVERLAP'. */
#include "bmesh_private.h"
-static void recount_totsels(BMesh *bm)
+/* -------------------------------------------------------------------- */
+/** \name Recounting total selection.
+ * \{ */
+
+typedef struct SelectionCountChunkData {
+ int selection_len;
+} SelectionCountChunkData;
+
+static void recount_totsels_range_vert_func(void *UNUSED(userdata),
+ MempoolIterData *iter,
+ const TaskParallelTLS *__restrict tls)
{
- const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
- int *tots[3];
- int i;
+ SelectionCountChunkData *count = tls->userdata_chunk;
+ const BMVert *eve = (const BMVert *)iter;
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ count->selection_len += 1;
+ }
+}
- /* Recount total selection variables. */
- bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
- tots[0] = &bm->totvertsel;
- tots[1] = &bm->totedgesel;
- tots[2] = &bm->totfacesel;
+static void recount_totsels_range_edge_func(void *UNUSED(userdata),
+ MempoolIterData *iter,
+ const TaskParallelTLS *__restrict tls)
+{
+ SelectionCountChunkData *count = tls->userdata_chunk;
+ const BMEdge *eed = (const BMEdge *)iter;
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ count->selection_len += 1;
+ }
+}
- for (i = 0; i < 3; i++) {
- BMIter iter;
- BMElem *ele;
- int count = 0;
+static void recount_totsels_range_face_func(void *UNUSED(userdata),
+ MempoolIterData *iter,
+ const TaskParallelTLS *__restrict tls)
+{
+ SelectionCountChunkData *count = tls->userdata_chunk;
+ const BMFace *efa = (const BMFace *)iter;
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ count->selection_len += 1;
+ }
+}
- BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
- if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
- count += 1;
- }
- }
- *tots[i] = count;
+static void recount_totsels_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ SelectionCountChunkData *dst = chunk_join;
+ const SelectionCountChunkData *src = chunk;
+ dst->selection_len += src->selection_len;
+}
+
+static TaskParallelMempoolFunc recount_totsels_get_range_func(BMIterType iter_type)
+{
+ BLI_assert(ELEM(iter_type, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH));
+
+ TaskParallelMempoolFunc range_func = NULL;
+ if (iter_type == BM_VERTS_OF_MESH) {
+ range_func = recount_totsels_range_vert_func;
+ }
+ else if (iter_type == BM_EDGES_OF_MESH) {
+ range_func = recount_totsels_range_edge_func;
}
+ else if (iter_type == BM_FACES_OF_MESH) {
+ range_func = recount_totsels_range_face_func;
+ }
+ return range_func;
+}
+
+static int recount_totsel(BMesh *bm, BMIterType iter_type)
+{
+ const int MIN_ITER_SIZE = 1024;
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.func_reduce = recount_totsels_reduce;
+ settings.min_iter_per_thread = MIN_ITER_SIZE;
+
+ SelectionCountChunkData count = {0};
+ settings.userdata_chunk = &count;
+ settings.userdata_chunk_size = sizeof(count);
+
+ TaskParallelMempoolFunc range_func = recount_totsels_get_range_func(iter_type);
+ BM_iter_parallel(bm, iter_type, range_func, NULL, &settings);
+ return count.selection_len;
+}
+
+static void recount_totvertsel(BMesh *bm)
+{
+ bm->totvertsel = recount_totsel(bm, BM_VERTS_OF_MESH);
+}
+
+static void recount_totedgesel(BMesh *bm)
+{
+ bm->totedgesel = recount_totsel(bm, BM_EDGES_OF_MESH);
+}
+
+static void recount_totfacesel(BMesh *bm)
+{
+ bm->totfacesel = recount_totsel(bm, BM_FACES_OF_MESH);
+}
+
+static void recount_totsels(BMesh *bm)
+{
+ recount_totvertsel(bm);
+ recount_totedgesel(bm);
+ recount_totfacesel(bm);
+}
+
+#ifndef NDEBUG
+static bool recount_totsels_are_ok(BMesh *bm)
+{
+ return bm->totvertsel == recount_totsel(bm, BM_VERTS_OF_MESH) &&
+ bm->totedgesel == recount_totsel(bm, BM_EDGES_OF_MESH) &&
+ bm->totfacesel == recount_totsel(bm, BM_FACES_OF_MESH);
}
+#endif
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name BMesh helper functions for selection & hide flushing.
@@ -231,6 +324,106 @@ void BM_mesh_select_mode_clean(BMesh *bm)
BM_mesh_select_mode_clean_ex(bm, bm->selectmode);
}
+/* -------------------------------------------------------------------- */
+/** \name Select mode flush selection
+ * \{ */
+
+typedef struct SelectionFlushChunkData {
+ int delta_selection_len;
+} SelectionFlushChunkData;
+
+static void bm_mesh_select_mode_flush_vert_to_edge_iter_fn(void *UNUSED(userdata),
+ MempoolIterData *iter,
+ const TaskParallelTLS *__restrict tls)
+{
+ SelectionFlushChunkData *chunk_data = tls->userdata_chunk;
+ BMEdge *e = (BMEdge *)iter;
+ const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT);
+ const bool is_hidden = BM_elem_flag_test(e, BM_ELEM_HIDDEN);
+ if (!is_hidden &&
+ (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT))) {
+ BM_elem_flag_enable(e, BM_ELEM_SELECT);
+ chunk_data->delta_selection_len += is_selected ? 0 : 1;
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ chunk_data->delta_selection_len += is_selected ? -1 : 0;
+ }
+}
+
+static void bm_mesh_select_mode_flush_edge_to_face_iter_fn(void *UNUSED(userdata),
+ MempoolIterData *iter,
+ const TaskParallelTLS *__restrict tls)
+{
+ SelectionFlushChunkData *chunk_data = tls->userdata_chunk;
+ BMFace *f = (BMFace *)iter;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ const bool is_selected = BM_elem_flag_test(f, BM_ELEM_SELECT);
+ bool ok = true;
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
+ ok = false;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ ok = false;
+ }
+
+ BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
+ if (is_selected && !ok) {
+ chunk_data->delta_selection_len -= 1;
+ }
+ else if (ok && !is_selected) {
+ chunk_data->delta_selection_len += 1;
+ }
+}
+
+static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ SelectionFlushChunkData *dst = chunk_join;
+ const SelectionFlushChunkData *src = chunk;
+ dst->delta_selection_len += src->delta_selection_len;
+}
+
+static void bm_mesh_select_mode_flush_vert_to_edge(BMesh *bm)
+{
+ SelectionFlushChunkData chunk_data = {0};
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
+ settings.userdata_chunk = &chunk_data;
+ settings.userdata_chunk_size = sizeof(chunk_data);
+ settings.func_reduce = bm_mesh_select_mode_flush_reduce_fn;
+
+ BM_iter_parallel(
+ bm, BM_EDGES_OF_MESH, bm_mesh_select_mode_flush_vert_to_edge_iter_fn, NULL, &settings);
+ bm->totedgesel += chunk_data.delta_selection_len;
+}
+
+static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm)
+{
+ SelectionFlushChunkData chunk_data = {0};
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = bm->totface >= BM_OMP_LIMIT;
+ settings.userdata_chunk = &chunk_data;
+ settings.userdata_chunk_size = sizeof(chunk_data);
+ settings.func_reduce = bm_mesh_select_mode_flush_reduce_fn;
+
+ BM_iter_parallel(
+ bm, BM_FACES_OF_MESH, bm_mesh_select_mode_flush_edge_to_face_iter_fn, NULL, &settings);
+ bm->totfacesel += chunk_data.delta_selection_len;
+}
+
/**
* \brief Select Mode Flush
*
@@ -238,76 +431,38 @@ void BM_mesh_select_mode_clean(BMesh *bm)
* (ie: all verts of an edge selects the edge and so on).
* This should only be called by system and not tool authors.
*/
-void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
+void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
{
- BMEdge *e;
- BMLoop *l_iter;
- BMLoop *l_first;
- BMFace *f;
-
- BMIter eiter;
- BMIter fiter;
-
if (selectmode & SCE_SELECT_VERTEX) {
- /* both loops only set edge/face flags and read off verts */
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
- !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BM_elem_flag_enable(e, BM_ELEM_SELECT);
- }
- else {
- BM_elem_flag_disable(e, BM_ELEM_SELECT);
- }
- }
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- bool ok = true;
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
- ok = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
- else {
- ok = false;
- }
-
- BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
- }
+ bm_mesh_select_mode_flush_vert_to_edge(bm);
}
- else if (selectmode & SCE_SELECT_EDGE) {
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- bool ok = true;
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
- ok = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
- else {
- ok = false;
- }
- BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
- }
+ if (selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ bm_mesh_select_mode_flush_edge_to_face(bm);
}
/* Remove any deselected elements from the BMEditSelection */
BM_select_history_validate(bm);
- recount_totsels(bm);
+ if (flags & BM_SELECT_LEN_FLUSH_RECALC_VERT) {
+ recount_totvertsel(bm);
+ }
+ if (flags & BM_SELECT_LEN_FLUSH_RECALC_EDGE) {
+ recount_totedgesel(bm);
+ }
+ if (flags & BM_SELECT_LEN_FLUSH_RECALC_FACE) {
+ recount_totfacesel(bm);
+ }
+ BLI_assert(recount_totsels_are_ok(bm));
}
void BM_mesh_select_mode_flush(BMesh *bm)
{
- BM_mesh_select_mode_flush_ex(bm, bm->selectmode);
+ BM_mesh_select_mode_flush_ex(bm, bm->selectmode, BM_SELECT_LEN_FLUSH_RECALC_ALL);
}
+/** \} */
+
/**
* mode independent flushing up/down
*/
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 04a49e24757..ff6c359138a 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -26,6 +26,16 @@ typedef struct BMEditSelection {
char htype;
} BMEditSelection;
+typedef enum eBMSelectionFlushFLags {
+ BM_SELECT_LEN_FLUSH_RECALC_NOTHING = 0,
+ BM_SELECT_LEN_FLUSH_RECALC_VERT = (1 << 0),
+ BM_SELECT_LEN_FLUSH_RECALC_EDGE = (1 << 1),
+ BM_SELECT_LEN_FLUSH_RECALC_FACE = (1 << 2),
+ BM_SELECT_LEN_FLUSH_RECALC_ALL = (BM_SELECT_LEN_FLUSH_RECALC_VERT |
+ BM_SELECT_LEN_FLUSH_RECALC_EDGE |
+ BM_SELECT_LEN_FLUSH_RECALC_FACE),
+} eBMSelectionFlushFLags;
+
/* geometry hiding code */
#define BM_elem_hide_set(bm, ele, hide) _bm_elem_hide_set(bm, &(ele)->head, hide)
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide);
@@ -72,7 +82,7 @@ void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
-void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode);
+void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags);
void BM_mesh_select_mode_flush(BMesh *bm);
void BM_mesh_deselect_flush(BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index d0c6bc83088..80028564ff2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -840,8 +840,8 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
BMVert **verts_pool, *verts_copy, **vep;
int i, totvert = bm->totvert;
const uint *new_idx;
- /* Special case: Python uses custom - data layers to hold PyObject references.
- * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
+ /* Special case: Python uses custom data layers to hold PyObject references.
+ * These have to be kept in place, else the PyObjects we point to, won't point back to us. */
const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -892,8 +892,8 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
BMEdge **edges_pool, *edges_copy, **edp;
int i, totedge = bm->totedge;
const uint *new_idx;
- /* Special case: Python uses custom - data layers to hold PyObject references.
- * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
+ /* Special case: Python uses custom data layers to hold PyObject references.
+ * These have to be kept in place, else the PyObjects we point to, won't point back to us. */
const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -943,8 +943,8 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
BMFace **faces_pool, *faces_copy, **fap;
int i, totface = bm->totface;
const uint *new_idx;
- /* Special case: Python uses custom - data layers to hold PyObject references.
- * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
+ /* Special case: Python uses custom data layers to hold PyObject references.
+ * These have to be kept in place, else the PyObjects we point to, won't point back to us. */
const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index a3eae6dabe8..bddd3da98b7 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -49,67 +49,9 @@
* assuming no other tool using it would run concurrently to clnors editing. */
#define BM_LNORSPACE_UPDATE _FLAG_MF
-typedef struct BMEdgesCalcVectorsData {
- /* Read-only data. */
- const float (*vcos)[3];
-
- /* Read-write data, but no need to protect it, no concurrency to fear here. */
- float (*edgevec)[3];
-} BMEdgesCalcVectorsData;
-
-static void bm_edge_calc_vectors_cb(void *userdata,
- MempoolIterData *mp_e,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- BMEdge *e = (BMEdge *)mp_e;
- /* The edge vector will not be needed when the edge has no radial. */
- if (e->l != NULL) {
- float(*edgevec)[3] = userdata;
- float *e_diff = edgevec[BM_elem_index_get(e)];
- sub_v3_v3v3(e_diff, e->v2->co, e->v1->co);
- normalize_v3(e_diff);
- }
-}
-
-static void bm_edge_calc_vectors_with_coords_cb(void *userdata,
- MempoolIterData *mp_e,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- BMEdge *e = (BMEdge *)mp_e;
- /* The edge vector will not be needed when the edge has no radial. */
- if (e->l != NULL) {
- BMEdgesCalcVectorsData *data = userdata;
- float *e_diff = data->edgevec[BM_elem_index_get(e)];
- sub_v3_v3v3(
- e_diff, data->vcos[BM_elem_index_get(e->v2)], data->vcos[BM_elem_index_get(e->v1)]);
- normalize_v3(e_diff);
- }
-}
-
-static void bm_mesh_edges_calc_vectors(BMesh *bm, float (*edgevec)[3], const float (*vcos)[3])
-{
- BM_mesh_elem_index_ensure(bm, BM_EDGE | (vcos ? BM_VERT : 0));
-
- TaskParallelSettings settings;
- BLI_parallel_mempool_settings_defaults(&settings);
- settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
-
- if (vcos == NULL) {
- BM_iter_parallel(bm, BM_EDGES_OF_MESH, bm_edge_calc_vectors_cb, edgevec, &settings);
- }
- else {
- BMEdgesCalcVectorsData data = {
- .edgevec = edgevec,
- .vcos = vcos,
- };
- BM_iter_parallel(bm, BM_EDGES_OF_MESH, bm_edge_calc_vectors_with_coords_cb, &data, &settings);
- }
-}
-
typedef struct BMVertsCalcNormalsWithCoordsData {
/* Read-only data. */
const float (*fnos)[3];
- const float (*edgevec)[3];
const float (*vcos)[3];
/* Write data. */
@@ -117,13 +59,12 @@ typedef struct BMVertsCalcNormalsWithCoordsData {
} BMVertsCalcNormalsWithCoordsData;
BLI_INLINE void bm_vert_calc_normals_accum_loop(const BMLoop *l_iter,
- const float (*edgevec)[3],
+ const float e1diff[3],
+ const float e2diff[3],
const float f_no[3],
float v_no[3])
{
/* Calculate the dot product of the two edges that meet at the loop's vertex. */
- const float *e1diff = edgevec[BM_elem_index_get(l_iter->prev->e)];
- const float *e2diff = edgevec[BM_elem_index_get(l_iter->e)];
/* Edge vectors are calculated from e->v1 to e->v2, so adjust the dot product if one but not
* both loops actually runs from from e->v2 to e->v1. */
float dotprod = dot_v3v3(e1diff, e2diff);
@@ -132,25 +73,61 @@ BLI_INLINE void bm_vert_calc_normals_accum_loop(const BMLoop *l_iter,
}
const float fac = saacos(-dotprod);
/* NAN detection, otherwise this is a degenerated case, ignore that vertex in this case. */
- if (fac == fac) { /* NAN detection. */
+ if (fac == fac) {
madd_v3_v3fl(v_no, f_no, fac);
}
}
-static void bm_vert_calc_normals_impl(const float (*edgevec)[3], BMVert *v)
+static void bm_vert_calc_normals_impl(BMVert *v)
{
+ /* Note on redundant unit-length edge-vector calculation:
+ *
+ * This functions calculates unit-length edge-vector for every loop edge
+ * in practice this means 2x `sqrt` calls per face-corner connected to each vertex.
+ *
+ * Previously (2.9x and older), the edge vectors were calculated and stored for reuse.
+ * However the overhead of did not perform well (~16% slower - single & multi-threaded)
+ * when compared with calculating the values as they are needed.
+ *
+ * For simple grid topologies this function calculates the edge-vectors 4x times.
+ * There is some room for improved performance by storing the edge-vectors for reuse locally
+ * in this function, reducing the number of redundant `sqrtf` in half (2x instead of 4x).
+ * so face loops that share an edge would not calculate it multiple times.
+ * From my tests the performance improvements are so small they're difficult to measure,
+ * the time saved removing `sqrtf` calls is lost on storing and looking up the information,
+ * even in the case of `BLI_smallhash.h` & small inline lookup tables.
+ *
+ * Further, local data structures would need to support cases where
+ * stack memory isn't sufficient - adding additional complexity for corner-cases
+ * (a vertex that has thousands of connected edges for example).
+ * Unless there are important use-cases that benefit from edge-vector caching,
+ * keep this simple and calculate ~4x as many edge-vectors.
+ *
+ * In conclusion, the cost of caching & looking up edge-vectors both globally or per-vertex
+ * doesn't save enough time to make it worthwhile.
+ * - Campbell. */
+
float *v_no = v->no;
zero_v3(v_no);
+
BMEdge *e_first = v->e;
if (e_first != NULL) {
+ float e1diff[3], e2diff[3];
BMEdge *e_iter = e_first;
do {
BMLoop *l_first = e_iter->l;
if (l_first != NULL) {
+ sub_v3_v3v3(e2diff, e_iter->v1->co, e_iter->v2->co);
+ normalize_v3(e2diff);
+
BMLoop *l_iter = l_first;
do {
if (l_iter->v == v) {
- bm_vert_calc_normals_accum_loop(l_iter, edgevec, l_iter->f->no, v_no);
+ BMEdge *e_prev = l_iter->prev->e;
+ sub_v3_v3v3(e1diff, e_prev->v1->co, e_prev->v2->co);
+ normalize_v3(e1diff);
+
+ bm_vert_calc_normals_accum_loop(l_iter, e1diff, e2diff, l_iter->f->no, v_no);
}
} while ((l_iter = l_iter->radial_next) != l_first);
}
@@ -164,32 +141,44 @@ static void bm_vert_calc_normals_impl(const float (*edgevec)[3], BMVert *v)
normalize_v3_v3(v_no, v->co);
}
-static void bm_vert_calc_normals_cb(void *userdata,
+static void bm_vert_calc_normals_cb(void *UNUSED(userdata),
MempoolIterData *mp_v,
const TaskParallelTLS *__restrict UNUSED(tls))
{
- const float(*edgevec)[3] = userdata;
BMVert *v = (BMVert *)mp_v;
- bm_vert_calc_normals_impl(edgevec, v);
+ bm_vert_calc_normals_impl(v);
}
static void bm_vert_calc_normals_with_coords(BMVert *v, BMVertsCalcNormalsWithCoordsData *data)
{
+ /* See #bm_vert_calc_normals_impl note on performance. */
float *v_no = data->vnos[BM_elem_index_get(v)];
zero_v3(v_no);
/* Loop over edges. */
BMEdge *e_first = v->e;
if (e_first != NULL) {
+ float e1diff[3], e2diff[3];
BMEdge *e_iter = e_first;
do {
BMLoop *l_first = e_iter->l;
if (l_first != NULL) {
+ sub_v3_v3v3(e2diff,
+ data->vcos[BM_elem_index_get(e_iter->v1)],
+ data->vcos[BM_elem_index_get(e_iter->v2)]);
+ normalize_v3(e2diff);
+
BMLoop *l_iter = l_first;
do {
if (l_iter->v == v) {
+ BMEdge *e_prev = l_iter->prev->e;
+ sub_v3_v3v3(e1diff,
+ data->vcos[BM_elem_index_get(e_prev->v1)],
+ data->vcos[BM_elem_index_get(e_prev->v2)]);
+ normalize_v3(e1diff);
+
bm_vert_calc_normals_accum_loop(
- l_iter, data->edgevec, data->fnos[BM_elem_index_get(l_iter->f)], v_no);
+ l_iter, e1diff, e2diff, data->fnos[BM_elem_index_get(l_iter->f)], v_no);
}
} while ((l_iter = l_iter->radial_next) != l_first);
}
@@ -213,24 +202,22 @@ static void bm_vert_calc_normals_with_coords_cb(void *userdata,
}
static void bm_mesh_verts_calc_normals(BMesh *bm,
- const float (*edgevec)[3],
const float (*fnos)[3],
const float (*vcos)[3],
float (*vnos)[3])
{
- BM_mesh_elem_index_ensure(bm, (BM_EDGE | BM_FACE) | ((vnos || vcos) ? BM_VERT : 0));
+ BM_mesh_elem_index_ensure(bm, BM_FACE | ((vnos || vcos) ? BM_VERT : 0));
TaskParallelSettings settings;
BLI_parallel_mempool_settings_defaults(&settings);
settings.use_threading = bm->totvert >= BM_OMP_LIMIT;
if (vcos == NULL) {
- BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_cb, (void *)edgevec, &settings);
+ BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_cb, NULL, &settings);
}
else {
BLI_assert(!ELEM(NULL, fnos, vnos));
BMVertsCalcNormalsWithCoordsData data = {
- .edgevec = edgevec,
.fnos = fnos,
.vcos = vcos,
.vnos = vnos,
@@ -253,25 +240,27 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata),
*
* Updates the normals of a mesh.
*/
-void BM_mesh_normals_update(BMesh *bm)
+void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
{
- float(*edgevec)[3] = MEM_mallocN(sizeof(*edgevec) * bm->totedge, __func__);
+ if (params->face_normals) {
+ /* Calculate all face normals. */
+ TaskParallelSettings settings;
+ BLI_parallel_mempool_settings_defaults(&settings);
+ settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
- /* Parallel mempool iteration does not allow generating indices inline anymore. */
- BM_mesh_elem_index_ensure(bm, (BM_EDGE | BM_FACE));
-
- /* Calculate all face normals. */
- TaskParallelSettings settings;
- BLI_parallel_mempool_settings_defaults(&settings);
- settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
-
- BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings);
-
- bm_mesh_edges_calc_vectors(bm, edgevec, NULL);
+ BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings);
+ }
/* Add weighted face normals to vertices, and normalize vert normals. */
- bm_mesh_verts_calc_normals(bm, edgevec, NULL, NULL, NULL);
- MEM_freeN(edgevec);
+ bm_mesh_verts_calc_normals(bm, NULL, NULL, NULL);
+}
+
+void BM_mesh_normals_update(BMesh *bm)
+{
+ BM_mesh_normals_update_ex(bm,
+ &(const struct BMeshNormalsUpdate_Params){
+ .face_normals = true,
+ });
}
/** \} */
@@ -287,99 +276,49 @@ static void bm_partial_faces_parallel_range_calc_normals_cb(
BM_face_calc_normal(f, f->no);
}
-static void bm_partial_edges_parallel_range_calc_vectors_cb(
- void *userdata, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- BMEdge *e = ((BMEdge **)((void **)userdata)[0])[iter];
- float *r_edgevec = ((float(*)[3])((void **)userdata)[1])[iter];
- sub_v3_v3v3(r_edgevec, e->v1->co, e->v2->co);
- normalize_v3(r_edgevec);
-}
-
static void bm_partial_verts_parallel_range_calc_normal_cb(
void *userdata, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
{
- BMVert *v = ((BMVert **)((void **)userdata)[0])[iter];
- const float(*edgevec)[3] = (const float(*)[3])((void **)userdata)[1];
- bm_vert_calc_normals_impl(edgevec, v);
+ BMVert *v = ((BMVert **)userdata)[iter];
+ bm_vert_calc_normals_impl(v);
}
/**
* A version of #BM_mesh_normals_update that updates a subset of geometry,
* used to avoid the overhead of updating everything.
*/
-void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpinfo)
+void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm),
+ const BMPartialUpdate *bmpinfo,
+ const struct BMeshNormalsUpdate_Params *params)
{
BLI_assert(bmpinfo->params.do_normals);
BMVert **verts = bmpinfo->verts;
- BMEdge **edges = bmpinfo->edges;
BMFace **faces = bmpinfo->faces;
const int verts_len = bmpinfo->verts_len;
- const int edges_len = bmpinfo->edges_len;
const int faces_len = bmpinfo->faces_len;
- float(*edgevec)[3] = MEM_mallocN(sizeof(*edgevec) * edges_len, __func__);
-
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
/* Faces. */
- BLI_task_parallel_range(
- 0, faces_len, faces, bm_partial_faces_parallel_range_calc_normals_cb, &settings);
-
- /* Temporarily override the edge indices,
- * storing the correct indices in the case they're not dirty.
- *
- * \note in most cases indices are modified and #BMesh.elem_index_dirty is set.
- * This is an exceptional case where indices are restored because the worst case downside
- * of marking the edge indices dirty would require a full loop over all edges to
- * correct the indices in other functions which need them to be valid.
- * When moving a few vertices on a high poly mesh setting and restoring connected
- * edges has very little overhead compared with restoring all edge indices. */
- int *edge_index_value = NULL;
- if ((bm->elem_index_dirty & BM_EDGE) == 0) {
- edge_index_value = MEM_mallocN(sizeof(*edge_index_value) * edges_len, __func__);
-
- for (int i = 0; i < edges_len; i++) {
- BMEdge *e = edges[i];
- edge_index_value[i] = BM_elem_index_get(e);
- BM_elem_index_set(e, i); /* set_dirty! (restore before this function exits). */
- }
- }
- else {
- for (int i = 0; i < edges_len; i++) {
- BMEdge *e = edges[i];
- BM_elem_index_set(e, i); /* set_dirty! (already dirty) */
- }
- }
-
- {
- /* Verts. */
-
- /* Compute normalized direction vectors for each edge.
- * Directions will be used for calculating the weights of the face normals on the vertex
- * normals. */
- void *data[2] = {edges, edgevec};
+ if (params->face_normals) {
BLI_task_parallel_range(
- 0, edges_len, data, bm_partial_edges_parallel_range_calc_vectors_cb, &settings);
-
- /* Calculate vertex normals. */
- data[0] = verts;
- BLI_task_parallel_range(
- 0, verts_len, data, bm_partial_verts_parallel_range_calc_normal_cb, &settings);
+ 0, faces_len, faces, bm_partial_faces_parallel_range_calc_normals_cb, &settings);
}
- if (edge_index_value != NULL) {
- for (int i = 0; i < edges_len; i++) {
- BMEdge *e = edges[i];
- BM_elem_index_set(e, edge_index_value[i]); /* set_ok (restore) */
- }
-
- MEM_freeN(edge_index_value);
- }
+ /* Verts. */
+ BLI_task_parallel_range(
+ 0, verts_len, verts, bm_partial_verts_parallel_range_calc_normal_cb, &settings);
+}
- MEM_freeN(edgevec);
+void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpinfo)
+{
+ BM_mesh_normals_update_with_partial_ex(bm,
+ bmpinfo,
+ &(const struct BMeshNormalsUpdate_Params){
+ .face_normals = true,
+ });
}
/** \} */
@@ -399,16 +338,8 @@ void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
float (*vnos)[3])
{
- float(*edgevec)[3] = MEM_mallocN(sizeof(*edgevec) * bm->totedge, __func__);
-
- /* Compute normalized direction vectors for each edge.
- * Directions will be used for calculating the weights of the face normals on the vertex normals.
- */
- bm_mesh_edges_calc_vectors(bm, edgevec, vcos);
-
/* Add weighted face normals to vertices, and normalize vert normals. */
- bm_mesh_verts_calc_normals(bm, edgevec, fnos, vcos, vnos);
- MEM_freeN(edgevec);
+ bm_mesh_verts_calc_normals(bm, fnos, vcos, vnos);
}
/** \} */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.h b/source/blender/bmesh/intern/bmesh_mesh_normals.h
index 41191340e9e..ecd627d4bfe 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.h
@@ -22,7 +22,19 @@
#include "bmesh_class.h"
+struct BMeshNormalsUpdate_Params {
+ /**
+ * When calculating tessellation as well as normals, tessellate & calculate face normals
+ * for improved performance. See #BMeshCalcTessellation_Params
+ */
+ bool face_normals;
+};
+
+void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update(BMesh *bm);
+void BM_mesh_normals_update_with_partial_ex(BMesh *bm,
+ const struct BMPartialUpdate *bmpinfo,
+ const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo);
void BM_verts_calc_normal_vcos(BMesh *bm,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
index 7b01b61d4fa..267705aa7c7 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
@@ -79,20 +79,6 @@ BLI_INLINE bool partial_elem_vert_ensure(BMPartialUpdate *bmpinfo,
return false;
}
-BLI_INLINE bool partial_elem_edge_ensure(BMPartialUpdate *bmpinfo,
- BLI_bitmap *edges_tag,
- BMEdge *e)
-{
- const int i = BM_elem_index_get(e);
- if (!BLI_BITMAP_TEST(edges_tag, i)) {
- BLI_BITMAP_ENABLE(edges_tag, i);
- GROW_ARRAY_AS_NEEDED(bmpinfo->edges, bmpinfo->edges_len_alloc, bmpinfo->edges_len);
- bmpinfo->edges[bmpinfo->edges_len++] = e;
- return true;
- }
- return false;
-}
-
BLI_INLINE bool partial_elem_face_ensure(BMPartialUpdate *bmpinfo,
BLI_bitmap *faces_tag,
BMFace *f)
@@ -121,17 +107,15 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
/* Reserve more edges than vertices since it's common for a grid topology
* to use around twice as many edges as vertices. */
const int default_verts_len_alloc = verts_len;
- const int default_edges_len_alloc = min_ii(bm->totedge, verts_len * 2);
const int default_faces_len_alloc = min_ii(bm->totface, verts_len);
/* Allocate tags instead of using #BM_ELEM_TAG because the caller may already be using tags.
* Further, walking over all geometry to clear the tags isn't so efficient. */
BLI_bitmap *verts_tag = NULL;
- BLI_bitmap *edges_tag = NULL;
BLI_bitmap *faces_tag = NULL;
/* Set vert inline. */
- BM_mesh_elem_index_ensure(bm, (BM_EDGE | BM_FACE));
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
if (params->do_normals || params->do_tessellate) {
/* - Extend to all vertices connected faces:
@@ -197,29 +181,12 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
verts_tag = BLI_BITMAP_NEW((size_t)bm->totvert, __func__);
}
- /* Edges. */
- if (bmpinfo->edges == NULL) {
- bmpinfo->edges_len_alloc = default_edges_len_alloc;
- bmpinfo->edges = MEM_mallocN((sizeof(BMEdge *) * bmpinfo->edges_len_alloc), __func__);
- edges_tag = BLI_BITMAP_NEW((size_t)bm->totedge, __func__);
- }
-
for (int i = 0; i < bmpinfo->faces_len; i++) {
BMFace *f = bmpinfo->faces[i];
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if (!partial_elem_vert_ensure(bmpinfo, verts_tag, l_iter->v)) {
- continue;
- }
- BMVert *v = l_iter->v;
- BMEdge *e_first = v->e;
- BMEdge *e_iter = e_first;
- do {
- if (e_iter->l) {
- partial_elem_edge_ensure(bmpinfo, edges_tag, e_iter);
- }
- } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+ partial_elem_vert_ensure(bmpinfo, verts_tag, l_iter->v);
} while ((l_iter = l_iter->next) != l_first);
}
}
@@ -227,9 +194,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
if (verts_tag) {
MEM_freeN(verts_tag);
}
- if (edges_tag) {
- MEM_freeN(edges_tag);
- }
if (faces_tag) {
MEM_freeN(faces_tag);
}
@@ -244,9 +208,6 @@ void BM_mesh_partial_destroy(BMPartialUpdate *bmpinfo)
if (bmpinfo->verts) {
MEM_freeN(bmpinfo->verts);
}
- if (bmpinfo->edges) {
- MEM_freeN(bmpinfo->edges);
- }
if (bmpinfo->faces) {
MEM_freeN(bmpinfo->faces);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
index b31ec127744..3dbfb985e92 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
@@ -44,10 +44,8 @@ typedef struct BMPartialUpdate_Params {
*/
typedef struct BMPartialUpdate {
BMVert **verts;
- BMEdge **edges;
BMFace **faces;
int verts_len, verts_len_alloc;
- int edges_len, edges_len_alloc;
int faces_len, faces_len_alloc;
/** Store the parameters used in creation so invalid use can be asserted. */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
index 7a95e52ce25..c9b027474e1 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
@@ -19,6 +19,8 @@
*
* This file contains code for polygon tessellation
* (creating triangles from polygons).
+ *
+ * \see mesh_tessellate.c for the #Mesh equivalent of this file.
*/
#include "DNA_meshdata_types.h"
@@ -50,10 +52,21 @@
/** \name Default Mesh Tessellation
* \{ */
-static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
- BMFace *efa,
- MemArena **pf_arena_p)
+/**
+ * \param face_normal: This will be optimized out as a constant.
+ */
+BLI_INLINE void bmesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3],
+ BMFace *efa,
+ MemArena **pf_arena_p,
+ const bool face_normal)
{
+#ifdef DEBUG
+ /* The face normal is used for projecting faces into 2D space for tessellation.
+ * Invalid normals may result in invalid tessellation.
+ * Either `face_normal` should be true or normals should be updated first. */
+ BLI_assert(face_normal || BM_face_is_normal_valid(efa));
+#endif
+
switch (efa->len) {
case 3: {
/* `0 1 2` -> `0 1 2` */
@@ -62,7 +75,10 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
l_ptr[1] = l = l->next;
l_ptr[2] = l->next;
- return 1;
+ if (face_normal) {
+ normal_tri_v3(efa->no, l_ptr[0]->v->co, l_ptr[1]->v->co, l_ptr[2]->v->co);
+ }
+ break;
}
case 4: {
/* `0 1 2 3` -> (`0 1 2`, `0 2 3`) */
@@ -74,15 +90,27 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
(l_ptr_a[2] = l_ptr_b[1] = l = l->next);
(l_ptr_b[2] = l->next);
- if (UNLIKELY(is_quad_flip_v3_first_third_fast(
- l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
+ if (face_normal) {
+ normal_quad_v3(
+ efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
+ }
+
+ if (UNLIKELY(is_quad_flip_v3_first_third_fast_with_normal(l_ptr_a[0]->v->co,
+ l_ptr_a[1]->v->co,
+ l_ptr_a[2]->v->co,
+ l_ptr_b[2]->v->co,
+ efa->no))) {
/* Flip out of degenerate 0-2 state. */
l_ptr_a[2] = l_ptr_b[2];
l_ptr_b[0] = l_ptr_a[1];
}
- return 2;
+ break;
}
default: {
+ if (face_normal) {
+ BM_face_calc_normal(efa, efa->no);
+ }
+
BMLoop *l_iter, *l_first;
BMLoop **l_arr;
@@ -123,18 +151,34 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
}
BLI_memarena_clear(pf_arena);
- return tris_len;
+ break;
}
}
}
+static void bmesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
+ BMFace *efa,
+ MemArena **pf_arena_p)
+{
+ bmesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, false);
+}
+
+static void bmesh_calc_tessellation_for_face_with_normal(BMLoop *(*looptris)[3],
+ BMFace *efa,
+ MemArena **pf_arena_p)
+{
+ bmesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, true);
+}
+
/**
* \brief BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh
* \param looptris:
*
* \note \a looptris Must be pre-allocated to at least the size of given by: poly_to_tri_count
*/
-static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, BMLoop *(*looptris)[3])
+static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const char face_normals)
{
#ifndef NDEBUG
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
@@ -146,9 +190,20 @@ static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, BMLoop *(*loop
MemArena *pf_arena = NULL;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BLI_assert(efa->len >= 3);
- i += mesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena);
+ if (face_normals) {
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BLI_assert(efa->len >= 3);
+ BM_face_calc_normal(efa, efa->no);
+ bmesh_calc_tessellation_for_face_with_normal(looptris + i, efa, &pf_arena);
+ i += efa->len - 2;
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BLI_assert(efa->len >= 3);
+ bmesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena);
+ i += efa->len - 2;
+ }
}
if (pf_arena) {
@@ -163,20 +218,32 @@ struct TessellationUserTLS {
MemArena *pf_arena;
};
-static void mesh_calc_tessellation_for_face_fn(void *__restrict userdata,
- MempoolIterData *mp_f,
- const TaskParallelTLS *__restrict tls)
+static void bmesh_calc_tessellation_for_face_fn(void *__restrict userdata,
+ MempoolIterData *mp_f,
+ const TaskParallelTLS *__restrict tls)
+{
+ struct TessellationUserTLS *tls_data = tls->userdata_chunk;
+ BMLoop *(*looptris)[3] = userdata;
+ BMFace *f = (BMFace *)mp_f;
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
+ bmesh_calc_tessellation_for_face(looptris + offset, f, &tls_data->pf_arena);
+}
+
+static void bmesh_calc_tessellation_for_face_with_normals_fn(void *__restrict userdata,
+ MempoolIterData *mp_f,
+ const TaskParallelTLS *__restrict tls)
{
struct TessellationUserTLS *tls_data = tls->userdata_chunk;
BMLoop *(*looptris)[3] = userdata;
BMFace *f = (BMFace *)mp_f;
BMLoop *l = BM_FACE_FIRST_LOOP(f);
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
- mesh_calc_tessellation_for_face(looptris + offset, f, &tls_data->pf_arena);
+ bmesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &tls_data->pf_arena);
}
-static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void bmesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
struct TessellationUserTLS *tls_data = tls_v;
if (tls_data->pf_arena) {
@@ -184,7 +251,9 @@ static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSE
}
}
-static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, BMLoop *(*looptris)[3])
+static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const char face_normals)
{
BM_mesh_elem_index_ensure(bm, BM_LOOP | BM_FACE);
@@ -193,20 +262,36 @@ static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, BMLoop *(*loopt
BLI_parallel_mempool_settings_defaults(&settings);
settings.userdata_chunk = &tls_dummy;
settings.userdata_chunk_size = sizeof(tls_dummy);
- settings.func_free = mesh_calc_tessellation_for_face_free_fn;
- BM_iter_parallel(bm, BM_FACES_OF_MESH, mesh_calc_tessellation_for_face_fn, looptris, &settings);
+ settings.func_free = bmesh_calc_tessellation_for_face_free_fn;
+ BM_iter_parallel(bm,
+ BM_FACES_OF_MESH,
+ face_normals ? bmesh_calc_tessellation_for_face_with_normals_fn :
+ bmesh_calc_tessellation_for_face_fn,
+ looptris,
+ &settings);
}
-void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3])
+void BM_mesh_calc_tessellation_ex(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const struct BMeshCalcTessellation_Params *params)
{
if (bm->totface < BM_FACE_TESSELLATE_THREADED_LIMIT) {
- bm_mesh_calc_tessellation__single_threaded(bm, looptris);
+ bm_mesh_calc_tessellation__single_threaded(bm, looptris, params->face_normals);
}
else {
- bm_mesh_calc_tessellation__multi_threaded(bm, looptris);
+ bm_mesh_calc_tessellation__multi_threaded(bm, looptris, params->face_normals);
}
}
+void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3])
+{
+ BM_mesh_calc_tessellation_ex(bm,
+ looptris,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = false,
+ });
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -222,19 +307,30 @@ struct PartialTessellationUserTLS {
MemArena *pf_arena;
};
-static void mesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata,
- const int index,
- const TaskParallelTLS *__restrict tls)
+static void bmesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata,
+ const int index,
+ const TaskParallelTLS *__restrict tls)
+{
+ struct PartialTessellationUserTLS *tls_data = tls->userdata_chunk;
+ struct PartialTessellationUserData *data = userdata;
+ BMFace *f = data->faces[index];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
+ bmesh_calc_tessellation_for_face(data->looptris + offset, f, &tls_data->pf_arena);
+}
+
+static void bmesh_calc_tessellation_for_face_partial_with_normals_fn(
+ void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls)
{
struct PartialTessellationUserTLS *tls_data = tls->userdata_chunk;
struct PartialTessellationUserData *data = userdata;
BMFace *f = data->faces[index];
BMLoop *l = BM_FACE_FIRST_LOOP(f);
const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
- mesh_calc_tessellation_for_face(data->looptris + offset, f, &tls_data->pf_arena);
+ bmesh_calc_tessellation_for_face_with_normal(data->looptris + offset, f, &tls_data->pf_arena);
}
-static void mesh_calc_tessellation_for_face_partial_free_fn(
+static void bmesh_calc_tessellation_for_face_partial_free_fn(
const void *__restrict UNUSED(userdata), void *__restrict tls_v)
{
struct PartialTessellationUserTLS *tls_data = tls_v;
@@ -243,8 +339,10 @@ static void mesh_calc_tessellation_for_face_partial_free_fn(
}
}
-static void bm_mesh_calc_tessellation_with_partial__multi_threaded(BMLoop *(*looptris)[3],
- const BMPartialUpdate *bmpinfo)
+static void bm_mesh_calc_tessellation_with_partial__multi_threaded(
+ BMLoop *(*looptris)[3],
+ const BMPartialUpdate *bmpinfo,
+ const struct BMeshCalcTessellation_Params *params)
{
const int faces_len = bmpinfo->faces_len;
BMFace **faces = bmpinfo->faces;
@@ -259,25 +357,42 @@ static void bm_mesh_calc_tessellation_with_partial__multi_threaded(BMLoop *(*loo
settings.use_threading = true;
settings.userdata_chunk = &tls_dummy;
settings.userdata_chunk_size = sizeof(tls_dummy);
- settings.func_free = mesh_calc_tessellation_for_face_partial_free_fn;
-
- BLI_task_parallel_range(
- 0, faces_len, &data, mesh_calc_tessellation_for_face_partial_fn, &settings);
+ settings.func_free = bmesh_calc_tessellation_for_face_partial_free_fn;
+
+ BLI_task_parallel_range(0,
+ faces_len,
+ &data,
+ params->face_normals ?
+ bmesh_calc_tessellation_for_face_partial_with_normals_fn :
+ bmesh_calc_tessellation_for_face_partial_fn,
+ &settings);
}
-static void bm_mesh_calc_tessellation_with_partial__single_threaded(BMLoop *(*looptris)[3],
- const BMPartialUpdate *bmpinfo)
+static void bm_mesh_calc_tessellation_with_partial__single_threaded(
+ BMLoop *(*looptris)[3],
+ const BMPartialUpdate *bmpinfo,
+ const struct BMeshCalcTessellation_Params *params)
{
const int faces_len = bmpinfo->faces_len;
BMFace **faces = bmpinfo->faces;
MemArena *pf_arena = NULL;
- for (int index = 0; index < faces_len; index++) {
- BMFace *f = faces[index];
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
- const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
- mesh_calc_tessellation_for_face(looptris + offset, f, &pf_arena);
+ if (params->face_normals) {
+ for (int index = 0; index < faces_len; index++) {
+ BMFace *f = faces[index];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
+ bmesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &pf_arena);
+ }
+ }
+ else {
+ for (int index = 0; index < faces_len; index++) {
+ BMFace *f = faces[index];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
+ bmesh_calc_tessellation_for_face(looptris + offset, f, &pf_arena);
+ }
}
if (pf_arena) {
@@ -285,22 +400,30 @@ static void bm_mesh_calc_tessellation_with_partial__single_threaded(BMLoop *(*lo
}
}
-void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
- BMLoop *(*looptris)[3],
- const BMPartialUpdate *bmpinfo)
+void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const BMPartialUpdate *bmpinfo,
+ const struct BMeshCalcTessellation_Params *params)
{
BLI_assert(bmpinfo->params.do_tessellate);
BM_mesh_elem_index_ensure(bm, BM_LOOP | BM_FACE);
if (bmpinfo->faces_len < BM_FACE_TESSELLATE_THREADED_LIMIT) {
- bm_mesh_calc_tessellation_with_partial__single_threaded(looptris, bmpinfo);
+ bm_mesh_calc_tessellation_with_partial__single_threaded(looptris, bmpinfo, params);
}
else {
- bm_mesh_calc_tessellation_with_partial__multi_threaded(looptris, bmpinfo);
+ bm_mesh_calc_tessellation_with_partial__multi_threaded(looptris, bmpinfo, params);
}
}
+void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const BMPartialUpdate *bmpinfo)
+{
+ BM_mesh_calc_tessellation_with_partial_ex(bm, looptris, bmpinfo, false);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -309,10 +432,10 @@ void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
* Avoid degenerate triangles.
* \{ */
-static int mesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
- BMFace *efa,
- MemArena **pf_arena_p,
- Heap **pf_heap_p)
+static int bmesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
+ BMFace *efa,
+ MemArena **pf_arena_p,
+ Heap **pf_heap_p)
{
switch (efa->len) {
case 3: {
@@ -442,7 +565,7 @@ void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3])
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BLI_assert(efa->len >= 3);
- i += mesh_calc_tessellation_for_face_beauty(looptris + i, efa, &pf_arena, &pf_heap);
+ i += bmesh_calc_tessellation_for_face_beauty(looptris + i, efa, &pf_arena, &pf_heap);
}
if (pf_arena) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
index f68a91cb988..9a6a20d7568 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
@@ -22,9 +22,25 @@
struct BMPartialUpdate;
+struct BMeshCalcTessellation_Params {
+ /**
+ * When calculating normals as well as tessellation, calculate normals after tessellation
+ * for improved performance. See #BMeshCalcTessellation_Params
+ */
+ bool face_normals;
+};
+
+void BM_mesh_calc_tessellation_ex(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const struct BMeshCalcTessellation_Params *params);
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
+
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
+void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ const struct BMPartialUpdate *bmpinfo,
+ const struct BMeshCalcTessellation_Params *params);
void BM_mesh_calc_tessellation_with_partial(BMesh *bm,
BMLoop *(*looptris)[3],
const struct BMPartialUpdate *bmpinfo);
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 76e32667804..548dba242bf 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -46,7 +46,7 @@
* </pre>
*
* This function can also collapse edges too
- * in cases when it cant merge into faces.
+ * in cases when it can't merge into faces.
*
* \par Example:
* <pre>
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 03655bccf1c..da407abfb21 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -699,7 +699,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
if (BM_edge_is_manifold(l_a->e)) {
l_a = l_a->radial_next;
}
- /* this wont have changed from the previous loop */
+ /* this won't have changed from the previous loop */
i++;
} while (l_a != e_first->l);
@@ -978,7 +978,7 @@ bool BM_vert_is_manifold(const BMVert *v)
/* start at the boundary */
l_first = e_iter->l;
boundary_num += 1;
- /* >2 boundaries cant be manifold */
+ /* >2 boundaries can't be manifold */
if (boundary_num == 3) {
return false;
}
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 5713c17e146..0a6540c0e5e 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -236,7 +236,7 @@ static void bridge_loop_pair(BMesh *bm,
if (UNLIKELY((len_squared_v3(el_dir) < eps) || ((fabsf(dot_a) < eps) && (fabsf(dot_b) < eps)))) {
/* in this case there is no depth between the two loops,
* eg: 2x 2d circles, one scaled smaller,
- * in this case 'el_dir' cant be used, just ensure we have matching flipping. */
+ * in this case 'el_dir' can't be used, just ensure we have matching flipping. */
if (dot_v3v3(BM_edgeloop_normal_get(el_store_a), BM_edgeloop_normal_get(el_store_b)) < 0.0f) {
BM_edgeloop_flip(bm, el_store_b);
}
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 0a08b340e87..ffdce943d9f 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -459,8 +459,10 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
/* Allocate array to store possible vertices that will be dissolved. */
- int boundary_verts_len = BMO_slot_map_count(dupeop.slots_out, "boundary_map.out");
- dissolve_verts = MEM_mallocN((size_t)boundary_verts_len * sizeof(*dissolve_verts), __func__);
+ int boundary_edges_len = BMO_slot_map_count(dupeop.slots_out, "boundary_map.out");
+ /* We do not know the real number of boundary vertices. */
+ int boundary_verts_len_maybe = 2 * boundary_edges_len;
+ dissolve_verts = MEM_mallocN(boundary_verts_len_maybe * sizeof(*dissolve_verts), __func__);
}
BMO_slot_copy(&dupeop, slots_out, "geom.out", op, slots_out, "geom.out");
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index 782fd98c2ea..e377fa6079b 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -154,8 +154,9 @@ void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op)
int face_tot;
BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
- BMO_slot_buffer_hflag_enable(
- bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); /* do inline */
+
+ /* do inline */
+ BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
/* now we can copy adjacent data */
face_tot = bmesh_face_attribute_fill(bm, use_normals, use_data);
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index 3311ffefb0d..b5f5e5e308b 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -138,7 +138,7 @@ static int recalc_face_normals_find_index(BMesh *bm,
* then the outer-most loop attached to that vertex.
*
* Important this is correctly detected,
- * where casting a ray from the center wont hit any loops past this one.
+ * where casting a ray from the center won't hit any loops past this one.
* Otherwise the result may be incorrect.
*/
for (i = 0; i < faces_len; i++) {
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index 38a27b811b0..16d7b79a028 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -244,7 +244,7 @@ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim)
el_store_other = BLI_ghash_lookup(vert_eloop_gh, v_other);
- /* in rare cases we cant find a match */
+ /* in rare cases we can't find a match */
if (el_store_other) {
pair_test.first = el_store;
pair_test.second = el_store_other;
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index cef97f20a6a..d39fb5e81f1 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -7361,7 +7361,6 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
{
float no_collide_offset = bp->offset + 1e6;
- float limit = no_collide_offset;
if (bp->offset == 0.0f) {
return no_collide_offset;
}
@@ -7373,8 +7372,7 @@ static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
if (kab <= 0.0f) {
return no_collide_offset;
}
- limit = la / kab;
- return limit;
+ return la / kab;
}
/**
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index e7d0fe6a0c6..8f03b86b859 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -368,7 +368,7 @@ static void bm_face_bisect_verts(
}
}
- /* Ideally wont happen, but it can for self intersecting faces. */
+ /* Ideally won't happen, but it can for self-intersecting faces. */
// BLI_assert(found == true);
/* In fact this simple test is good enough, test if the loops are adjacent. */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 869856d0c5b..82878c7618a 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -1285,6 +1285,11 @@ static bool bm_decim_edge_collapse(BMesh *bm,
* a vertex group is the usual source for this.
* \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
* \param symmetry_eps: Threshold when matching mirror verts.
+ *
+ * \note The caller is responsible for recalculating face and vertex normals.
+ * - Vertex normals are maintained while decimating,
+ * although they won't necessarily match the final recalculated normals.
+ * - Face normals are not maintained at all.
*/
void BM_mesh_decimate_collapse(BMesh *bm,
const float factor,
@@ -1367,7 +1372,7 @@ void BM_mesh_decimate_collapse(BMesh *bm,
/* handy to detect corruptions elsewhere */
BLI_assert(BM_elem_index_get(e) < tot_edge_orig);
- /* Under normal conditions wont be accessed again,
+ /* Under normal conditions won't be accessed again,
* but NULL just in case so we don't use freed node. */
eheap_table[BM_elem_index_get(e)] = NULL;
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 710d7f79637..cc980a81aad 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -560,8 +560,8 @@ static void bm_isect_tri_tri(
/* vert-vert
* --------- */
{
- /* first check in any verts are touching
- * (any case where we wont create new verts)
+ /* first check if any verts are touching
+ * (any case where we won't create new verts)
*/
uint i_a;
for (i_a = 0; i_a < 3; i_a++) {
@@ -1606,7 +1606,7 @@ bool BM_mesh_intersect(BMesh *bm,
for (node = s.vert_dissolve; node; node = node->next) {
BMVert *v = node->link;
if (BM_vert_is_edge_pair(v)) {
- /* we wont create degenerate faces from this */
+ /* we won't create degenerate faces from this */
bool ok = true;
/* would we create a 2-sided-face?
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 561b00544b5..c538d5b17cd 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -553,7 +553,8 @@ static void bm_uuidwalk_pass_add(UUIDWalk *uuidwalk,
static int bm_face_len_cmp(const void *v1, const void *v2)
{
- const BMFace *f1 = v1, *f2 = v2;
+ const BMFace *f1 = *((BMFace **)v1);
+ const BMFace *f2 = *((BMFace **)v2);
if (f1->len > f2->len) {
return 1;
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index 1c820db74f4..a3db93be033 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -63,7 +63,7 @@ static void bm_vert_boundary_tangent(
float tvec_a[3], tvec_b[3];
/* get 2 boundary edges, there should only _be_ 2,
- * in case there are more - results wont be valid of course */
+ * in case there are more - results won't be valid of course */
BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
if (e_a == NULL) {
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index 5a52d216117..857cbf0beee 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -62,6 +62,24 @@ constexpr int COM_data_type_num_channels(const DataType datatype)
constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType::Value);
constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color);
+constexpr float COM_VALUE_ZERO[1] = {0.0f};
+
+/**
+ * Utility to get data type for given number of channels.
+ */
+constexpr DataType COM_num_channels_data_type(const int num_channels)
+{
+ switch (num_channels) {
+ case 1:
+ return DataType::Value;
+ case 3:
+ return DataType::Vector;
+ case 4:
+ default:
+ return DataType::Color;
+ }
+}
+
// configurable items
// chunk size determination
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index 8c30d3215d7..44d3f059374 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -18,10 +18,31 @@
#include "COM_MemoryBuffer.h"
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf_types.h"
#include "MEM_guardedalloc.h"
+#define ASSERT_BUFFER_CONTAINS_AREA(buf, area) \
+ BLI_assert(BLI_rcti_inside_rcti(&(buf)->get_rect(), &(area)))
+
+#define ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(buf, area, x, y) \
+ BLI_assert((buf)->get_rect().xmin <= (x)); \
+ BLI_assert((buf)->get_rect().ymin <= (y)); \
+ BLI_assert((buf)->get_rect().xmax >= (x) + BLI_rcti_size_x(&(area))); \
+ BLI_assert((buf)->get_rect().ymax >= (y) + BLI_rcti_size_y(&(area)))
+
+#define ASSERT_VALID_ELEM_SIZE(buf, channel_offset, elem_size) \
+ BLI_assert((buf)->get_num_channels() <= (channel_offset) + (elem_size))
+
namespace blender::compositor {
+static rcti create_rect(const int width, const int height)
+{
+ rcti rect;
+ BLI_rcti_init(&rect, 0, width, 0, height);
+ return rect;
+}
+
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state)
{
m_rect = rect;
@@ -30,6 +51,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBuf
this->m_num_channels = COM_data_type_num_channels(memoryProxy->getDataType());
this->m_buffer = (float *)MEM_mallocN_aligned(
sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
+ owns_data_ = true;
this->m_state = state;
this->m_datatype = memoryProxy->getDataType();
@@ -44,12 +66,44 @@ MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect, bool is_a_single
this->m_num_channels = COM_data_type_num_channels(dataType);
this->m_buffer = (float *)MEM_mallocN_aligned(
sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
+ owns_data_ = true;
this->m_state = MemoryBufferState::Temporary;
this->m_datatype = dataType;
set_strides();
}
+/**
+ * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
+ * freeing it.
+ */
+MemoryBuffer::MemoryBuffer(
+ float *buffer, int num_channels, int width, int height, bool is_a_single_elem)
+ : MemoryBuffer(buffer, num_channels, create_rect(width, height), is_a_single_elem)
+{
+}
+
+/**
+ * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
+ * freeing given buffer.
+ */
+MemoryBuffer::MemoryBuffer(float *buffer,
+ const int num_channels,
+ const rcti &rect,
+ const bool is_a_single_elem)
+{
+ m_rect = rect;
+ m_is_a_single_elem = is_a_single_elem;
+ m_memoryProxy = nullptr;
+ m_num_channels = num_channels;
+ m_datatype = COM_num_channels_data_type(num_channels);
+ m_buffer = buffer;
+ owns_data_ = false;
+ m_state = MemoryBufferState::Temporary;
+
+ set_strides();
+}
+
MemoryBuffer::MemoryBuffer(const MemoryBuffer &src)
: MemoryBuffer(src.m_datatype, src.m_rect, false)
{
@@ -112,31 +166,195 @@ float MemoryBuffer::get_max_value(const rcti &rect) const
MemoryBuffer::~MemoryBuffer()
{
- if (this->m_buffer) {
+ if (this->m_buffer && owns_data_) {
MEM_freeN(this->m_buffer);
this->m_buffer = nullptr;
}
}
-void MemoryBuffer::fill_from(const MemoryBuffer &src)
+void MemoryBuffer::copy_from(const MemoryBuffer *src, const rcti &area)
{
- BLI_assert(!this->is_a_single_elem());
+ copy_from(src, area, area.xmin, area.ymin);
+}
+
+void MemoryBuffer::copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int to_x,
+ const int to_y)
+{
+ BLI_assert(this->get_num_channels() == src->get_num_channels());
+ copy_from(src, area, 0, src->get_num_channels(), to_x, to_y, 0);
+}
+
+void MemoryBuffer::copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int to_channel_offset)
+{
+ copy_from(src, area, channel_offset, elem_size, area.xmin, area.ymin, to_channel_offset);
+}
+
+void MemoryBuffer::copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int to_x,
+ const int to_y,
+ const int to_channel_offset)
+{
+ if (this->is_a_single_elem()) {
+ copy_single_elem_from(src, channel_offset, elem_size, to_channel_offset);
+ }
+ else if (!src->is_a_single_elem() && elem_size == src->get_num_channels() &&
+ elem_size == this->get_num_channels()) {
+ BLI_assert(to_channel_offset == 0);
+ BLI_assert(channel_offset == 0);
+ copy_rows_from(src, area, to_x, to_y);
+ }
+ else {
+ copy_elems_from(src, area, channel_offset, elem_size, to_x, to_y, to_channel_offset);
+ }
+}
+
+void MemoryBuffer::copy_from(const uchar *src, const rcti &area)
+{
+ copy_from(src, area, 0, this->get_num_channels(), this->get_num_channels(), 0);
+}
+
+void MemoryBuffer::copy_from(const uchar *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int elem_stride,
+ const int to_channel_offset)
+{
+ copy_from(
+ src, area, channel_offset, elem_size, elem_stride, area.xmin, area.ymin, to_channel_offset);
+}
+
+void MemoryBuffer::copy_from(const uchar *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int elem_stride,
+ const int to_x,
+ const int to_y,
+ const int to_channel_offset)
+{
+ ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(this, area, to_x, to_y);
+ ASSERT_VALID_ELEM_SIZE(this, to_channel_offset, elem_size);
+
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ const int src_row_stride = width * elem_stride;
+ const uchar *const src_start = src + area.ymin * src_row_stride + channel_offset;
+ for (int y = 0; y < height; y++) {
+ const uchar *from_elem = src_start + y * src_row_stride;
+ float *to_elem = &this->get_value(to_x, to_y + y, to_channel_offset);
+ const float *row_end = to_elem + width * this->elem_stride;
+ while (to_elem < row_end) {
+ for (int i = 0; i < elem_size; i++) {
+ to_elem[i] = ((float)from_elem[i]) * (1.0f / 255.0f);
+ }
+ to_elem += this->elem_stride;
+ from_elem += elem_stride;
+ }
+ }
+}
+
+static void colorspace_to_scene_linear(MemoryBuffer *buf, const rcti &area, ColorSpace *colorspace)
+{
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ float *out = buf->get_elem(area.xmin, area.ymin);
+ /* If area allows continuous memory do conversion in one step. Otherwise per row. */
+ if (buf->getWidth() == width) {
+ IMB_colormanagement_colorspace_to_scene_linear(
+ out, width, height, buf->get_num_channels(), colorspace, false);
+ }
+ else {
+ for (int y = 0; y < height; y++) {
+ IMB_colormanagement_colorspace_to_scene_linear(
+ out, width, 1, buf->get_num_channels(), colorspace, false);
+ out += buf->row_stride;
+ }
+ }
+}
+
+void MemoryBuffer::copy_from(const ImBuf *src, const rcti &area, const bool ensure_linear_space)
+{
+ copy_from(src, area, 0, this->get_num_channels(), 0, ensure_linear_space);
+}
- unsigned int otherY;
- unsigned int minX = MAX2(this->m_rect.xmin, src.m_rect.xmin);
- unsigned int maxX = MIN2(this->m_rect.xmax, src.m_rect.xmax);
- unsigned int minY = MAX2(this->m_rect.ymin, src.m_rect.ymin);
- unsigned int maxY = MIN2(this->m_rect.ymax, src.m_rect.ymax);
- int offset;
- int otherOffset;
+void MemoryBuffer::copy_from(const ImBuf *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int to_channel_offset,
+ const bool ensure_linear_space)
+{
+ copy_from(src,
+ area,
+ channel_offset,
+ elem_size,
+ area.xmin,
+ area.ymin,
+ to_channel_offset,
+ ensure_linear_space);
+}
- for (otherY = minY; otherY < maxY; otherY++) {
- otherOffset = src.get_coords_offset(minX, otherY);
- offset = this->get_coords_offset(minX, otherY);
- memcpy(&this->m_buffer[offset],
- &src.m_buffer[otherOffset],
- (maxX - minX) * this->m_num_channels * sizeof(float));
+void MemoryBuffer::copy_from(const ImBuf *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int to_x,
+ const int to_y,
+ const int to_channel_offset,
+ const bool ensure_linear_space)
+{
+ if (src->rect_float) {
+ const MemoryBuffer mem_buf(src->rect_float, src->channels, src->x, src->y, false);
+ copy_from(&mem_buf, area, channel_offset, elem_size, to_x, to_y, to_channel_offset);
}
+ else if (src->rect) {
+ const uchar *uc_buf = (uchar *)src->rect;
+ const int elem_stride = src->channels;
+ copy_from(uc_buf, area, channel_offset, elem_size, elem_stride, to_x, to_y, to_channel_offset);
+ if (ensure_linear_space) {
+ colorspace_to_scene_linear(this, area, src->rect_colorspace);
+ }
+ }
+ else {
+ /* Empty ImBuf source. Fill destination with empty values. */
+ const float *zero_elem = new float[elem_size]{0};
+ fill(area, to_channel_offset, zero_elem, elem_size);
+ delete[] zero_elem;
+ }
+}
+
+void MemoryBuffer::fill(const rcti &area, const float *value)
+{
+ fill(area, 0, value, this->get_num_channels());
+}
+
+void MemoryBuffer::fill(const rcti &area,
+ const int channel_offset,
+ const float *value,
+ const int value_size)
+{
+ const MemoryBuffer single_elem(const_cast<float *>(value), value_size, this->get_rect(), true);
+ copy_from(&single_elem, area, 0, value_size, area.xmin, area.ymin, channel_offset);
+}
+
+void MemoryBuffer::fill_from(const MemoryBuffer &src)
+{
+ rcti overlap;
+ overlap.xmin = MAX2(this->m_rect.xmin, src.m_rect.xmin);
+ overlap.xmax = MIN2(this->m_rect.xmax, src.m_rect.xmax);
+ overlap.ymin = MAX2(this->m_rect.ymin, src.m_rect.ymin);
+ overlap.ymax = MIN2(this->m_rect.ymax, src.m_rect.ymax);
+ copy_from(&src, overlap);
}
void MemoryBuffer::writePixel(int x, int y, const float color[4])
@@ -196,4 +414,70 @@ void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivat
}
}
+void MemoryBuffer::copy_single_elem_from(const MemoryBuffer *src,
+ const int channel_offset,
+ const int elem_size,
+ const int to_channel_offset)
+{
+ ASSERT_VALID_ELEM_SIZE(this, to_channel_offset, elem_size);
+ ASSERT_VALID_ELEM_SIZE(src, channel_offset, elem_size);
+ BLI_assert(this->is_a_single_elem());
+
+ float *to_elem = &this->get_value(
+ this->get_rect().xmin, this->get_rect().ymin, to_channel_offset);
+ const float *from_elem = &src->get_value(
+ src->get_rect().xmin, src->get_rect().ymin, channel_offset);
+ const int elem_bytes = elem_size * sizeof(float);
+ memcpy(to_elem, from_elem, elem_bytes);
+}
+
+void MemoryBuffer::copy_rows_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int to_x,
+ const int to_y)
+{
+ ASSERT_BUFFER_CONTAINS_AREA(src, area);
+ ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(this, area, to_x, to_y);
+ BLI_assert(this->get_num_channels() == src->get_num_channels());
+ BLI_assert(!this->is_a_single_elem());
+ BLI_assert(!src->is_a_single_elem());
+
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ const int row_bytes = this->get_num_channels() * width * sizeof(float);
+ for (int y = 0; y < height; y++) {
+ float *to_row = this->get_elem(to_x, to_y + y);
+ const float *from_row = src->get_elem(area.xmin, area.ymin + y);
+ memcpy(to_row, from_row, row_bytes);
+ }
+}
+
+void MemoryBuffer::copy_elems_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int to_x,
+ const int to_y,
+ const int to_channel_offset)
+{
+ ASSERT_BUFFER_CONTAINS_AREA(src, area);
+ ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(this, area, to_x, to_y);
+ ASSERT_VALID_ELEM_SIZE(this, to_channel_offset, elem_size);
+ ASSERT_VALID_ELEM_SIZE(src, channel_offset, elem_size);
+
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ const int elem_bytes = elem_size * sizeof(float);
+ for (int y = 0; y < height; y++) {
+ float *to_elem = &this->get_value(to_x, to_y + y, to_channel_offset);
+ const float *from_elem = &src->get_value(area.xmin, area.ymin + y, channel_offset);
+ const float *row_end = to_elem + width * this->elem_stride;
+ while (to_elem < row_end) {
+ memcpy(to_elem, from_elem, elem_bytes);
+ to_elem += this->elem_stride;
+ from_elem += src->elem_stride;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 97b220508e0..575bb2fe383 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -106,6 +106,11 @@ class MemoryBuffer {
*/
bool m_is_a_single_elem;
+ /**
+ * Whether MemoryBuffer owns buffer data.
+ */
+ bool owns_data_;
+
public:
/**
* \brief construct new temporarily MemoryBuffer for an area
@@ -117,6 +122,11 @@ class MemoryBuffer {
*/
MemoryBuffer(DataType datatype, const rcti &rect, bool is_a_single_elem = false);
+ MemoryBuffer(
+ float *buffer, int num_channels, int width, int height, bool is_a_single_elem = false);
+
+ MemoryBuffer(float *buffer, int num_channels, const rcti &rect, bool is_a_single_elem = false);
+
/**
* Copy constructor
*/
@@ -223,7 +233,7 @@ class MemoryBuffer {
return is_a_single_elem() ? 1 : getHeight();
}
- uint8_t get_num_channels()
+ uint8_t get_num_channels() const
{
return this->m_num_channels;
}
@@ -404,11 +414,58 @@ class MemoryBuffer {
return this->m_state == MemoryBufferState::Temporary;
}
+ void copy_from(const MemoryBuffer *src, const rcti &area);
+ void copy_from(const MemoryBuffer *src, const rcti &area, int to_x, int to_y);
+ void copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int to_channel_offset);
+ void copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int to_x,
+ int to_y,
+ int to_channel_offset);
+ void copy_from(const uchar *src, const rcti &area);
+ void copy_from(const uchar *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int elem_stride,
+ int to_channel_offset);
+ void copy_from(const uchar *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int elem_stride,
+ int to_x,
+ int to_y,
+ int to_channel_offset);
+ void copy_from(const struct ImBuf *src, const rcti &area, bool ensure_linear_space = false);
+ void copy_from(const struct ImBuf *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int to_channel_offset,
+ bool ensure_linear_space = false);
+ void copy_from(const struct ImBuf *src,
+ const rcti &src_area,
+ int channel_offset,
+ int elem_size,
+ int to_x,
+ int to_y,
+ int to_channel_offset,
+ bool ensure_linear_space = false);
+
+ void fill(const rcti &area, const float *value);
+ void fill(const rcti &area, int channel_offset, const float *value, int value_size);
/**
* \brief add the content from otherBuffer to this MemoryBuffer
* \param otherBuffer: source buffer
*
- * \note take care when running this on a new buffer since it wont fill in
+ * \note take care when running this on a new buffer since it won't fill in
* uninitialized values in areas where the buffers don't overlap.
*/
void fill_from(const MemoryBuffer &src);
@@ -452,6 +509,22 @@ class MemoryBuffer {
return get_memory_width() * get_memory_height();
}
+ void copy_single_elem_from(const MemoryBuffer *src,
+ int channel_offset,
+ int elem_size,
+ const int to_channel_offset);
+ void copy_rows_from(const MemoryBuffer *src,
+ const rcti &src_area,
+ const int to_x,
+ const int to_y);
+ void copy_elems_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int channel_offset,
+ const int elem_size,
+ const int to_x,
+ const int to_y,
+ const int to_channel_offset);
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
#endif
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
index c54c2edccb0..e6e98d69b36 100644
--- a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
@@ -5,21 +5,22 @@ namespace blender::compositor {
MultiThreadedOperation::MultiThreadedOperation()
{
- m_num_passes = 1;
+ num_passes_ = 1;
+ current_pass_ = 0;
flags.is_fullframe_operation = true;
}
void MultiThreadedOperation::update_memory_buffer(MemoryBuffer *output,
- const rcti &output_area,
- blender::Span<MemoryBuffer *> inputs,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
ExecutionSystem &exec_system)
{
- for (int current_pass = 0; current_pass < m_num_passes; current_pass++) {
- update_memory_buffer_started(output, output_area, inputs, exec_system, current_pass);
- exec_system.execute_work(output_area, [=, &exec_system](const rcti &split_rect) {
- update_memory_buffer_partial(output, split_rect, inputs, exec_system, current_pass);
+ for (current_pass_ = 0; current_pass_ < num_passes_; current_pass_++) {
+ update_memory_buffer_started(output, area, inputs);
+ exec_system.execute_work(area, [=](const rcti &split_rect) {
+ update_memory_buffer_partial(output, split_rect, inputs);
});
- update_memory_buffer_finished(output, output_area, inputs, exec_system, current_pass);
+ update_memory_buffer_finished(output, area, inputs);
}
}
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.h b/source/blender/compositor/intern/COM_MultiThreadedOperation.h
index 97c5fba4ead..ad09c4df089 100644
--- a/source/blender/compositor/intern/COM_MultiThreadedOperation.h
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.h
@@ -27,7 +27,11 @@ class MultiThreadedOperation : public NodeOperation {
/**
* Number of execution passes.
*/
- int m_num_passes;
+ int num_passes_;
+ /**
+ * Current execution pass.
+ */
+ int current_pass_;
protected:
MultiThreadedOperation();
@@ -36,37 +40,31 @@ class MultiThreadedOperation : public NodeOperation {
* Called before an update memory buffer pass is executed. Single-threaded calls.
*/
virtual void update_memory_buffer_started(MemoryBuffer *UNUSED(output),
- const rcti &UNUSED(output_rect),
- blender::Span<MemoryBuffer *> UNUSED(inputs),
- ExecutionSystem &UNUSED(exec_system),
- int UNUSED(current_pass))
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> UNUSED(inputs))
{
}
/**
- * Executes operation updating output memory buffer on output_rect area. Multi-threaded calls.
+ * Executes operation updating a memory buffer area. Multi-threaded calls.
*/
virtual void update_memory_buffer_partial(MemoryBuffer *output,
- const rcti &output_rect,
- blender::Span<MemoryBuffer *> inputs,
- ExecutionSystem &exec_system,
- int current_pass) = 0;
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) = 0;
/**
* Called after an update memory buffer pass is executed. Single-threaded calls.
*/
virtual void update_memory_buffer_finished(MemoryBuffer *UNUSED(output),
- const rcti &UNUSED(output_rect),
- blender::Span<MemoryBuffer *> UNUSED(inputs),
- ExecutionSystem &UNUSED(exec_system),
- int UNUSED(current_pass))
+ const rcti &UNUSED(area),
+ Span<MemoryBuffer *> UNUSED(inputs))
{
}
private:
void update_memory_buffer(MemoryBuffer *output,
- const rcti &output_area,
- blender::Span<MemoryBuffer *> inputs,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
ExecutionSystem &exec_system) override;
};
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc
index 83de8a751c4..b943ab6af7f 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cc
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -188,12 +188,12 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
* caller must clamp it.
* TODO: See if it's possible to use parameter overloading (input_id for example).
*
- * \param input_op_idx: Input operation index for which we want to calculate the area being read.
+ * \param input_idx: Input operation index for which we want to calculate the area being read.
* \param output_area: Area being rendered by this operation.
* \param r_input_area: Returned input operation area that needs to be read in order to render
* given output area.
*/
-void NodeOperation::get_area_of_interest(const int input_op_idx,
+void NodeOperation::get_area_of_interest(const int input_idx,
const rcti &output_area,
rcti &r_input_area)
{
@@ -203,7 +203,7 @@ void NodeOperation::get_area_of_interest(const int input_op_idx,
else {
/* Non full-frame operations never implement this method. To ensure correctness assume
* whole area is used. */
- NodeOperation *input_op = getInputOperation(input_op_idx);
+ NodeOperation *input_op = getInputOperation(input_idx);
BLI_rcti_init(&r_input_area, 0, input_op->getWidth(), 0, input_op->getHeight());
}
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 5c4d6dd19ba..5ae0aae67d5 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -578,7 +578,7 @@ class NodeOperation {
* Executes operation updating output memory buffer. Single-threaded calls.
*/
virtual void update_memory_buffer(MemoryBuffer *UNUSED(output),
- const rcti &UNUSED(output_area),
+ const rcti &UNUSED(area),
Span<MemoryBuffer *> UNUSED(inputs),
ExecutionSystem &UNUSED(exec_system))
{
@@ -587,7 +587,7 @@ class NodeOperation {
/**
* Get input operation area being read by this operation on rendering given output area.
*/
- virtual void get_area_of_interest(int input_op_idx, const rcti &output_area, rcti &r_input_area);
+ virtual void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area);
void get_area_of_interest(NodeOperation *input_op, const rcti &output_area, rcti &r_input_area);
/** \} */
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc
index cd0139fd18e..157ded943d6 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cc
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cc
@@ -411,8 +411,7 @@ static void threading_model_task_schedule(WorkPackage *package)
static void threading_model_task_start()
{
BLI_thread_local_create(g_thread_device);
- g_work_scheduler.task.pool = BLI_task_pool_create(
- nullptr, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ g_work_scheduler.task.pool = BLI_task_pool_create(nullptr, TASK_PRIORITY_HIGH);
}
static void threading_model_task_finish()
diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.h b/source/blender/compositor/nodes/COM_AntiAliasingNode.h
index d4a6d0d26dc..7d3dd750864 100644
--- a/source/blender/compositor/nodes/COM_AntiAliasingNode.h
+++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.h
@@ -25,8 +25,8 @@
namespace blender::compositor {
/**
- * @brief AntiAliasingNode
- * @ingroup Node
+ * \brief AntiAliasingNode
+ * \ingroup Node
*/
class AntiAliasingNode : public Node {
public:
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cc b/source/blender/compositor/nodes/COM_ImageNode.cc
index f0bfda0f40e..20476144efa 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cc
+++ b/source/blender/compositor/nodes/COM_ImageNode.cc
@@ -168,7 +168,7 @@ void ImageNode::convertToOperations(NodeConverter &converter,
if (index == 0 && operation) {
converter.addPreview(operation->getOutputSocket());
}
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && !(bnodeSocket->flag & SOCK_UNAVAIL)) {
for (NodeOutput *alphaSocket : getOutputSockets()) {
bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket();
if (!STREQ(bnodeAlphaSocket->name, "Alpha")) {
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cc b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
index 23d6f4b80c7..deccbb28f49 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cc
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
@@ -202,4 +202,72 @@ void *AntiAliasOperation::initializeTileData(rcti *rect)
return getInputOperation(0)->initializeTileData(rect);
}
+void AntiAliasOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ BLI_assert(input_idx == 0);
+ UNUSED_VARS_NDEBUG(input_idx);
+ r_input_area.xmax = output_area.xmax + 1;
+ r_input_area.xmin = output_area.xmin - 1;
+ r_input_area.ymax = output_area.ymax + 1;
+ r_input_area.ymin = output_area.ymin - 1;
+}
+
+void AntiAliasOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input = inputs[0];
+ const rcti &input_area = input->get_rect();
+ float ninepix[9];
+ for (int y = area.ymin; y < area.ymax; y++) {
+ float *out = output->get_elem(area.xmin, y);
+ const float *row_curr = input->get_elem(area.xmin, y);
+ const float *row_prev = row_curr - input->row_stride;
+ const float *row_next = row_curr + input->row_stride;
+ int x_offset = 0;
+ for (int x = area.xmin; x < area.xmax;
+ x++, out += output->elem_stride, x_offset += input->elem_stride) {
+ if (x == input_area.xmin || x == input_area.xmax - 1 || y == input_area.xmin ||
+ y == input_area.ymax - 1) {
+ out[0] = row_curr[x_offset];
+ continue;
+ }
+
+ if (extrapolate9(&ninepix[0],
+ &ninepix[1],
+ &ninepix[2],
+ &ninepix[3],
+ &ninepix[4],
+ &ninepix[5],
+ &ninepix[6],
+ &ninepix[7],
+ &ninepix[8],
+ &row_prev[x_offset - input->elem_stride],
+ &row_prev[x_offset],
+ &row_prev[x_offset + input->elem_stride],
+ &row_curr[x_offset - input->elem_stride],
+ &row_curr[x_offset],
+ &row_curr[x_offset + input->elem_stride],
+ &row_next[x_offset - input->elem_stride],
+ &row_next[x_offset],
+ &row_next[x_offset + input->elem_stride])) {
+ /* Some rounding magic to make weighting correct with the
+ * original coefficients. */
+ unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] +
+ 5 * ninepix[3] + 6 * ninepix[4] + 5 * ninepix[5] +
+ 3 * ninepix[6] + 5 * ninepix[7] + 3 * ninepix[8]) *
+ 255.0f +
+ 19.0f) /
+ 38.0f;
+ out[0] = result / 255.0f;
+ }
+ else {
+ out[0] = row_curr[x_offset];
+ }
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.h b/source/blender/compositor/operations/COM_AntiAliasOperation.h
index fc9102b5b4c..b5048248425 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.h
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.h
@@ -18,7 +18,7 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_node_types.h"
namespace blender::compositor {
@@ -28,7 +28,7 @@ namespace blender::compositor {
* it only supports anti aliasing on BW buffers.
* \ingroup operation
*/
-class AntiAliasOperation : public NodeOperation {
+class AntiAliasOperation : public MultiThreadedOperation {
protected:
/**
* \brief Cached reference to the reader
@@ -57,6 +57,12 @@ class AntiAliasOperation : public NodeOperation {
bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output) override;
+
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cc b/source/blender/compositor/operations/COM_IDMaskOperation.cc
index 1bb247e9bc5..38f8b7e075f 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc
@@ -42,4 +42,22 @@ void IDMaskOperation::executePixel(float output[4], int x, int y, void *data)
output[0] = (roundf(buffer[buffer_index]) == this->m_objectIndex) ? 1.0f : 0.0f;
}
+void IDMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ const MemoryBuffer *input = inputs[0];
+ const int width = BLI_rcti_size_x(&area);
+ for (int y = area.ymin; y < area.ymax; y++) {
+ float *out = output->get_elem(area.xmin, y);
+ const float *in = input->get_elem(area.xmin, y);
+ const float *row_end = out + width * output->elem_stride;
+ while (out < row_end) {
+ out[0] = (roundf(in[0]) == m_objectIndex) ? 1.0f : 0.0f;
+ in += input->elem_stride;
+ out += output->elem_stride;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.h b/source/blender/compositor/operations/COM_IDMaskOperation.h
index 79b7e53b67c..c2e13641b46 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.h
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.h
@@ -18,11 +18,11 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class IDMaskOperation : public NodeOperation {
+class IDMaskOperation : public MultiThreadedOperation {
private:
float m_objectIndex;
@@ -36,6 +36,10 @@ class IDMaskOperation : public NodeOperation {
{
this->m_objectIndex = objectIndex;
}
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cc b/source/blender/compositor/operations/COM_ImageOperation.cc
index a1d401d4499..e78d389410f 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cc
+++ b/source/blender/compositor/operations/COM_ImageOperation.cc
@@ -44,6 +44,7 @@ BaseImageOperation::BaseImageOperation()
this->m_imageheight = 0;
this->m_framenumber = 0;
this->m_depthBuffer = nullptr;
+ depth_buffer_ = nullptr;
this->m_numberOfChannels = 0;
this->m_rd = nullptr;
this->m_viewName = nullptr;
@@ -91,6 +92,9 @@ void BaseImageOperation::initExecution()
this->m_imageFloatBuffer = stackbuf->rect_float;
this->m_imageByteBuffer = stackbuf->rect;
this->m_depthBuffer = stackbuf->zbuf_float;
+ if (stackbuf->zbuf_float) {
+ depth_buffer_ = new MemoryBuffer(stackbuf->zbuf_float, 1, stackbuf->x, stackbuf->y);
+ }
this->m_imagewidth = stackbuf->x;
this->m_imageheight = stackbuf->y;
this->m_numberOfChannels = stackbuf->channels;
@@ -102,6 +106,10 @@ void BaseImageOperation::deinitExecution()
this->m_imageFloatBuffer = nullptr;
this->m_imageByteBuffer = nullptr;
BKE_image_release_ibuf(this->m_image, this->m_buffer, nullptr);
+ if (depth_buffer_) {
+ delete depth_buffer_;
+ depth_buffer_ = nullptr;
+ }
}
void BaseImageOperation::determineResolution(unsigned int resolution[2],
@@ -170,6 +178,13 @@ void ImageOperation::executePixelSampled(float output[4], float x, float y, Pixe
}
}
+void ImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ output->copy_from(m_buffer, area, true);
+}
+
void ImageAlphaOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -187,6 +202,13 @@ void ImageAlphaOperation::executePixelSampled(float output[4],
}
}
+void ImageAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ output->copy_from(m_buffer, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
+}
+
void ImageDepthOperation::executePixelSampled(float output[4],
float x,
float y,
@@ -206,4 +228,16 @@ void ImageDepthOperation::executePixelSampled(float output[4],
}
}
+void ImageDepthOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ if (depth_buffer_) {
+ output->copy_from(depth_buffer_, area);
+ }
+ else {
+ output->fill(area, COM_VALUE_ZERO);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h
index 58373663db5..f8b4239c9f8 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.h
+++ b/source/blender/compositor/operations/COM_ImageOperation.h
@@ -21,7 +21,7 @@
#include "BKE_image.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "MEM_guardedalloc.h"
#include "RE_pipeline.h"
@@ -32,14 +32,17 @@ namespace blender::compositor {
/**
* \brief Base class for all image operations
*/
-class BaseImageOperation : public NodeOperation {
+class BaseImageOperation : public MultiThreadedOperation {
protected:
ImBuf *m_buffer;
Image *m_image;
ImageUser *m_imageUser;
+ /* TODO: Remove raw buffers when removing Tiled implementation. */
float *m_imageFloatBuffer;
unsigned int *m_imageByteBuffer;
float *m_depthBuffer;
+
+ MemoryBuffer *depth_buffer_;
int m_imageheight;
int m_imagewidth;
int m_framenumber;
@@ -87,6 +90,10 @@ class ImageOperation : public BaseImageOperation {
*/
ImageOperation();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class ImageAlphaOperation : public BaseImageOperation {
public:
@@ -95,6 +102,10 @@ class ImageAlphaOperation : public BaseImageOperation {
*/
ImageAlphaOperation();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class ImageDepthOperation : public BaseImageOperation {
public:
@@ -103,6 +114,10 @@ class ImageDepthOperation : public BaseImageOperation {
*/
ImageDepthOperation();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
index 647e93225e5..3a5de944a00 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
@@ -51,6 +51,13 @@ ImBuf *MultilayerBaseOperation::getImBuf()
return nullptr;
}
+void MultilayerBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ output->copy_from(m_buffer, area);
+}
+
std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData()
{
BLI_assert(this->m_buffer);
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
index 6e6062cf854..a682ca1941c 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
@@ -37,6 +37,10 @@ class MultilayerBaseOperation : public BaseImageOperation {
* Constructor
*/
MultilayerBaseOperation(RenderLayer *render_layer, RenderPass *render_pass, int view);
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class MultilayerColorOperation : public MultilayerBaseOperation {
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc
index dbe45fa60db..79dee33e266 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cc
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cc
@@ -24,6 +24,7 @@ SetColorOperation::SetColorOperation()
{
this->addOutputSocket(DataType::Color);
flags.is_set_operation = true;
+ flags.is_fullframe_operation = true;
}
void SetColorOperation::executePixelSampled(float output[4],
@@ -41,4 +42,14 @@ void SetColorOperation::determineResolution(unsigned int resolution[2],
resolution[1] = preferredResolution[1];
}
+void SetColorOperation::update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs),
+ ExecutionSystem &UNUSED(exec_system))
+{
+ BLI_assert(output->is_a_single_elem());
+ float *out_elem = output->get_elem(area.xmin, area.ymin);
+ copy_v4_v4(out_elem, m_color);
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h
index 4b9b80013d4..2e22ef60ba4 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.h
+++ b/source/blender/compositor/operations/COM_SetColorOperation.h
@@ -80,6 +80,11 @@ class SetColorOperation : public NodeOperation {
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) override;
+
+ void update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
+ ExecutionSystem &exec_system) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cc b/source/blender/compositor/operations/COM_SetValueOperation.cc
index ef43cf64653..359647c8fe3 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cc
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cc
@@ -24,6 +24,7 @@ SetValueOperation::SetValueOperation()
{
this->addOutputSocket(DataType::Value);
flags.is_set_operation = true;
+ flags.is_fullframe_operation = true;
}
void SetValueOperation::executePixelSampled(float output[4],
@@ -41,4 +42,14 @@ void SetValueOperation::determineResolution(unsigned int resolution[2],
resolution[1] = preferredResolution[1];
}
+void SetValueOperation::update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs),
+ ExecutionSystem &UNUSED(exec_system))
+{
+ BLI_assert(output->is_a_single_elem());
+ float *out_elem = output->get_elem(area.xmin, area.ymin);
+ *out_elem = m_value;
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h
index 5383f3b5fd3..acde5aa03b7 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.h
+++ b/source/blender/compositor/operations/COM_SetValueOperation.h
@@ -51,6 +51,10 @@ class SetValueOperation : public NodeOperation {
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) override;
+ void update_memory_buffer(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs,
+ ExecutionSystem &exec_system) override;
};
} // namespace blender::compositor
diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c
index f4f510891e0..7f1d90f20ea 100644
--- a/source/blender/datatoc/datatoc_icon.c
+++ b/source/blender/datatoc/datatoc_icon.c
@@ -66,9 +66,9 @@ static bool path_test_extension(const char *str, const char *ext)
return !(a == 0 || b == 0 || b >= a) && (strcmp(ext, str + a - b) == 0);
}
-static void endian_switch_uint32(unsigned int *val)
+static void endian_switch_uint32(uint *val)
{
- unsigned int tval = *val;
+ uint tval = *val;
*val = ((tval >> 24)) | ((tval << 8) & 0x00ff0000) | ((tval >> 8) & 0x0000ff00) | ((tval << 24));
}
@@ -96,10 +96,7 @@ static const char *path_basename(const char *path)
/* -------------------------------------------------------------------- */
/* Write a PNG from RGBA pixels */
-static bool write_png(const char *name,
- const unsigned int *pixels,
- const int width,
- const int height)
+static bool write_png(const char *name, const uint *pixels, const int width, const int height)
{
png_structp png_ptr;
png_infop info_ptr;
@@ -199,9 +196,9 @@ static bool write_png(const char *name,
/* Merge icon-data from files */
struct IconHead {
- unsigned int icon_w, icon_h;
- unsigned int orig_x, orig_y;
- unsigned int canvas_w, canvas_h;
+ uint icon_w, icon_h;
+ uint orig_x, orig_y;
+ uint canvas_w, canvas_h;
};
struct IconInfo {
@@ -289,10 +286,10 @@ static bool icon_decode_head(FILE *f_src, struct IconHead *r_head)
return false;
}
-static bool icon_decode(FILE *f_src, struct IconHead *r_head, unsigned int **r_pixels)
+static bool icon_decode(FILE *f_src, struct IconHead *r_head, uint **r_pixels)
{
- unsigned int *pixels;
- unsigned int pixels_size;
+ uint *pixels;
+ uint pixels_size;
if (!icon_decode_head(f_src, r_head)) {
printf("%s: failed to read header\n", __func__);
@@ -316,7 +313,7 @@ static bool icon_decode(FILE *f_src, struct IconHead *r_head, unsigned int **r_p
return true;
}
-static bool icon_read(const char *file_src, struct IconHead *r_head, unsigned int **r_pixels)
+static bool icon_read(const char *file_src, struct IconHead *r_head, uint **r_pixels)
{
FILE *f_src;
bool success;
@@ -335,18 +332,18 @@ static bool icon_read(const char *file_src, struct IconHead *r_head, unsigned in
static bool icon_merge(struct IconMergeContext *context,
const char *file_src,
- unsigned int **r_pixels_canvas,
- unsigned int *r_canvas_w,
- unsigned int *r_canvas_h)
+ uint32_t **r_pixels_canvas,
+ uint *r_canvas_w,
+ uint *r_canvas_h)
{
struct IconHead head;
- unsigned int *pixels;
+ uint *pixels;
- unsigned int x, y;
+ uint x, y;
/* canvas */
- unsigned int *pixels_canvas;
- unsigned int canvas_w, canvas_h;
+ uint32_t *pixels_canvas;
+ uint canvas_w, canvas_h;
if (!icon_read(file_src, &head, &pixels)) {
return false;
@@ -365,7 +362,7 @@ static bool icon_merge(struct IconMergeContext *context,
/* init once */
*r_canvas_w = head.canvas_w;
*r_canvas_h = head.canvas_h;
- *r_pixels_canvas = calloc(1, (head.canvas_w * head.canvas_h) * sizeof(const unsigned char[4]));
+ *r_pixels_canvas = calloc(1, (head.canvas_w * head.canvas_h) * sizeof(uint32_t));
}
canvas_w = *r_canvas_w;
@@ -377,9 +374,9 @@ static bool icon_merge(struct IconMergeContext *context,
for (x = 0; x < head.icon_w; x++) {
for (y = 0; y < head.icon_h; y++) {
- unsigned int pixel;
- unsigned int dst_x, dst_y;
- unsigned int pixel_xy_dst;
+ uint pixel;
+ uint dst_x, dst_y;
+ uint pixel_xy_dst;
/* get pixel */
pixel = pixels[(y * head.icon_w) + x];
@@ -413,8 +410,8 @@ static bool icondir_to_png(const char *path_src, const char *file_dst)
struct IconMergeContext context;
- unsigned int *pixels_canvas = NULL;
- unsigned int canvas_w = 0, canvas_h = 0;
+ uint32_t *pixels_canvas = NULL;
+ uint canvas_w = 0, canvas_h = 0;
icon_merge_context_init(&context);
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 740124f6113..27441c9a7ae 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -109,11 +109,11 @@ void DEG_free_node_types(void);
/* Update Tagging -------------------------------- */
-/* Update dependency graph when visible scenes/layers changes. */
-void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph, const bool do_time);
+/* Tag dependency graph for updates when visible scenes/layers changes. */
+void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time);
-/* Update all dependency graphs when visible scenes/layers changes. */
-void DEG_on_visible_update(struct Main *bmain, const bool do_time);
+/* Tag all dependency graphs for update when visible scenes/layers changes. */
+void DEG_tag_on_visible_update(struct Main *bmain, const bool do_time);
/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations
* when recalc flag has been removed. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index ae530cc010e..3ab278b0c4c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -450,6 +450,22 @@ void DepsgraphNodeBuilder::update_invalid_cow_pointers()
/* Node/ID already tagged for COW flush, no need to check it. */
continue;
}
+ if ((id_node->id_cow->flag & LIB_EMBEDDED_DATA) != 0) {
+ /* For now, we assume embedded data are managed by their owner IDs and do not need to be
+ * checked here.
+ *
+ * NOTE: This exception somewhat weak, and ideally should not be needed. Currently however,
+ * embedded data are handled as full local (private) data of their owner IDs in part of
+ * Blender (like read/write code, including undo/redo), while depsgraph generally treat them
+ * as regular independent IDs. This leads to inconsistencies that can lead to bad level
+ * memory accesses.
+ *
+ * E.g. when undoing creation/deletion of a collection directly child of a scene's master
+ * collection, the scene itself is re-read in place, but its master collection becomes a
+ * completely new different pointer, and the existing COW of the old master collection in the
+ * matching deg node is therefore pointing to fully invalid (freed) memory. */
+ continue;
+ }
BKE_library_foreach_ID_link(nullptr,
id_node->id_cow,
deg::foreach_id_cow_detect_need_for_update_callback,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 32c36d78250..e4591e2e994 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -421,7 +421,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
if (prev) {
OperationCode opcode = OperationCode::BONE_DONE;
/* Inheriting parent roll requires access to prev handle's B-Bone properties. */
- if ((pchan->bone->flag & BONE_ADD_PARENT_END_ROLL) != 0 &&
+ if ((pchan->bone->bbone_flag & BBONE_ADD_PARENT_END_ROLL) != 0 &&
check_pchan_has_bbone_segments(object, prev)) {
opcode = OperationCode::BONE_SEGMENTS;
}
diff --git a/source/blender/depsgraph/intern/builder/pipeline.cc b/source/blender/depsgraph/intern/builder/pipeline.cc
index 10bc7213061..28e4c973c1e 100644
--- a/source/blender/depsgraph/intern/builder/pipeline.cc
+++ b/source/blender/depsgraph/intern/builder/pipeline.cc
@@ -98,7 +98,7 @@ void AbstractBuilderPipeline::build_step_finalize()
deg_graph_->scene_cow = (Scene *)deg_graph_->get_cow_id(&deg_graph_->scene->id);
/* Flush visibility layer and re-schedule nodes for update. */
deg_graph_build_finalize(bmain_, deg_graph_);
- DEG_graph_on_visible_update(bmain_, reinterpret_cast<::Depsgraph *>(deg_graph_), false);
+ DEG_graph_tag_on_visible_update(reinterpret_cast<::Depsgraph *>(deg_graph_), false);
#if 0
if (!DEG_debug_consistency_check(deg_graph_)) {
printf("Consistency validation failed, ABORTING!\n");
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 8e1ab23fae0..6fe7d5f5d8b 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -62,6 +62,8 @@ namespace blender::deg {
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
need_update(true),
+ need_visibility_update(true),
+ need_visibility_time_update(false),
bmain(bmain),
scene(scene),
view_layer(view_layer),
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index b87ce94709a..ff536c19c05 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -108,6 +108,11 @@ struct Depsgraph {
/* Indicates whether relations needs to be updated. */
bool need_update;
+ /* Indicated whether IDs in this graph are to be tagged as if they first appear visible, with
+ * an optional tag for their animation (time) update. */
+ bool need_visibility_update;
+ bool need_visibility_time_update;
+
/* Indicates which ID types were updated. */
char id_type_updated[INDEX_ID_MAX];
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 204143d7cbd..78c5a0c7a13 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -500,8 +500,23 @@ void deg_graph_node_tag_zero(Main *bmain,
deg_graph_id_tag_legacy_compat(bmain, graph, id, (IDRecalcFlag)0, update_source);
}
-void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_time)
+void graph_tag_on_visible_update(Depsgraph *graph, const bool do_time)
{
+ graph->need_visibility_update = true;
+ graph->need_visibility_time_update |= do_time;
+}
+
+} /* namespace */
+
+void graph_tag_ids_for_visible_update(Depsgraph *graph)
+{
+ if (!graph->need_visibility_update) {
+ return;
+ }
+
+ const bool do_time = graph->need_visibility_time_update;
+ Main *bmain = graph->bmain;
+
/* NOTE: It is possible to have this function called with `do_time=false` first and later (prior
* to evaluation though) with `do_time=true`. This means early output checks should be aware of
* this. */
@@ -559,9 +574,10 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti
* dependency graph. */
id_node->previously_visible_components_mask = id_node->visible_components_mask;
}
-}
-} /* namespace */
+ graph->need_visibility_update = false;
+ graph->need_visibility_time_update = false;
+}
NodeType geometry_tag_to_component(const ID *id)
{
@@ -804,16 +820,16 @@ void DEG_id_type_tag(Main *bmain, short id_type)
}
/* Update dependency graph when visible scenes/layers changes. */
-void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool do_time)
+void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
- deg::deg_graph_on_visible_update(bmain, graph, do_time);
+ deg::graph_tag_on_visible_update(graph, do_time);
}
-void DEG_on_visible_update(Main *bmain, const bool do_time)
+void DEG_tag_on_visible_update(Main *bmain, const bool do_time)
{
for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) {
- DEG_graph_on_visible_update(bmain, reinterpret_cast<::Depsgraph *>(depsgraph), do_time);
+ deg::graph_tag_on_visible_update(depsgraph, do_time);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.h b/source/blender/depsgraph/intern/depsgraph_tag.h
index 68b6a164be4..70504840fef 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.h
+++ b/source/blender/depsgraph/intern/depsgraph_tag.h
@@ -41,5 +41,9 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source);
void graph_id_tag_update(
Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source);
+/* Tag IDs of the graph for the visibility update tags.
+ * Will do nothing if the graph is not tagged for visibility update. */
+void graph_tag_ids_for_visible_update(Depsgraph *graph);
+
} // namespace deg
} // namespace blender
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 2107e075139..6f35143e28f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -45,6 +45,7 @@
#include "intern/depsgraph.h"
#include "intern/depsgraph_relation.h"
+#include "intern/depsgraph_tag.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/eval/deg_eval_flush.h"
#include "intern/eval/deg_eval_stats.h"
@@ -353,8 +354,7 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
return BLI_task_pool_create_no_threads(state);
}
- /* TODO: Disable task isolation. */
- return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH);
}
/**
@@ -366,6 +366,8 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
*/
void deg_evaluate_on_refresh(Depsgraph *graph)
{
+ graph_tag_ids_for_visible_update(graph);
+
/* Nothing to update, early out. */
if (graph->entry_tags.is_empty()) {
return;
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 e5d7bd70214..0d367762b00 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
@@ -320,7 +320,6 @@ bool id_copy_inplace_no_main(const ID *id, ID *newid)
* is already allocated. */
bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
{
- const ID *id_for_copy = &scene->id;
if (G.debug & G_DEBUG_DEPSGRAPH_UUID) {
SEQ_relations_check_uuids_unique_and_report(scene);
@@ -328,9 +327,10 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
#ifdef NESTED_ID_NASTY_WORKAROUND
NestedIDHackTempStorage id_hack_storage;
- id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, &scene->id);
+ const ID *id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, &scene->id);
+#else
+ const ID *id_for_copy = &scene->id;
#endif
-
bool result = (BKE_id_copy_ex(nullptr,
id_for_copy,
(ID **)&new_scene,
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 3938242eb6e..4f68c3fdc7e 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -85,6 +85,7 @@ set(SRC
intern/draw_manager_text.c
intern/draw_manager_texture.c
intern/draw_select_buffer.c
+ intern/draw_shader.c
intern/draw_view.c
engines/basic/basic_engine.c
engines/image/image_engine.c
@@ -172,6 +173,7 @@ set(SRC
intern/DRW_render.h
intern/draw_cache.h
intern/draw_cache_extract.h
+ intern/draw_cache_extract_mesh_private.h
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_color_management.h
@@ -184,6 +186,7 @@ set(SRC
intern/draw_manager_testing.h
intern/draw_manager_text.h
intern/draw_view.h
+ intern/draw_shader.h
intern/smaa_textures.h
engines/basic/basic_engine.h
engines/eevee/eevee_engine.h
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index 21d55357a2a..315133186da 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -397,7 +397,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData
unit_m4(uv_mat);
zero_v2(wave_ofs);
- /* We reset the uv_mat so we need to account for the rotation in the */
+ /* Reset the `uv_mat` to account for rotation in the Y-axis (Shadow-V parameter). */
copy_v2_fl2(tmp, 0.0f, blur_size[1]);
rotate_v2_v2fl(blur_dir, tmp, -fx->rotation);
mul_v2_v2(blur_dir, vp_size_inv);
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index fbad60ff4ab..e6c3248b6c4 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -1167,21 +1167,28 @@ static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_B
param.roll1 = ebone->roll1;
param.roll2 = ebone->roll2;
- if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
+ if (prev && (ebone->bbone_flag & BBONE_ADD_PARENT_END_ROLL)) {
param.roll1 += prev->roll2;
}
- param.scale_in_x = ebone->scale_in_x;
- param.scale_in_y = ebone->scale_in_y;
-
- param.scale_out_x = ebone->scale_out_x;
- param.scale_out_y = ebone->scale_out_y;
+ copy_v3_v3(param.scale_in, ebone->scale_in);
+ copy_v3_v3(param.scale_out, ebone->scale_out);
param.curve_in_x = ebone->curve_in_x;
- param.curve_in_y = ebone->curve_in_y;
+ param.curve_in_z = ebone->curve_in_z;
param.curve_out_x = ebone->curve_out_x;
- param.curve_out_y = ebone->curve_out_y;
+ param.curve_out_z = ebone->curve_out_z;
+
+ if (ebone->bbone_flag & BBONE_SCALE_EASING) {
+ param.ease1 *= param.scale_in[1];
+ param.curve_in_x *= param.scale_in[1];
+ param.curve_in_z *= param.scale_in[1];
+
+ param.ease2 *= param.scale_out[1];
+ param.curve_out_x *= param.scale_out[1];
+ param.curve_out_z *= param.scale_out[1];
+ }
ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
}
@@ -2011,7 +2018,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
((draw_ctx->object_mode == OB_MODE_OBJECT) &&
(scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
/* Allow selection when in weight-paint mode
- * (selection code ensures this wont become active). */
+ * (selection code ensures this won't become active). */
((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) &&
(draw_ctx->object_pose != NULL))))) &&
DRW_state_is_select();
@@ -2063,9 +2070,8 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
set_pchan_colorset(ctx, ob, pchan);
}
- int boneflag = bone->flag;
/* catch exception for bone with hidden parent */
- boneflag = bone->flag;
+ int boneflag = bone->flag;
if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
boneflag &= ~BONE_CONNECTED;
}
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index 19f822e3f68..81b07b49784 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -324,7 +324,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
!is_select;
const bool draw_fade = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FADE_INACTIVE) &&
overlay_should_fade_object(ob, draw_ctx->obact);
- const bool draw_mode_transfer = draw_surface && (pd->overlay.flag & V3D_OVERLAY_MODE_TRANSFER);
+ const bool draw_mode_transfer = draw_surface;
const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
const bool draw_wires = draw_surface && has_surface &&
(pd->wireframe_mode || !pd->hide_overlays);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 304cae1d2dc..5fc6629e804 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -83,8 +83,9 @@ typedef enum eMRDataType {
MR_DATA_LOOPTRI = 1 << 3,
/** Force loop normals calculation. */
MR_DATA_TAN_LOOP_NOR = 1 << 4,
+ MR_DATA_MAT_OFFSETS = 1 << 5,
} eMRDataType;
-ENUM_OPERATORS(eMRDataType, MR_DATA_TAN_LOOP_NOR)
+ENUM_OPERATORS(eMRDataType, MR_DATA_MAT_OFFSETS)
#ifdef __cplusplus
extern "C" {
@@ -160,46 +161,19 @@ typedef struct MeshBufferCache {
* - Loose geometry.
*/
typedef struct MeshBufferExtractionCache {
- int edge_loose_len;
- int vert_loose_len;
- int *lverts;
- int *ledges;
-} MeshBufferExtractionCache;
+ struct {
+ int edge_len;
+ int vert_len;
+ int *verts;
+ int *edges;
+ } loose_geom;
-typedef enum DRWBatchFlag {
- MBC_SURFACE = (1 << 0),
- MBC_SURFACE_WEIGHTS = (1 << 1),
- MBC_EDIT_TRIANGLES = (1 << 2),
- MBC_EDIT_VERTICES = (1 << 3),
- MBC_EDIT_EDGES = (1 << 4),
- MBC_EDIT_VNOR = (1 << 5),
- MBC_EDIT_LNOR = (1 << 6),
- MBC_EDIT_FACEDOTS = (1 << 7),
- MBC_EDIT_MESH_ANALYSIS = (1 << 8),
- MBC_EDITUV_FACES_STRETCH_AREA = (1 << 9),
- MBC_EDITUV_FACES_STRETCH_ANGLE = (1 << 10),
- MBC_EDITUV_FACES = (1 << 11),
- MBC_EDITUV_EDGES = (1 << 12),
- MBC_EDITUV_VERTS = (1 << 13),
- MBC_EDITUV_FACEDOTS = (1 << 14),
- MBC_EDIT_SELECTION_VERTS = (1 << 15),
- MBC_EDIT_SELECTION_EDGES = (1 << 16),
- MBC_EDIT_SELECTION_FACES = (1 << 17),
- MBC_EDIT_SELECTION_FACEDOTS = (1 << 18),
- MBC_ALL_VERTS = (1 << 19),
- MBC_ALL_EDGES = (1 << 20),
- MBC_LOOSE_EDGES = (1 << 21),
- MBC_EDGE_DETECTION = (1 << 22),
- MBC_WIRE_EDGES = (1 << 23),
- MBC_WIRE_LOOPS = (1 << 24),
- MBC_WIRE_LOOPS_UVS = (1 << 25),
- MBC_SKIN_ROOTS = (1 << 26),
- MBC_SCULPT_OVERLAYS = (1 << 27),
-} DRWBatchFlag;
+ struct {
+ int *tri;
+ int visible_tri_len;
+ } mat_offsets;
-#define MBC_EDITUV \
- (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
- MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
+} MeshBufferExtractionCache;
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
for (MeshBufferCache *mbc = &batch_cache->final; \
@@ -253,8 +227,8 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
- DRWBatchFlag batch_requested;
- DRWBatchFlag batch_ready;
+ uint32_t batch_requested; /* DRWBatchFlag */
+ uint32_t batch_ready; /* DRWBatchFlag */
/* settings to determine if cache is invalid */
int edge_len;
@@ -288,6 +262,48 @@ typedef struct MeshBatchCache {
#define MBC_VBO_LEN (sizeof(((MeshBufferCache){0}).vbo) / sizeof(void *))
#define MBC_IBO_LEN (sizeof(((MeshBufferCache){0}).ibo) / sizeof(void *))
+#define MBC_BATCH_INDEX(batch_name) \
+ ((offsetof(MeshBatchCache, batch_name) - offsetof(MeshBatchCache, batch.surface)) / \
+ sizeof(void *))
+
+typedef enum DRWBatchFlag {
+ MBC_SURFACE = (1u << MBC_BATCH_INDEX(batch.surface)),
+ MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(batch.surface_weights)),
+ MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(batch.edit_triangles)),
+ MBC_EDIT_VERTICES = (1u << MBC_BATCH_INDEX(batch.edit_vertices)),
+ MBC_EDIT_EDGES = (1u << MBC_BATCH_INDEX(batch.edit_edges)),
+ MBC_EDIT_VNOR = (1u << MBC_BATCH_INDEX(batch.edit_vnor)),
+ MBC_EDIT_LNOR = (1u << MBC_BATCH_INDEX(batch.edit_lnor)),
+ MBC_EDIT_FACEDOTS = (1u << MBC_BATCH_INDEX(batch.edit_fdots)),
+ MBC_EDIT_MESH_ANALYSIS = (1u << MBC_BATCH_INDEX(batch.edit_mesh_analysis)),
+ MBC_SKIN_ROOTS = (1u << MBC_BATCH_INDEX(batch.edit_skin_roots)),
+ MBC_EDITUV_FACES_STRETCH_AREA = (1u << MBC_BATCH_INDEX(batch.edituv_faces_stretch_area)),
+ MBC_EDITUV_FACES_STRETCH_ANGLE = (1u << MBC_BATCH_INDEX(batch.edituv_faces_stretch_angle)),
+ MBC_EDITUV_FACES = (1u << MBC_BATCH_INDEX(batch.edituv_faces)),
+ MBC_EDITUV_EDGES = (1u << MBC_BATCH_INDEX(batch.edituv_edges)),
+ MBC_EDITUV_VERTS = (1u << MBC_BATCH_INDEX(batch.edituv_verts)),
+ MBC_EDITUV_FACEDOTS = (1u << MBC_BATCH_INDEX(batch.edituv_fdots)),
+ MBC_EDIT_SELECTION_VERTS = (1u << MBC_BATCH_INDEX(batch.edit_selection_verts)),
+ MBC_EDIT_SELECTION_EDGES = (1u << MBC_BATCH_INDEX(batch.edit_selection_edges)),
+ MBC_EDIT_SELECTION_FACES = (1u << MBC_BATCH_INDEX(batch.edit_selection_faces)),
+ MBC_EDIT_SELECTION_FACEDOTS = (1u << MBC_BATCH_INDEX(batch.edit_selection_fdots)),
+ MBC_ALL_VERTS = (1u << MBC_BATCH_INDEX(batch.all_verts)),
+ MBC_ALL_EDGES = (1u << MBC_BATCH_INDEX(batch.all_edges)),
+ MBC_LOOSE_EDGES = (1u << MBC_BATCH_INDEX(batch.loose_edges)),
+ MBC_EDGE_DETECTION = (1u << MBC_BATCH_INDEX(batch.edge_detection)),
+ MBC_WIRE_EDGES = (1u << MBC_BATCH_INDEX(batch.wire_edges)),
+ MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(batch.wire_loops)),
+ MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(batch.wire_loops_uvs)),
+ MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(batch.sculpt_overlays)),
+} DRWBatchFlag;
+
+BLI_STATIC_ASSERT(MBC_BATCH_INDEX(surface_per_mat) < 32,
+ "Number of batches exceeded the limit of bit fields");
+
+#define MBC_EDITUV \
+ (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
+ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
+
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 6b5877e6759..e577069f000 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -50,8 +50,6 @@
# include "PIL_time_utildefines.h"
#endif
-#define CHUNK_SIZE 8192
-
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -65,26 +63,12 @@ struct ExtractorRunData {
const MeshExtract *extractor;
/* During iteration the VBO/IBO that is being build. */
void *buffer = nullptr;
- /* User data during iteration. Created in MeshExtract.init and passed along to other MeshExtract
- * functions. */
- void *user_data = nullptr;
- std::optional<Array<void *>> task_user_datas;
+ uint32_t data_offset = 0;
ExtractorRunData(const MeshExtract *extractor) : extractor(extractor)
{
}
- void init_task_user_datas(const TaskLen task_len)
- {
- task_user_datas = Array<void *>(task_len);
- }
-
- void *&operator[](const TaskId task_id)
- {
- BLI_assert(task_user_datas);
- return (*task_user_datas)[task_id];
- }
-
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DRAW:ExtractorRunData")
#endif
@@ -140,7 +124,7 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
return iter_type;
}
- const uint iter_types_len() const
+ uint iter_types_len() const
{
const eMRIterType iter_type = iter_types();
uint bits = static_cast<uint>(iter_type);
@@ -157,6 +141,16 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
return data_type;
}
+ size_t data_size_total()
+ {
+ size_t data_size = 0;
+ for (const ExtractorRunData &data : *this) {
+ const MeshExtract *extractor = data.extractor;
+ data_size += extractor->data_size;
+ }
+ return data_size;
+ }
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DRAW:ExtractorRunDatas")
#endif
@@ -165,446 +159,334 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Extract
+/** \name ExtractTaskData
+ * \{ */
+struct ExtractTaskData {
+ const MeshRenderData *mr = nullptr;
+ MeshBatchCache *cache = nullptr;
+ ExtractorRunDatas *extractors = nullptr;
+ MeshBufferCache *mbc = nullptr;
+
+ eMRIterType iter_type;
+ bool use_threading = false;
+
+ ExtractTaskData(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ ExtractorRunDatas *extractors,
+ MeshBufferCache *mbc,
+ const bool use_threading)
+ : mr(mr), cache(cache), extractors(extractors), mbc(mbc), use_threading(use_threading)
+ {
+ iter_type = extractors->iter_types();
+ };
+
+ ExtractTaskData(const ExtractTaskData &src) = default;
+
+ ~ExtractTaskData()
+ {
+ delete extractors;
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("DRW:ExtractTaskData")
+#endif
+};
+
+static void extract_task_data_free(void *data)
+{
+ ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
+ delete task_data;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Init and Finish
* \{ */
BLI_INLINE void extract_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
ExtractorRunDatas &extractors,
- MeshBufferCache *mbc)
+ MeshBufferCache *mbc,
+ void *data_stack)
{
- /* Multi thread. */
+ uint32_t data_offset = 0;
for (ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
run_data.buffer = mesh_extract_buffer_get(extractor, mbc);
- run_data.user_data = extractor->init(mr, cache, run_data.buffer);
+ run_data.data_offset = data_offset;
+ extractor->init(mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, data_offset));
+ data_offset += (uint32_t)extractor->data_size;
}
}
-BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr,
- const ExtractTriBMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+BLI_INLINE void extract_finish(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ const ExtractorRunDatas &extractors,
+ void *data_stack)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_LOOPTRI);
-
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_looptri_bm(mr, elt, elt_index, run_data[task_id]);
+ for (const ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ if (extractor->finish) {
+ extractor->finish(
+ mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, run_data.data_offset));
}
}
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
}
-BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr,
- const ExtractTriMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
-{
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract In Parallel Ranges
+ * \{ */
+
+struct ExtractorIterData {
ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_LOOPTRI);
+ const MeshRenderData *mr = nullptr;
+ const void *elems = nullptr;
+ const int *loose_elems = nullptr;
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data[task_id]);
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData")
+#endif
+};
+
+static void extract_task_reduce(const void *__restrict userdata,
+ void *__restrict chunk_to,
+ void *__restrict chunk_from)
+{
+ const ExtractorIterData *data = static_cast<const ExtractorIterData *>(userdata);
+ for (const ExtractorRunData &run_data : data->extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ if (extractor->task_reduce) {
+ extractor->task_reduce(POINTER_OFFSET(chunk_to, run_data.data_offset),
+ POINTER_OFFSET(chunk_from, run_data.data_offset));
}
}
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
}
-BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+static void extract_range_iter_looptri_bm(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_POLY);
-
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_poly_bm(mr, f, f_index, run_data[task_id]);
- }
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ void *extract_data = tls->userdata_chunk;
+ const MeshRenderData *mr = data->mr;
+ BMLoop **elt = ((BMLoop * (*)[3]) data->elems)[iter];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_looptri_bm(
+ mr, elt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
- EXTRACT_POLY_FOREACH_BM_END;
}
-BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+static void extract_range_iter_looptri_mesh(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_POLY);
+ void *extract_data = tls->userdata_chunk;
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_poly_mesh(mr, mp, mp_index, run_data[task_id]);
- }
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const MLoopTri *mlt = &((const MLoopTri *)data->elems)[iter];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_looptri_mesh(
+ mr, mlt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
- EXTRACT_POLY_FOREACH_MESH_END;
}
-BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+static void extract_range_iter_poly_bm(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_LEDGE);
+ void *extract_data = tls->userdata_chunk;
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_ledge_bm(mr, eed, ledge_index, run_data[task_id]);
- }
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const BMFace *f = ((const BMFace **)data->elems)[iter];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_poly_bm(
+ mr, f, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
- EXTRACT_LEDGE_FOREACH_BM_END;
}
-BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+static void extract_range_iter_poly_mesh(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_LEDGE);
+ void *extract_data = tls->userdata_chunk;
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_ledge_mesh(mr, med, ledge_index, run_data[task_id]);
- }
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const MPoly *mp = &((const MPoly *)data->elems)[iter];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_poly_mesh(
+ mr, mp, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
- EXTRACT_LEDGE_FOREACH_MESH_END;
}
-BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+static void extract_range_iter_ledge_bm(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_LVERT);
+ void *extract_data = tls->userdata_chunk;
- EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_lvert_bm(mr, eve, lvert_index, run_data[task_id]);
- }
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const int ledge_index = data->loose_elems[iter];
+ const BMEdge *eed = ((const BMEdge **)data->elems)[ledge_index];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_ledge_bm(
+ mr, eed, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
- EXTRACT_LVERT_FOREACH_BM_END;
}
-BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
- const ExtractorRunDatas &all_extractors,
- const TaskId task_id)
+static void extract_range_iter_ledge_mesh(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- ExtractorRunDatas extractors;
- all_extractors.filter_into(extractors, MR_ITER_LVERT);
+ void *extract_data = tls->userdata_chunk;
- EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
- {
- for (ExtractorRunData &run_data : extractors) {
- run_data.extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data[task_id]);
- }
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const int ledge_index = data->loose_elems[iter];
+ const MEdge *med = &((const MEdge *)data->elems)[ledge_index];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_ledge_mesh(
+ mr, med, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
- EXTRACT_LVERT_FOREACH_MESH_END;
}
-BLI_INLINE void extract_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- const ExtractorRunDatas &extractors)
+static void extract_range_iter_lvert_bm(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- for (const ExtractorRunData &run_data : extractors) {
- const MeshExtract *extractor = run_data.extractor;
- if (extractor->finish) {
- extractor->finish(mr, cache, run_data.buffer, run_data.user_data);
- }
+ void *extract_data = tls->userdata_chunk;
+
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const int lvert_index = data->loose_elems[iter];
+ const BMVert *eve = ((const BMVert **)data->elems)[lvert_index];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_lvert_bm(
+ mr, eve, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
-BLI_INLINE void extract_task_init(ExtractorRunDatas &extractors, const TaskLen task_len)
+static void extract_range_iter_lvert_mesh(void *__restrict userdata,
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
{
- for (ExtractorRunData &run_data : extractors) {
- run_data.init_task_user_datas(task_len);
- const MeshExtract *extractor = run_data.extractor;
- for (TaskId task_id = 0; task_id < task_len; task_id++) {
- void *user_task_data = run_data.user_data;
- if (extractor->task_init) {
- user_task_data = extractor->task_init(run_data.user_data);
- }
- run_data[task_id] = user_task_data;
- }
+ void *extract_data = tls->userdata_chunk;
+
+ const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
+ const MeshRenderData *mr = data->mr;
+ const int lvert_index = data->loose_elems[iter];
+ const MVert *mv = &((const MVert *)data->elems)[lvert_index];
+ for (const ExtractorRunData &run_data : data->extractors) {
+ run_data.extractor->iter_lvert_mesh(
+ mr, mv, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
-BLI_INLINE void extract_task_finish(ExtractorRunDatas &extractors, const TaskLen task_len)
+BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr,
+ ExtractorRunDatas *extractors,
+ const eMRIterType iter_type,
+ bool is_mesh,
+ TaskParallelSettings *settings)
{
- for (ExtractorRunData &run_data : extractors) {
- const MeshExtract *extractor = run_data.extractor;
- if (extractor->task_finish) {
- for (TaskId task_id = 0; task_id < task_len; task_id++) {
- void *task_user_data = run_data[task_id];
- extractor->task_finish(run_data.user_data, task_user_data);
- run_data[task_id] = nullptr;
- }
- }
+ ExtractorIterData range_data;
+ range_data.mr = mr;
+
+ TaskParallelRangeFunc func;
+ int stop;
+ switch (iter_type) {
+ case MR_ITER_LOOPTRI:
+ range_data.elems = is_mesh ? mr->mlooptri : (void *)mr->edit_bmesh->looptris;
+ func = is_mesh ? extract_range_iter_looptri_mesh : extract_range_iter_looptri_bm;
+ stop = mr->tri_len;
+ break;
+ case MR_ITER_POLY:
+ range_data.elems = is_mesh ? mr->mpoly : (void *)mr->bm->ftable;
+ func = is_mesh ? extract_range_iter_poly_mesh : extract_range_iter_poly_bm;
+ stop = mr->poly_len;
+ break;
+ case MR_ITER_LEDGE:
+ range_data.loose_elems = mr->ledges;
+ range_data.elems = is_mesh ? mr->medge : (void *)mr->bm->etable;
+ func = is_mesh ? extract_range_iter_ledge_mesh : extract_range_iter_ledge_bm;
+ stop = mr->edge_loose_len;
+ break;
+ case MR_ITER_LVERT:
+ range_data.loose_elems = mr->lverts;
+ range_data.elems = is_mesh ? mr->mvert : (void *)mr->bm->vtable;
+ func = is_mesh ? extract_range_iter_lvert_mesh : extract_range_iter_lvert_bm;
+ stop = mr->vert_loose_len;
+ break;
+ default:
+ BLI_assert(false);
+ return;
}
+
+ extractors->filter_into(range_data.extractors, iter_type);
+ BLI_task_parallel_range(0, stop, &range_data, func, settings);
}
-/* Single Thread. */
-BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- ExtractorRunDatas &extractors,
- eMRIterType iter_type,
- MeshBufferCache *mbc)
+static void extract_task_range_run(void *__restrict taskdata)
{
- const TaskLen task_len = 1;
- const TaskId task_id = 0;
+ ExtractTaskData *data = (ExtractTaskData *)taskdata;
+ const eMRIterType iter_type = data->iter_type;
+ const bool is_mesh = data->mr->extract_type != MR_EXTRACT_BMESH;
+
+ size_t userdata_chunk_size = data->extractors->data_size_total();
+ void *userdata_chunk = MEM_callocN(userdata_chunk_size, __func__);
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = data->use_threading;
+ settings.userdata_chunk = userdata_chunk;
+ settings.userdata_chunk_size = userdata_chunk_size;
+ settings.func_reduce = extract_task_reduce;
+ settings.min_iter_per_thread = MIN_RANGE_LEN;
- extract_init(mr, cache, extractors, mbc);
- extract_task_init(extractors, task_len);
+ extract_init(data->mr, data->cache, *data->extractors, data->mbc, userdata_chunk);
- bool is_mesh = mr->extract_type != MR_EXTRACT_BMESH;
if (iter_type & MR_ITER_LOOPTRI) {
- if (is_mesh) {
- ExtractTriMesh_Params params;
- params.mlooptri = mr->mlooptri;
- params.tri_range[0] = 0;
- params.tri_range[1] = mr->tri_len;
- extract_iter_looptri_mesh(mr, &params, extractors, task_id);
- }
- else {
- ExtractTriBMesh_Params params;
- params.looptris = mr->edit_bmesh->looptris;
- params.tri_range[0] = 0;
- params.tri_range[1] = mr->tri_len;
- extract_iter_looptri_bm(mr, &params, extractors, task_id);
- }
+ extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LOOPTRI, is_mesh, &settings);
}
if (iter_type & MR_ITER_POLY) {
- if (is_mesh) {
- ExtractPolyMesh_Params params;
- params.poly_range[0] = 0;
- params.poly_range[1] = mr->poly_len;
- extract_iter_poly_mesh(mr, &params, extractors, task_id);
- }
- else {
- ExtractPolyBMesh_Params params;
- params.poly_range[0] = 0;
- params.poly_range[1] = mr->poly_len;
- extract_iter_poly_bm(mr, &params, extractors, task_id);
- }
+ extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_POLY, is_mesh, &settings);
}
if (iter_type & MR_ITER_LEDGE) {
- if (is_mesh) {
- ExtractLEdgeMesh_Params params;
- params.ledge = mr->ledges;
- params.ledge_range[0] = 0;
- params.ledge_range[1] = mr->edge_loose_len;
- extract_iter_ledge_mesh(mr, &params, extractors, task_id);
- }
- else {
- ExtractLEdgeBMesh_Params params;
- params.ledge = mr->ledges;
- params.ledge_range[0] = 0;
- params.ledge_range[1] = mr->edge_loose_len;
- extract_iter_ledge_bm(mr, &params, extractors, task_id);
- }
+ extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LEDGE, is_mesh, &settings);
}
if (iter_type & MR_ITER_LVERT) {
- if (is_mesh) {
- ExtractLVertMesh_Params params;
- params.lvert = mr->lverts;
- params.lvert_range[0] = 0;
- params.lvert_range[1] = mr->vert_loose_len;
- extract_iter_lvert_mesh(mr, &params, extractors, task_id);
- }
- else {
- ExtractLVertBMesh_Params params;
- params.lvert = mr->lverts;
- params.lvert_range[0] = 0;
- params.lvert_range[1] = mr->vert_loose_len;
- extract_iter_lvert_bm(mr, &params, extractors, task_id);
- }
+ extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LVERT, is_mesh, &settings);
}
- extract_task_finish(extractors, task_len);
- extract_finish(mr, cache, extractors);
+
+ extract_finish(data->mr, data->cache, *data->extractors, userdata_chunk);
+ MEM_freeN(userdata_chunk);
}
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name ExtractTaskData
+/** \name Extract In Parallel Ranges
* \{ */
-struct ExtractTaskData {
- const MeshRenderData *mr = nullptr;
- MeshBatchCache *cache = nullptr;
- /* #UserData is shared between the iterations as it holds counters to detect if the
- * extraction is finished. To make sure the duplication of the user_data does not create a new
- * instance of the counters we allocate the user_data in its own container.
- *
- * This structure makes sure that when extract_init is called, that the user data of all
- * iterations are updated. */
-
- ExtractorRunDatas *extractors = nullptr;
- MeshBufferCache *mbc = nullptr;
- int32_t *task_counter = nullptr;
-
- /* Total number of tasks that are created for multi threaded extraction.
- * (= 1 for single threaded extractors). */
- uint task_len;
- /* Task id of the extraction task. Must never exceed task_len. (= 0 for single threaded
- * extractors). */
- uint task_id = 0;
-
- eMRIterType iter_type;
- int start = 0;
- int end = INT_MAX;
- /** Decremented each time a task is finished. */
-
- ExtractTaskData(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- ExtractorRunDatas *extractors,
- MeshBufferCache *mbc,
- int32_t *task_counter,
- const uint task_len)
- : mr(mr),
- cache(cache),
- extractors(extractors),
- mbc(mbc),
- task_counter(task_counter),
- task_len(task_len)
- {
- iter_type = extractors->iter_types();
- };
-
- ExtractTaskData(const ExtractTaskData &src) = default;
-
- ~ExtractTaskData()
- {
- delete extractors;
- }
-
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("DRW:ExtractTaskData")
-#endif
-};
-
-static void extract_task_data_free(void *data)
-{
- ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
- delete task_data;
-}
-
-static void extract_task_data_free_ex(void *data)
-{
- ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
- task_data->extractors = nullptr;
- delete task_data;
-}
-
-BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
- const eMRIterType iter_type,
- int start,
- int end,
- ExtractorRunDatas &extractors,
- const TaskId task_id)
-{
- switch (mr->extract_type) {
- case MR_EXTRACT_BMESH:
- if (iter_type & MR_ITER_LOOPTRI) {
- ExtractTriBMesh_Params params;
- params.looptris = mr->edit_bmesh->looptris;
- params.tri_range[0] = start;
- params.tri_range[1] = min_ii(mr->tri_len, end);
- extract_iter_looptri_bm(mr, &params, extractors, task_id);
- }
- if (iter_type & MR_ITER_POLY) {
- ExtractPolyBMesh_Params params;
- params.poly_range[0] = start;
- params.poly_range[1] = min_ii(mr->poly_len, end);
- extract_iter_poly_bm(mr, &params, extractors, task_id);
- }
- if (iter_type & MR_ITER_LEDGE) {
- ExtractLEdgeBMesh_Params params;
- params.ledge = mr->ledges;
- params.ledge_range[0] = start;
- params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
- extract_iter_ledge_bm(mr, &params, extractors, task_id);
- }
- if (iter_type & MR_ITER_LVERT) {
- ExtractLVertBMesh_Params params;
- params.lvert = mr->lverts;
- params.lvert_range[0] = start;
- params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
- extract_iter_lvert_bm(mr, &params, extractors, task_id);
- }
- break;
- case MR_EXTRACT_MAPPED:
- case MR_EXTRACT_MESH:
- if (iter_type & MR_ITER_LOOPTRI) {
- ExtractTriMesh_Params params;
- params.mlooptri = mr->mlooptri;
- params.tri_range[0] = start;
- params.tri_range[1] = min_ii(mr->tri_len, end);
- extract_iter_looptri_mesh(mr, &params, extractors, task_id);
- }
- if (iter_type & MR_ITER_POLY) {
- ExtractPolyMesh_Params params;
- params.poly_range[0] = start;
- params.poly_range[1] = min_ii(mr->poly_len, end);
- extract_iter_poly_mesh(mr, &params, extractors, task_id);
- }
- if (iter_type & MR_ITER_LEDGE) {
- ExtractLEdgeMesh_Params params;
- params.ledge = mr->ledges;
- params.ledge_range[0] = start;
- params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
- extract_iter_ledge_mesh(mr, &params, extractors, task_id);
- }
- if (iter_type & MR_ITER_LVERT) {
- ExtractLVertMesh_Params params;
- params.lvert = mr->lverts;
- params.lvert_range[0] = start;
- params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
- extract_iter_lvert_mesh(mr, &params, extractors, task_id);
- }
- break;
- }
-}
-
-static void extract_task_init(ExtractTaskData *data)
-{
- extract_init(data->mr, data->cache, *data->extractors, data->mbc);
- extract_task_init(*data->extractors, data->task_len);
-}
-
-static void extract_task_run(void *__restrict taskdata)
-{
- ExtractTaskData *data = (ExtractTaskData *)taskdata;
- mesh_extract_iter(
- data->mr, data->iter_type, data->start, data->end, *data->extractors, data->task_id);
-
- /* If this is the last task, we do the finish function. */
- int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
- if (remainin_tasks == 0) {
- extract_task_finish(*data->extractors, data->task_len);
- extract_finish(data->mr, data->cache, *data->extractors);
- }
-}
-static void extract_task_init_and_run(void *__restrict taskdata)
+static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ ExtractorRunDatas *extractors,
+ MeshBufferCache *mbc,
+ const bool use_threading)
{
- ExtractTaskData *data = (ExtractTaskData *)taskdata;
- extract_run_single_threaded(
- data->mr, data->cache, *data->extractors, data->iter_type, data->mbc);
+ ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbc, use_threading);
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ extract_task_range_run,
+ taskdata,
+ (TaskGraphNodeFreeFunction)extract_task_data_free);
+ return task_node;
}
/** \} */
@@ -614,11 +496,15 @@ static void extract_task_init_and_run(void *__restrict taskdata)
* \{ */
struct MeshRenderDataUpdateTaskData {
MeshRenderData *mr = nullptr;
+ MeshBufferExtractionCache *cache = nullptr;
eMRIterType iter_type;
eMRDataType data_flag;
- MeshRenderDataUpdateTaskData(MeshRenderData *mr, eMRIterType iter_type, eMRDataType data_flag)
- : mr(mr), iter_type(iter_type), data_flag(data_flag)
+ MeshRenderDataUpdateTaskData(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ eMRIterType iter_type,
+ eMRDataType data_flag)
+ : mr(mr), cache(cache), iter_type(iter_type), data_flag(data_flag)
{
}
@@ -649,15 +535,17 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data)
mesh_render_data_update_normals(mr, data_flag);
mesh_render_data_update_looptris(mr, iter_type, data_flag);
+ mesh_render_data_update_mat_offsets(mr, update_task_data->cache, data_flag);
}
static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
const eMRIterType iter_type,
const eMRDataType data_flag)
{
MeshRenderDataUpdateTaskData *task_data = new MeshRenderDataUpdateTaskData(
- mr, iter_type, data_flag);
+ mr, cache, iter_type, data_flag);
struct TaskNode *task_node = BLI_task_graph_node_create(
task_graph,
@@ -670,153 +558,9 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Task Node - Extract Single Threaded
- * \{ */
-
-static struct TaskNode *extract_single_threaded_task_node_create(struct TaskGraph *task_graph,
- ExtractTaskData *task_data)
-{
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph,
- extract_task_init_and_run,
- task_data,
- (TaskGraphNodeFreeFunction)extract_task_data_free);
- return task_node;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Task Node - UserData Initializer
- * \{ */
-struct UserDataInitTaskData {
- ExtractTaskData *td = nullptr;
- int32_t task_counter = 0;
-
- ~UserDataInitTaskData()
- {
- extract_task_data_free(td);
- }
-
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("DRW:UserDataInitTaskData")
-#endif
-};
-
-static void user_data_init_task_data_free(void *data)
-{
- UserDataInitTaskData *taskdata = static_cast<UserDataInitTaskData *>(data);
- delete taskdata;
-}
-
-static void user_data_init_task_data_exec(void *__restrict task_data)
-{
- UserDataInitTaskData *extract_task_data = static_cast<UserDataInitTaskData *>(task_data);
- ExtractTaskData *taskdata_base = extract_task_data->td;
- extract_task_init(taskdata_base);
-}
-
-static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
- UserDataInitTaskData *task_data)
-{
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph,
- user_data_init_task_data_exec,
- task_data,
- (TaskGraphNodeFreeFunction)user_data_init_task_data_free);
- return task_node;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
/** \name Extract Loop
* \{ */
-static void extract_range_task_create(struct TaskGraph *task_graph,
- struct TaskNode *task_node_user_data_init,
- ExtractTaskData *taskdata,
- const eMRIterType type,
- int start,
- int length)
-{
- taskdata = new ExtractTaskData(*taskdata);
- taskdata->task_id = atomic_fetch_and_add_int32(taskdata->task_counter, 1);
- BLI_assert(taskdata->task_id < taskdata->task_len);
- taskdata->iter_type = type;
- taskdata->start = start;
- taskdata->end = start + length;
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph, extract_task_run, taskdata, extract_task_data_free_ex);
- BLI_task_graph_edge_create(task_node_user_data_init, task_node);
-}
-
-static int extract_range_task_num_elements_get(const MeshRenderData *mr,
- const eMRIterType iter_type)
-{
- /* Divide task into sensible chunks. */
- int iter_len = 0;
- if (iter_type & MR_ITER_LOOPTRI) {
- iter_len += mr->tri_len;
- }
- if (iter_type & MR_ITER_POLY) {
- iter_len += mr->poly_len;
- }
- if (iter_type & MR_ITER_LEDGE) {
- iter_len += mr->edge_loose_len;
- }
- if (iter_type & MR_ITER_LVERT) {
- iter_len += mr->vert_loose_len;
- }
- return iter_len;
-}
-
-static int extract_range_task_chunk_size_get(const MeshRenderData *mr,
- const eMRIterType iter_type,
- const int num_threads)
-{
- /* Divide task into sensible chunks. */
- const int num_elements = extract_range_task_num_elements_get(mr, iter_type);
- int range_len = (num_elements + num_threads) / num_threads;
- CLAMP_MIN(range_len, CHUNK_SIZE);
- return range_len;
-}
-
-static void extract_task_in_ranges_create(struct TaskGraph *task_graph,
- struct TaskNode *task_node_user_data_init,
- ExtractTaskData *taskdata_base,
- const int num_threads)
-{
- const MeshRenderData *mr = taskdata_base->mr;
- const int range_len = extract_range_task_chunk_size_get(
- mr, taskdata_base->iter_type, num_threads);
-
- if (taskdata_base->iter_type & MR_ITER_LOOPTRI) {
- for (int i = 0; i < mr->tri_len; i += range_len) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LOOPTRI, i, range_len);
- }
- }
- if (taskdata_base->iter_type & MR_ITER_POLY) {
- for (int i = 0; i < mr->poly_len; i += range_len) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata_base, MR_ITER_POLY, i, range_len);
- }
- }
- if (taskdata_base->iter_type & MR_ITER_LEDGE) {
- for (int i = 0; i < mr->edge_loose_len; i += range_len) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LEDGE, i, range_len);
- }
- }
- if (taskdata_base->iter_type & MR_ITER_LVERT) {
- for (int i = 0; i < mr->vert_loose_len; i += range_len) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LVERT, i, range_len);
- }
- }
-}
-
static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
@@ -962,26 +706,22 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
- task_graph, mr, iter_type, data_flag);
+ task_graph, mr, extraction_cache, iter_type, data_flag);
/* Simple heuristic. */
- const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE;
+ const bool use_thread = (mr->loop_len + mr->loop_loose_len) > MIN_RANGE_LEN;
if (use_thread) {
- uint single_threaded_extractors_len = 0;
-
/* First run the requested extractors that do not support asynchronous ranges. */
for (const ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
if (!extractor->use_threading) {
ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas();
single_threaded_extractors->append(extractor);
- ExtractTaskData *taskdata = new ExtractTaskData(
- mr, cache, single_threaded_extractors, mbc, nullptr, 1);
- struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph,
- taskdata);
+ struct TaskNode *task_node = extract_task_node_create(
+ task_graph, mr, cache, single_threaded_extractors, mbc, false);
+
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
- single_threaded_extractors_len++;
}
}
@@ -989,31 +729,10 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
ExtractorRunDatas *multi_threaded_extractors = new ExtractorRunDatas();
extractors.filter_threaded_extractors_into(*multi_threaded_extractors);
if (!multi_threaded_extractors->is_empty()) {
- /*
- * Determine the number of thread to use for multithreading.
- * Thread can be used for single threaded tasks. These typically take longer to execute so
- * fill the rest of the threads for range operations.
- */
- int num_threads = BLI_task_scheduler_num_threads();
- num_threads -= single_threaded_extractors_len % num_threads;
- const int max_multithreaded_task_len = multi_threaded_extractors->iter_types_len() +
- num_threads;
-
- UserDataInitTaskData *user_data_init_task_data = new UserDataInitTaskData();
- struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
- task_graph, user_data_init_task_data);
-
- user_data_init_task_data->td = new ExtractTaskData(mr,
- cache,
- multi_threaded_extractors,
- mbc,
- &user_data_init_task_data->task_counter,
- max_multithreaded_task_len);
-
- extract_task_in_ranges_create(
- task_graph, task_node_user_data_init, user_data_init_task_data->td, num_threads);
-
- BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
+ struct TaskNode *task_node = extract_task_node_create(
+ task_graph, mr, cache, multi_threaded_extractors, mbc, true);
+
+ BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
}
else {
/* No tasks created freeing extractors list. */
@@ -1023,9 +742,9 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
else {
/* Run all requests on the same thread. */
ExtractorRunDatas *extractors_copy = new ExtractorRunDatas(extractors);
- ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors_copy, mbc, nullptr, 1);
+ struct TaskNode *task_node = extract_task_node_create(
+ task_graph, mr, cache, extractors_copy, mbc, false);
- struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph, taskdata);
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
}
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
index 3cac391c42d..42cd571b089 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
@@ -130,12 +130,13 @@ typedef struct PosNorLoop {
typedef struct MeshExtract_PosNor_Data {
PosNorLoop *vbo_data;
- GPUNormal normals[];
+ GPUNormal *normals;
} MeshExtract_PosNor_Data;
-static void *extract_pos_nor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_pos_nor_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -149,9 +150,9 @@ static void *extract_pos_nor_init(const MeshRenderData *mr,
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
/* Pack normals per vert, reduce amount of computation. */
- size_t packed_nor_len = sizeof(GPUNormal) * mr->vert_len;
- MeshExtract_PosNor_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
+ MeshExtract_PosNor_Data *data = tls_data;
data->vbo_data = (PosNorLoop *)GPU_vertbuf_get_data(vbo);
+ data->normals = MEM_mallocN(sizeof(GPUNormal) * mr->vert_len, __func__);
/* Quicker than doing it for each loop. */
if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -168,11 +169,10 @@ static void *extract_pos_nor_init(const MeshRenderData *mr,
data->normals[v].low = GPU_normal_convert_i10_s3(mv->no);
}
}
- return data;
}
static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -220,7 +220,7 @@ static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *_data)
{
@@ -249,7 +249,7 @@ static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr,
- BMVert *eve,
+ const BMVert *eve,
const int lvert_index,
void *_data)
{
@@ -280,9 +280,10 @@ static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr,
static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
- void *data)
+ void *_data)
{
- MEM_freeN(data);
+ MeshExtract_PosNor_Data *data = _data;
+ MEM_freeN(data->normals);
}
const MeshExtract extract_pos_nor = {
@@ -295,6 +296,7 @@ const MeshExtract extract_pos_nor = {
.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh,
.finish = extract_pos_nor_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_PosNor_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor),
};
@@ -312,12 +314,13 @@ typedef struct PosNorHQLoop {
typedef struct MeshExtract_PosNorHQ_Data {
PosNorHQLoop *vbo_data;
- GPUNormal normals[];
+ GPUNormal *normals;
} MeshExtract_PosNorHQ_Data;
-static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_pos_nor_hq_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -331,9 +334,9 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
/* Pack normals per vert, reduce amount of computation. */
- size_t packed_nor_len = sizeof(GPUNormal) * mr->vert_len;
- MeshExtract_PosNorHQ_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
+ MeshExtract_PosNorHQ_Data *data = tls_data;
data->vbo_data = (PosNorHQLoop *)GPU_vertbuf_get_data(vbo);
+ data->normals = MEM_mallocN(sizeof(GPUNormal) * mr->vert_len, __func__);
/* Quicker than doing it for each loop. */
if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -350,11 +353,10 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
copy_v3_v3_short(data->normals[v].high, mv->no);
}
}
- return data;
}
static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -404,7 +406,7 @@ static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *_data)
{
@@ -436,7 +438,7 @@ static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr,
- BMVert *eve,
+ const BMVert *eve,
const int lvert_index,
void *_data)
{
@@ -469,9 +471,10 @@ static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr,
static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
- void *data)
+ void *_data)
{
- MEM_freeN(data);
+ MeshExtract_PosNorHQ_Data *data = _data;
+ MEM_freeN(data->normals);
}
const MeshExtract extract_pos_nor_hq = {
@@ -484,6 +487,7 @@ const MeshExtract extract_pos_nor_hq = {
.iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh,
.finish = extract_pos_nor_hq_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_PosNorHQ_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)};
@@ -496,9 +500,10 @@ typedef struct gpuHQNor {
short x, y, z, w;
} gpuHQNor;
-static void *extract_lnor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_lnor_hq_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -509,11 +514,11 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- return GPU_vertbuf_get_data(vbo);
+ *(gpuHQNor **)tls_data = GPU_vertbuf_get_data(vbo);
}
static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@@ -522,14 +527,14 @@ static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr,
do {
const int l_index = BM_elem_index_get(l_iter);
if (mr->loop_normals) {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]);
+ normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr->loop_normals[l_index]);
}
else {
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l_iter->v));
+ normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_vert_no_get(mr, l_iter->v));
}
else {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, f));
+ normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_face_no_get(mr, f));
}
}
} while ((l_iter = l_iter->next) != l_first);
@@ -544,7 +549,7 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index];
+ gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[ml_index];
if (mr->loop_normals) {
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
}
@@ -576,6 +581,7 @@ const MeshExtract extract_lnor_hq = {
.iter_poly_bm = extract_lnor_hq_iter_poly_bm,
.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh,
.data_type = MR_DATA_LOOP_NOR,
+ .data_size = sizeof(gpuHQNor *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor),
};
@@ -585,9 +591,10 @@ const MeshExtract extract_lnor_hq = {
/** \name Extract Loop Normal
* \{ */
-static void *extract_lnor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_lnor_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -598,11 +605,11 @@ static void *extract_lnor_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- return GPU_vertbuf_get_data(vbo);
+ *(GPUPackedNormal **)tls_data = GPU_vertbuf_get_data(vbo);
}
static void extract_lnor_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@@ -611,18 +618,18 @@ static void extract_lnor_iter_poly_bm(const MeshRenderData *mr,
do {
const int l_index = BM_elem_index_get(l_iter);
if (mr->loop_normals) {
- ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]);
+ (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]);
}
else {
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
- ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(
+ (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(
bm_vert_no_get(mr, l_iter->v));
}
else {
- ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f));
+ (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f));
}
}
- ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
+ (*(GPUPackedNormal **)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -635,7 +642,7 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index];
+ GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[ml_index];
if (mr->loop_normals) {
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
}
@@ -667,6 +674,7 @@ const MeshExtract extract_lnor = {
.iter_poly_bm = extract_lnor_iter_poly_bm,
.iter_poly_mesh = extract_lnor_iter_poly_mesh,
.data_type = MR_DATA_LOOP_NOR,
+ .data_size = sizeof(GPUPackedNormal *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor),
};
@@ -677,7 +685,10 @@ const MeshExtract extract_lnor = {
/** \name Extract UV layers
* \{ */
-static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
+static void extract_uv_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
GPUVertFormat format = {0};
@@ -757,13 +768,12 @@ static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *ca
}
}
}
-
- return NULL;
}
const MeshExtract extract_uv = {
.init = extract_uv_init,
.data_type = 0,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv),
};
@@ -946,15 +956,18 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
CustomData_free(&loop_data, mr->loop_len);
}
-static void *extract_tan_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
+static void extract_tan_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
{
extract_tan_ex_init(mr, cache, buf, false);
- return NULL;
}
const MeshExtract extract_tan = {
.init = extract_tan_init,
.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan),
};
@@ -965,16 +978,20 @@ const MeshExtract extract_tan = {
/** \name Extract HQ Tangent layers
* \{ */
-static void *extract_tan_hq_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
+static void extract_tan_hq_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
{
extract_tan_ex_init(mr, cache, buf, true);
- return NULL;
}
const MeshExtract extract_tan_hq = {
.init = extract_tan_hq_init,
.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
+ .data_size = 0,
.use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan),
};
/** \} */
@@ -983,9 +1000,10 @@ const MeshExtract extract_tan_hq = {
/** \name Extract Sculpt Data
* \{ */
-static void *extract_sculpt_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_sculpt_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
GPUVertFormat format = {0};
@@ -1066,13 +1084,12 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr,
}
}
}
-
- return NULL;
}
const MeshExtract extract_sculpt_data = {
.init = extract_sculpt_data_init,
.data_type = 0,
+ .data_size = 0,
/* TODO: enable threading. */
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data)};
@@ -1083,7 +1100,10 @@ const MeshExtract extract_sculpt_data = {
/** \name Extract VCol
* \{ */
-static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
+static void extract_vcol_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
GPUVertFormat format = {0};
@@ -1216,12 +1236,12 @@ static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *
}
}
}
- return NULL;
}
const MeshExtract extract_vcol = {
.init = extract_vcol_init,
.data_type = 0,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol),
};
@@ -1237,9 +1257,10 @@ typedef struct MeshExtract_Orco_Data {
float (*orco)[3];
} MeshExtract_Orco_Data;
-static void *extract_orco_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_orco_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -1256,16 +1277,15 @@ static void *extract_orco_init(const MeshRenderData *mr,
CustomData *cd_vdata = &mr->me->vdata;
- MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__);
+ MeshExtract_Orco_Data *data = tls_data;
data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo);
data->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
/* Make sure `orco` layer was requested only if needed! */
BLI_assert(data->orco);
- return data;
}
static void extract_orco_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@@ -1296,20 +1316,12 @@ static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_orco_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf),
- void *data)
-{
- MEM_freeN(data);
-}
-
const MeshExtract extract_orco = {
.init = extract_orco_init,
.iter_poly_bm = extract_orco_iter_poly_bm,
.iter_poly_mesh = extract_orco_iter_poly_mesh,
- .finish = extract_orco_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_Orco_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco),
};
@@ -1325,7 +1337,7 @@ typedef struct MeshExtract_EdgeFac_Data {
uchar *vbo_data;
bool use_edge_render;
/* Number of loop per edge. */
- uchar edge_loop_count[0];
+ uchar *edge_loop_count;
} MeshExtract_EdgeFac_Data;
static float loop_edge_factor_get(const float f_no[3],
@@ -1344,9 +1356,10 @@ static float loop_edge_factor_get(const float f_no[3],
return d;
}
-static void *extract_edge_fac_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_edge_fac_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -1357,11 +1370,10 @@ static void *extract_edge_fac_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
- MeshExtract_EdgeFac_Data *data;
+ MeshExtract_EdgeFac_Data *data = tls_data;
if (mr->extract_type == MR_EXTRACT_MESH) {
- size_t edge_loop_count_size = sizeof(uint32_t) * mr->edge_len;
- data = MEM_callocN(sizeof(*data) + edge_loop_count_size, __func__);
+ data->edge_loop_count = MEM_callocN(sizeof(uint32_t) * mr->edge_len, __func__);
/* HACK(fclem) Detecting the need for edge render.
* We could have a flag in the mesh instead or check the modifier stack. */
@@ -1374,17 +1386,15 @@ static void *extract_edge_fac_init(const MeshRenderData *mr,
}
}
else {
- data = MEM_callocN(sizeof(*data), __func__);
/* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
data->use_edge_render = true;
}
data->vbo_data = GPU_vertbuf_get_data(vbo);
- return data;
}
static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -1450,7 +1460,7 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *UNUSED(eed),
+ const BMEdge *UNUSED(eed),
const int ledge_index,
void *_data)
{
@@ -1501,7 +1511,7 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
/* Free old byte data. */
MEM_freeN(data->vbo_data);
}
- MEM_freeN(data);
+ MEM_SAFE_FREE(data->edge_loop_count);
}
const MeshExtract extract_edge_fac = {
@@ -1512,6 +1522,7 @@ const MeshExtract extract_edge_fac = {
.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh,
.finish = extract_edge_fac_finish,
.data_type = MR_DATA_POLY_NOR,
+ .data_size = sizeof(MeshExtract_EdgeFac_Data),
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac)};
@@ -1580,9 +1591,10 @@ static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeig
return input;
}
-static void *extract_weights_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf)
+static void extract_weights_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -1592,7 +1604,7 @@ static void *extract_weights_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
- MeshExtract_Weight_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MeshExtract_Weight_Data *data = tls_data;
data->vbo_data = (float *)GPU_vertbuf_get_data(vbo);
data->wstate = &cache->weight_state;
@@ -1609,11 +1621,10 @@ static void *extract_weights_init(const MeshRenderData *mr,
data->dvert = CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT);
data->cd_ofs = -1;
}
- return data;
}
static void extract_weights_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -1653,20 +1664,12 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_weights_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf),
- void *data)
-{
- MEM_freeN(data);
-}
-
const MeshExtract extract_weights = {
.init = extract_weights_init,
.iter_poly_bm = extract_weights_iter_poly_bm,
.iter_poly_mesh = extract_weights_iter_poly_mesh,
- .finish = extract_weights_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_Weight_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights),
};
@@ -1685,7 +1688,7 @@ typedef struct EditLoopData {
} EditLoopData;
static void mesh_render_data_face_flag(const MeshRenderData *mr,
- BMFace *efa,
+ const BMFace *efa,
const int cd_ofs,
EditLoopData *eattr)
{
@@ -1713,7 +1716,9 @@ static void mesh_render_data_face_flag(const MeshRenderData *mr,
#endif
}
-static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, EditLoopData *eattr)
+static void mesh_render_data_edge_flag(const MeshRenderData *mr,
+ const BMEdge *eed,
+ EditLoopData *eattr)
{
const ToolSettings *ts = mr->toolsettings;
const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
@@ -1805,7 +1810,9 @@ static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
}
}
-static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, EditLoopData *eattr)
+static void mesh_render_data_vert_flag(const MeshRenderData *mr,
+ const BMVert *eve,
+ EditLoopData *eattr)
{
if (eve == mr->eve_act) {
eattr->e_flag |= VFLAG_VERT_ACTIVE;
@@ -1815,9 +1822,10 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, Ed
}
}
-static void *extract_edit_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_edit_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -1828,20 +1836,23 @@ static void *extract_edit_data_init(const MeshRenderData *mr,
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
- return GPU_vertbuf_get_data(vbo);
+ EditLoopData *vbo_data = GPU_vertbuf_get_data(vbo);
+ *(EditLoopData **)tls_data = vbo_data;
}
static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
- EditLoopData *data = (EditLoopData *)_data + l_index;
+ EditLoopData *data = vbo_data + l_index;
memset(data, 0x0, sizeof(*data));
mesh_render_data_face_flag(mr, f, -1, data);
mesh_render_data_edge_flag(mr, l_iter->e, data);
@@ -1854,11 +1865,13 @@ static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr,
const int mp_index,
void *_data)
{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- EditLoopData *data = (EditLoopData *)_data + ml_index;
+ EditLoopData *data = vbo_data + ml_index;
memset(data, 0x0, sizeof(*data));
BMFace *efa = bm_original_face_get(mr, mp_index);
BMEdge *eed = bm_original_edge_get(mr, ml->e);
@@ -1876,11 +1889,12 @@ static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *_data)
{
- EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2);
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+ EditLoopData *data = vbo_data + mr->loop_len + (ledge_index * 2);
memset(data, 0x0, sizeof(*data) * 2);
mesh_render_data_edge_flag(mr, eed, &data[0]);
data[1] = data[0];
@@ -1893,7 +1907,8 @@ static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr,
const int ledge_index,
void *_data)
{
- EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2;
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+ EditLoopData *data = vbo_data + mr->loop_len + ledge_index * 2;
memset(data, 0x0, sizeof(*data) * 2);
const int e_index = mr->ledges[ledge_index];
BMEdge *eed = bm_original_edge_get(mr, e_index);
@@ -1912,12 +1927,13 @@ static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr,
- BMVert *eve,
+ const BMVert *eve,
const int lvert_index,
void *_data)
{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
+ EditLoopData *data = vbo_data + offset + lvert_index;
memset(data, 0x0, sizeof(*data));
mesh_render_data_vert_flag(mr, eve, data);
}
@@ -1927,9 +1943,10 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
const int lvert_index,
void *_data)
{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
+ EditLoopData *data = vbo_data + offset + lvert_index;
memset(data, 0x0, sizeof(*data));
const int v_index = mr->lverts[lvert_index];
BMVert *eve = bm_original_vert_get(mr, v_index);
@@ -1947,6 +1964,7 @@ const MeshExtract extract_edit_data = {
.iter_lvert_bm = extract_edit_data_iter_lvert_bm,
.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh,
.data_type = 0,
+ .data_size = sizeof(EditLoopData *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data)};
@@ -1961,9 +1979,10 @@ typedef struct MeshExtract_EditUVData_Data {
int cd_ofs;
} MeshExtract_EditUVData_Data;
-static void *extract_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_edituv_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -1978,14 +1997,13 @@ static void *extract_edituv_data_init(const MeshRenderData *mr,
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MeshExtract_EditUVData_Data *data = tls_data;
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
- return data;
}
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -2044,20 +2062,12 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf),
- void *data)
-{
- MEM_freeN(data);
-}
-
const MeshExtract extract_edituv_data = {
.init = extract_edituv_data_init,
.iter_poly_bm = extract_edituv_data_iter_poly_bm,
.iter_poly_mesh = extract_edituv_data_iter_poly_mesh,
- .finish = extract_edituv_data_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_EditUVData_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data)};
@@ -2067,9 +2077,10 @@ const MeshExtract extract_edituv_data = {
/** \name Extract Edit UV area stretch
* \{ */
-static void *extract_edituv_stretch_area_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_edituv_stretch_area_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -2079,8 +2090,6 @@ static void *extract_edituv_stretch_area_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
-
- return NULL;
}
BLI_INLINE float area_ratio_get(float area, float uvarea)
@@ -2174,6 +2183,7 @@ const MeshExtract extract_edituv_stretch_area = {
.init = extract_edituv_stretch_area_init,
.finish = extract_edituv_stretch_area_finish,
.data_type = 0,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area)};
@@ -2237,9 +2247,10 @@ static void edituv_get_edituv_stretch_angle(float auv[2][2],
#endif
}
-static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_edituv_stretch_angle_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -2252,7 +2263,7 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MeshExtract_StretchAngle_Data *data = tls_data;
data->vbo_data = (UVStretchAngle *)GPU_vertbuf_get_data(vbo);
/* Special iterator needed to save about half of the computing cost. */
@@ -2263,11 +2274,10 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH));
data->luv = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
}
- return data;
}
static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -2363,20 +2373,12 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr
}
}
-static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf),
- void *data)
-{
- MEM_freeN(data);
-}
-
const MeshExtract extract_edituv_stretch_angle = {
.init = extract_edituv_stretch_angle_init,
.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm,
.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh,
- .finish = extract_edituv_stretch_angle_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_StretchAngle_Data),
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle)};
@@ -2386,9 +2388,10 @@ const MeshExtract extract_edituv_stretch_angle = {
/** \name Extract Edit Mesh Analysis Colors
* \{ */
-static void *extract_mesh_analysis_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_mesh_analysis_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -2398,8 +2401,6 @@ static void *extract_mesh_analysis_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
-
- return NULL;
}
static void axis_from_enum_v3(float v[3], const char axis)
@@ -2984,6 +2985,7 @@ const MeshExtract extract_mesh_analysis = {
/* This is not needed for all visualization types.
* * Maybe split into different extract. */
.data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis)};
@@ -2993,9 +2995,10 @@ const MeshExtract extract_mesh_analysis = {
/** \name Extract Face-dots positions
* \{ */
-static void *extract_fdots_pos_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_fdots_pos_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3005,15 +3008,15 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
- return GPU_vertbuf_get_data(vbo);
+ *(float(**)[3])tls_data = GPU_vertbuf_get_data(vbo);
}
static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int f_index,
void *data)
{
- float(*center)[3] = data;
+ float(*center)[3] = *(float(**)[3])data;
float *co = center[f_index];
zero_v3(co);
@@ -3031,7 +3034,7 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
const int mp_index,
void *data)
{
- float(*center)[3] = (float(*)[3])data;
+ float(*center)[3] = *(float(**)[3])data;
float *co = center[mp_index];
zero_v3(co);
@@ -3064,6 +3067,7 @@ const MeshExtract extract_fdots_pos = {
.iter_poly_bm = extract_fdots_pos_iter_poly_bm,
.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh,
.data_type = 0,
+ .data_size = sizeof(float (*)[3]),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos)};
@@ -3077,9 +3081,10 @@ const MeshExtract extract_fdots_pos = {
#define NOR_AND_FLAG_ACTIVE -1
#define NOR_AND_FLAG_HIDDEN -2
-static void *extract_fdots_nor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_fdots_nor_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3089,8 +3094,6 @@ static void *extract_fdots_nor_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
-
- return NULL;
}
static void extract_fdots_nor_finish(const MeshRenderData *mr,
@@ -3146,6 +3149,7 @@ const MeshExtract extract_fdots_nor = {
.init = extract_fdots_nor_init,
.finish = extract_fdots_nor_finish,
.data_type = MR_DATA_POLY_NOR,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)};
@@ -3154,9 +3158,10 @@ const MeshExtract extract_fdots_nor = {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots High Quality Normal and edit flag
* \{ */
-static void *extract_fdots_nor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3166,8 +3171,6 @@ static void *extract_fdots_nor_hq_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
-
- return NULL;
}
static void extract_fdots_nor_hq_finish(const MeshRenderData *mr,
@@ -3223,6 +3226,7 @@ const MeshExtract extract_fdots_nor_hq = {
.init = extract_fdots_nor_hq_init,
.finish = extract_fdots_nor_hq_finish,
.data_type = MR_DATA_POLY_NOR,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)};
@@ -3238,9 +3242,10 @@ typedef struct MeshExtract_FdotUV_Data {
int cd_ofs;
} MeshExtract_FdotUV_Data;
-static void *extract_fdots_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_fdots_uv_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3258,7 +3263,7 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr,
memset(GPU_vertbuf_get_data(vbo), 0x0, mr->poly_len * GPU_vertbuf_get_format(vbo)->stride);
}
- MeshExtract_FdotUV_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MeshExtract_FdotUV_Data *data = tls_data;
data->vbo_data = (float(*)[2])GPU_vertbuf_get_data(vbo);
if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -3267,11 +3272,10 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr,
else {
data->uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
}
- return data;
}
static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -3308,20 +3312,12 @@ static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf),
- void *data)
-{
- MEM_freeN(data);
-}
-
const MeshExtract extract_fdots_uv = {
.init = extract_fdots_uv_init,
.iter_poly_bm = extract_fdots_uv_iter_poly_bm,
.iter_poly_mesh = extract_fdots_uv_iter_poly_mesh,
- .finish = extract_fdots_uv_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_FdotUV_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv)};
@@ -3336,9 +3332,10 @@ typedef struct MeshExtract_EditUVFdotData_Data {
int cd_ofs;
} MeshExtract_EditUVFdotData_Data;
-static void *extract_fdots_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_fdots_edituv_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3349,14 +3346,13 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
- MeshExtract_EditUVFdotData_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MeshExtract_EditUVFdotData_Data *data = tls_data;
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
- return data;
}
static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -3380,20 +3376,12 @@ static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf),
- void *data)
-{
- MEM_freeN(data);
-}
-
const MeshExtract extract_fdots_edituv_data = {
.init = extract_fdots_edituv_data_init,
.iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm,
.iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh,
- .finish = extract_fdots_edituv_data_finish,
.data_type = 0,
+ .data_size = sizeof(MeshExtract_EditUVFdotData_Data),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data)};
@@ -3408,9 +3396,10 @@ typedef struct SkinRootData {
float local_pos[3];
} SkinRootData;
-static void *extract_skin_roots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_skin_roots_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
{
GPUVertBuf *vbo = buf;
/* Exclusively for edit mode. */
@@ -3444,13 +3433,12 @@ static void *extract_skin_roots_init(const MeshRenderData *mr,
/* It's really unlikely that all verts will be roots. Resize to avoid losing VRAM. */
GPU_vertbuf_data_len_set(vbo, root_len);
-
- return NULL;
}
const MeshExtract extract_skin_roots = {
.init = extract_skin_roots_init,
.data_type = 0,
+ .data_size = 0,
.use_threading = false,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots)};
@@ -3460,9 +3448,10 @@ const MeshExtract extract_skin_roots = {
/** \name Extract Selection Index
* \{ */
-static void *extract_select_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_select_idx_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3472,7 +3461,7 @@ static void *extract_select_idx_init(const MeshRenderData *mr,
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
- return GPU_vertbuf_get_data(vbo);
+ *(uint32_t **)tls_data = GPU_vertbuf_get_data(vbo);
}
/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the
@@ -3481,7 +3470,7 @@ static void *extract_select_idx_init(const MeshRenderData *mr,
* shader to output original index. */
static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int f_index,
void *data)
{
@@ -3489,12 +3478,12 @@ static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
- ((uint32_t *)data)[l_index] = f_index;
+ (*(uint32_t **)data)[l_index] = f_index;
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@@ -3502,12 +3491,12 @@ static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
- ((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->e);
+ (*(uint32_t **)data)[l_index] = BM_elem_index_get(l_iter->e);
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@@ -3515,36 +3504,36 @@ static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
- ((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->v);
+ (*(uint32_t **)data)[l_index] = BM_elem_index_get(l_iter->v);
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *data)
{
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed);
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed);
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed);
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed);
}
static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *data)
{
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1);
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2);
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1);
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2);
}
static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr,
- BMVert *eve,
+ const BMVert *eve,
const int lvert_index,
void *data)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve);
+ (*(uint32_t **)data)[offset + lvert_index] = BM_elem_index_get(eve);
}
static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr,
@@ -3554,7 +3543,7 @@ static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr,
{
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
- ((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index;
+ (*(uint32_t **)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index;
}
}
@@ -3567,7 +3556,7 @@ static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr,
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- ((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e;
+ (*(uint32_t **)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e;
}
}
@@ -3580,7 +3569,7 @@ static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr,
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
const MLoop *ml = &mloop[ml_index];
- ((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v;
+ (*(uint32_t **)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v;
}
}
@@ -3591,8 +3580,8 @@ static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr,
{
const int e_index = mr->ledges[ledge_index];
const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig;
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig;
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig;
}
static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr,
@@ -3602,8 +3591,8 @@ static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr,
{
int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1;
int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig;
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig;
+ (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig;
}
static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
@@ -3615,7 +3604,7 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
const int v_index = mr->lverts[lvert_index];
const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index;
- ((uint32_t *)data)[offset + lvert_index] = v_orig;
+ (*(uint32_t **)data)[offset + lvert_index] = v_orig;
}
const MeshExtract extract_poly_idx = {
@@ -3623,6 +3612,7 @@ const MeshExtract extract_poly_idx = {
.iter_poly_bm = extract_poly_idx_iter_poly_bm,
.iter_poly_mesh = extract_poly_idx_iter_poly_mesh,
.data_type = 0,
+ .data_size = sizeof(uint32_t *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx)};
@@ -3633,6 +3623,7 @@ const MeshExtract extract_edge_idx = {
.iter_ledge_bm = extract_edge_idx_iter_ledge_bm,
.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh,
.data_type = 0,
+ .data_size = sizeof(uint32_t *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx)};
@@ -3645,12 +3636,14 @@ const MeshExtract extract_vert_idx = {
.iter_lvert_bm = extract_vert_idx_iter_lvert_bm,
.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh,
.data_type = 0,
+ .data_size = sizeof(uint32_t *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx)};
-static void *extract_fdot_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void extract_fdot_idx_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
{
GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
@@ -3661,15 +3654,15 @@ static void *extract_fdot_idx_init(const MeshRenderData *mr,
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
- return GPU_vertbuf_get_data(vbo);
+ *(uint32_t **)tls_data = GPU_vertbuf_get_data(vbo);
}
static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *UNUSED(f),
+ const BMFace *UNUSED(f),
const int f_index,
void *data)
{
- ((uint32_t *)data)[f_index] = f_index;
+ (*(uint32_t **)data)[f_index] = f_index;
}
static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr,
@@ -3678,10 +3671,10 @@ static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr,
void *data)
{
if (mr->p_origindex != NULL) {
- ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index];
+ (*(uint32_t **)data)[mp_index] = mr->p_origindex[mp_index];
}
else {
- ((uint32_t *)data)[mp_index] = mp_index;
+ (*(uint32_t **)data)[mp_index] = mp_index;
}
}
@@ -3690,5 +3683,6 @@ const MeshExtract extract_fdot_idx = {
.iter_poly_bm = extract_fdot_idx_iter_poly_bm,
.iter_poly_mesh = extract_fdot_idx_iter_poly_mesh,
.data_type = 0,
+ .data_size = sizeof(uint32_t *),
.use_threading = true,
.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx)};
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
index 2eea53354f2..a258967564b 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
@@ -38,6 +38,72 @@
extern "C" {
#endif
+#define MIN_RANGE_LEN 1024
+
+/* ---------------------------------------------------------------------- */
+/** \name Dependencies between buffer and batch
+ * \{ */
+#ifndef NDEBUG
+# define _MDEF_type(name) static DRWBatchFlag MDEP_assert_##name = 0, MDEP_##name
+#else
+# define _MDEF_type(name) static const DRWBatchFlag MDEP_##name
+#endif
+
+/* clang-format off */
+
+#define _MDEPS_CREATE1(b) (1u << MBC_BATCH_INDEX(b))
+#define _MDEPS_CREATE2(b1, b2) _MDEPS_CREATE1(b1) | _MDEPS_CREATE1(b2)
+#define _MDEPS_CREATE3(b1, b2, b3) _MDEPS_CREATE2(b1, b2) | _MDEPS_CREATE1(b3)
+#define _MDEPS_CREATE4(b1, b2, b3, b4) _MDEPS_CREATE3(b1, b2, b3) | _MDEPS_CREATE1(b4)
+#define _MDEPS_CREATE5(b1, b2, b3, b4, b5) _MDEPS_CREATE4(b1, b2, b3, b4) | _MDEPS_CREATE1(b5)
+#define _MDEPS_CREATE6(b1, b2, b3, b4, b5, b6) _MDEPS_CREATE5(b1, b2, b3, b4, b5) | _MDEPS_CREATE1(b6)
+#define _MDEPS_CREATE7(b1, b2, b3, b4, b5, b6, b7) _MDEPS_CREATE6(b1, b2, b3, b4, b5, b6) | _MDEPS_CREATE1(b7)
+#define _MDEPS_CREATE8(b1, b2, b3, b4, b5, b6, b7, b8) _MDEPS_CREATE7(b1, b2, b3, b4, b5, b6, b7) | _MDEPS_CREATE1(b8)
+#define _MDEPS_CREATE9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _MDEPS_CREATE8(b1, b2, b3, b4, b5, b6, b7, b8) | _MDEPS_CREATE1(b9)
+#define _MDEPS_CREATE10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _MDEPS_CREATE9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _MDEPS_CREATE1(b10)
+#define _MDEPS_CREATE19(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19) _MDEPS_CREATE10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _MDEPS_CREATE9(b11, b12, b13, b14, b15, b16, b17, b18, b19)
+
+#define MDEPS_CREATE(name, ...) _MDEF_type(name) = VA_NARGS_CALL_OVERLOAD(_MDEPS_CREATE, __VA_ARGS__)
+
+#define _MDEPS_CREATE_MAP1(a) MDEP_##a
+#define _MDEPS_CREATE_MAP2(a, b) MDEP_##a | MDEP_##b
+#define _MDEPS_CREATE_MAP3(a, b, c) _MDEPS_CREATE_MAP2(a, b) | MDEP_##c
+#define _MDEPS_CREATE_MAP4(a, b, c, d) _MDEPS_CREATE_MAP3(a, b, c) | MDEP_##d
+#define _MDEPS_CREATE_MAP5(a, b, c, d, e) _MDEPS_CREATE_MAP4(a, b, c, d) | MDEP_##e
+#define _MDEPS_CREATE_MAP6(a, b, c, d, e, f) _MDEPS_CREATE_MAP5(a, b, c, d, e) | MDEP_##f
+#define _MDEPS_CREATE_MAP7(a, b, c, d, e, f, g) _MDEPS_CREATE_MAP6(a, b, c, d, e, f) | MDEP_##g
+#define _MDEPS_CREATE_MAP8(a, b, c, d, e, f, g, h) _MDEPS_CREATE_MAP7(a, b, c, d, e, f, g) | MDEP_##h
+#define _MDEPS_CREATE_MAP9(a, b, c, d, e, f, g, h, i) _MDEPS_CREATE_MAP8(a, b, c, d, e, f, g, h) | MDEP_##i
+#define _MDEPS_CREATE_MAP10(a, b, c, d, e, f, g, h, i, j) _MDEPS_CREATE_MAP9(a, b, c, d, e, f, g, h, i) | MDEP_##j
+
+#define MDEPS_CREATE_MAP(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_CREATE_MAP, __VA_ARGS__)
+
+#ifndef NDEBUG
+# define _MDEPS_ASSERT2(b, name) \
+ MDEP_assert_##name |= _MDEPS_CREATE1(b); \
+ BLI_assert(MDEP_##name & _MDEPS_CREATE1(b))
+# define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2)
+# define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3)
+# define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4)
+# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5)
+# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6)
+# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7)
+
+# define MDEPS_ASSERT(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__)
+# define MDEPS_ASSERT_MAP(name) BLI_assert(MDEP_assert_##name == MDEP_##name)
+#else
+# define MDEPS_ASSERT(...)
+# define MDEPS_ASSERT_MAP(name) UNUSED_VARS(MDEP_##name)
+#endif
+
+/* clang-format on */
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Render Data
+ * \{ */
+
typedef enum eMRExtractType {
MR_EXTRACT_BMESH,
MR_EXTRACT_MAPPED,
@@ -94,6 +160,10 @@ typedef struct MeshRenderData {
float (*loop_normals)[3];
float (*poly_normals)[3];
int *lverts, *ledges;
+ struct {
+ int *tri;
+ int visible_tri_len;
+ } mat_offsets;
} MeshRenderData;
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
@@ -150,278 +220,57 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
return efa->no;
}
-/* TODO(jbakker): phase out batch iteration macros as they are only used once. */
+/** \} */
+
/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Loop Triangles
+/** \name Mesh Elements Extract Struct
* \{ */
-
-typedef struct ExtractTriBMesh_Params {
- BMLoop *(*looptris)[3];
- int tri_range[2];
-} ExtractTriBMesh_Params;
+/* TODO(jbakker): move parameters inside a struct. */
typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
BMLoop **elt,
const int elt_index,
void *data);
-
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
- CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
- { \
- const int _tri_index_end = (params)->tri_range[1]; \
- BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
- for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
- index_tri += 1, elem_tri += 3)
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
-
-typedef struct ExtractTriMesh_Params {
- const MLoopTri *mlooptri;
- int tri_range[2];
-} ExtractTriMesh_Params;
typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
const MLoopTri *mlt,
const int elt_index,
void *data);
-
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
- CHECK_TYPE(params, const ExtractTriMesh_Params *); \
- { \
- const int _tri_index_end = (params)->tri_range[1]; \
- const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
- for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
- index_tri += 1, elem_tri += 1)
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Polygons, Loops
- * \{ */
-
-typedef struct ExtractPolyBMesh_Params {
- BMLoop *(*looptris)[3];
- int poly_range[2];
-} ExtractPolyBMesh_Params;
typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
- BMFace *f,
+ const BMFace *f,
const int f_index,
void *data);
-
-#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
- CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
- BMFace **_ftable = mr->bm->ftable; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- BMFace *elem_poly = _ftable[index_poly]; \
- (void)elem_poly;
-
-#define EXTRACT_POLY_FOREACH_BM_END \
- } \
- }
-
-/* Iterate over polygon and loop. */
-#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
- CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
- BMFace **_ftable = mr->bm->ftable; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- BMFace *elem_face = _ftable[index_poly]; \
- BMLoop *elem_loop, *l_first; \
- elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
- do { \
- const int index_loop = BM_elem_index_get(elem_loop); \
- (void)index_loop; /* Quiet warning when unused. */
-
-#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
- } \
- while ((elem_loop = elem_loop->next) != l_first) \
- ; \
- } \
- }
-
-typedef struct ExtractPolyMesh_Params {
- int poly_range[2];
-} ExtractPolyMesh_Params;
typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
const MPoly *mp,
const int mp_index,
void *data);
-
-#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
- CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
- { \
- const MPoly *_mpoly = mr->mpoly; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- const MPoly *elem_poly = &_mpoly[index_poly]; \
- (void)elem_poly;
-
-#define EXTRACT_POLY_FOREACH_MESH_END \
- } \
- }
-
-/* Iterate over polygon and loop. */
-#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
- elem_poly, index_poly, elem_loop, index_loop, params, mr) \
- CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
- { \
- const MPoly *_mpoly = mr->mpoly; \
- const MLoop *_mloop = mr->mloop; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- const MPoly *elem_poly = &_mpoly[index_poly]; \
- const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
- for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
- const MLoop *elem_loop = &_mloop[index_loop]; \
- (void)elem_loop;
-
-#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
- } \
- } \
- }
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Loose Edges
- * \{ */
-
-typedef struct ExtractLEdgeBMesh_Params {
- const int *ledge;
- int ledge_range[2];
-} ExtractLEdgeBMesh_Params;
typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *data);
-
-#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
- CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
- BMEdge **_etable = mr->bm->etable; \
- const int *_ledge = (params)->ledge; \
- const int _ledge_index_end = (params)->ledge_range[1]; \
- for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
- index_ledge += 1) { \
- BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
- (void)elem_edge; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LEDGE_FOREACH_BM_END \
- } \
- } \
- }
-
-typedef struct ExtractLEdgeMesh_Params {
- const int *ledge;
- int ledge_range[2];
-} ExtractLEdgeMesh_Params;
typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
const MEdge *med,
const int ledge_index,
void *data);
-
-#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
- CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
- { \
- const MEdge *_medge = mr->medge; \
- const int *_ledge = (params)->ledge; \
- const int _ledge_index_end = (params)->ledge_range[1]; \
- for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
- index_ledge += 1) { \
- const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
- (void)elem_edge; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LEDGE_FOREACH_MESH_END \
- } \
- } \
- }
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Loose Vertices
- * \{ */
-
-typedef struct ExtractLVertBMesh_Params {
- const int *lvert;
- int lvert_range[2];
-} ExtractLVertBMesh_Params;
typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
- BMVert *eve,
+ const BMVert *eve,
const int lvert_index,
void *data);
-
-#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
- CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
- BMVert **vtable = mr->bm->vtable; \
- const int *lverts = (params)->lvert; \
- const int _lvert_index_end = (params)->lvert_range[1]; \
- for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
- index_lvert += 1) { \
- BMVert *elem_vert = vtable[lverts[index_lvert]]; \
- (void)elem_vert; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LVERT_FOREACH_BM_END \
- } \
- } \
- }
-
-typedef struct ExtractLVertMesh_Params {
- const int *lvert;
- int lvert_range[2];
-} ExtractLVertMesh_Params;
typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
const MVert *mv,
const int lvert_index,
void *data);
-
-#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
- CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
- { \
- const MVert *mvert = mr->mvert; \
- const int *lverts = (params)->lvert; \
- const int _lvert_index_end = (params)->lvert_range[1]; \
- for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
- index_lvert += 1) { \
- const MVert *elem = &mvert[lverts[index_lvert]]; \
- (void)elem; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LVERT_FOREACH_MESH_END \
- } \
- } \
- }
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract Struct
- * \{ */
-/* TODO(jbakker): move parameters inside a struct. */
-typedef void *(ExtractInitFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer);
+typedef void(ExtractInitFn)(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *r_data);
typedef void(ExtractFinishFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
void *data);
-typedef void *(ExtractTaskInitFn)(void *userdata);
-typedef void(ExtractTaskFinishFn)(void *userdata, void *task_userdata);
+typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata);
typedef struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
- /** Task local data. */
- ExtractTaskInitFn *task_init;
/** Executed on one (or more if use_threading) worker thread(s). */
ExtractTriBMeshFn *iter_looptri_bm;
ExtractTriMeshFn *iter_looptri_mesh;
@@ -432,10 +281,11 @@ typedef struct MeshExtract {
ExtractLVertBMeshFn *iter_lvert_bm;
ExtractLVertMeshFn *iter_lvert_mesh;
/** Executed on one worker thread after all elements iterations. */
- ExtractTaskFinishFn *task_finish;
+ ExtractTaskReduceFn *task_reduce;
ExtractFinishFn *finish;
/** Used to request common data. */
eMRDataType data_type;
+ size_t data_size;
/** Used to know if the element callbacks are thread-safe and can be parallelized. */
bool use_threading;
/**
@@ -460,6 +310,9 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
const eMRIterType iter_type);
void mesh_render_data_free(MeshRenderData *mr);
void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag);
+void mesh_render_data_update_mat_offsets(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ const eMRDataType data_flag);
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index 4741bcb06c9..bccf894cc53 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -27,6 +27,7 @@
#include "BLI_bitmap.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
@@ -39,15 +40,26 @@
#include "draw_cache_extract_mesh_private.h"
/* ---------------------------------------------------------------------- */
-/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
+/** \name Update Loose Geometry
* \{ */
+static void mesh_render_data_lverts_bm(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ BMesh *bm);
+static void mesh_render_data_ledges_bm(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ BMesh *bm);
+static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+static void mesh_render_data_loose_geom_build(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+
static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtractionCache *cache)
{
- mr->ledges = cache->ledges;
- mr->lverts = cache->lverts;
- mr->vert_loose_len = cache->vert_loose_len;
- mr->edge_loose_len = cache->edge_loose_len;
+ mr->ledges = cache->loose_geom.edges;
+ mr->lverts = cache->loose_geom.verts;
+ mr->vert_loose_len = cache->loose_geom.vert_len;
+ mr->edge_loose_len = cache->loose_geom.edge_len;
mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
}
@@ -55,76 +67,276 @@ static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtra
static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr,
MeshBufferExtractionCache *cache)
{
- /* Early exit: Are loose geometry already available. Only checking for loose verts as loose edges
- * and verts are calculated at the same time.*/
- if (cache->lverts) {
+ /* Early exit: Are loose geometry already available.
+ * Only checking for loose verts as loose edges and verts are calculated at the same time. */
+ if (cache->loose_geom.verts) {
return;
}
+ mesh_render_data_loose_geom_build(mr, cache);
+}
- cache->vert_loose_len = 0;
- cache->edge_loose_len = 0;
+static void mesh_render_data_loose_geom_build(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ cache->loose_geom.vert_len = 0;
+ cache->loose_geom.edge_len = 0;
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
+ mesh_render_data_loose_geom_mesh(mr, cache);
+ }
+ else {
+ /* #BMesh */
+ BMesh *bm = mr->bm;
+ mesh_render_data_lverts_bm(mr, cache, bm);
+ mesh_render_data_ledges_bm(mr, cache, bm);
+ }
+}
- BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
+static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
- cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
- const MEdge *med = mr->medge;
- for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
- if (med->flag & ME_LOOSEEDGE) {
- cache->ledges[cache->edge_loose_len++] = med_index;
- }
- /* Tag verts as not loose. */
- BLI_BITMAP_ENABLE(lvert_map, med->v1);
- BLI_BITMAP_ENABLE(lvert_map, med->v2);
+ cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ const MEdge *med = mr->medge;
+ for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
+ if (med->flag & ME_LOOSEEDGE) {
+ cache->loose_geom.edges[cache->loose_geom.edge_len++] = med_index;
}
- if (cache->edge_loose_len < mr->edge_len) {
- cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
+ /* Tag verts as not loose. */
+ BLI_BITMAP_ENABLE(lvert_map, med->v1);
+ BLI_BITMAP_ENABLE(lvert_map, med->v2);
+ }
+ if (cache->loose_geom.edge_len < mr->edge_len) {
+ cache->loose_geom.edges = MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ }
+
+ cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ for (int v = 0; v < mr->vert_len; v++) {
+ if (!BLI_BITMAP_TEST(lvert_map, v)) {
+ cache->loose_geom.verts[cache->loose_geom.vert_len++] = v;
}
+ }
+ if (cache->loose_geom.vert_len < mr->vert_len) {
+ cache->loose_geom.verts = MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ }
- cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
- for (int v = 0; v < mr->vert_len; v++) {
- if (!BLI_BITMAP_TEST(lvert_map, v)) {
- cache->lverts[cache->vert_loose_len++] = v;
- }
+ MEM_freeN(lvert_map);
+}
+
+static void mesh_render_data_lverts_bm(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ BMesh *bm)
+{
+ int elem_id;
+ BMIter iter;
+ BMVert *eve;
+ cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
+ if (eve->e == NULL) {
+ cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id;
}
- if (cache->vert_loose_len < mr->vert_len) {
- cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
+ }
+ if (cache->loose_geom.vert_len < mr->vert_len) {
+ cache->loose_geom.verts = MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ }
+}
+
+static void mesh_render_data_ledges_bm(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ BMesh *bm)
+{
+ int elem_id;
+ BMIter iter;
+ BMEdge *ede;
+ cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
+ if (ede->l == NULL) {
+ cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id;
}
+ }
+ if (cache->loose_geom.edge_len < mr->edge_len) {
+ cache->loose_geom.edges = MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ }
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Material Offsets
+ *
+ * Material offsets contains the offset of a material after sorting tris based on their material.
+ *
+ * \{ */
+static void mesh_render_data_mat_offset_load(MeshRenderData *mr,
+ const MeshBufferExtractionCache *cache);
+static void mesh_render_data_mat_offset_ensure(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+static void mesh_render_data_mat_offset_build(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+static void mesh_render_data_mat_offset_build_bm(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+static void mesh_render_data_mat_offset_build_mesh(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+static void mesh_render_data_mat_offset_apply_offset(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache);
+
+void mesh_render_data_update_mat_offsets(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ const eMRDataType data_flag)
+{
+ if (data_flag & MR_DATA_MAT_OFFSETS) {
+ mesh_render_data_mat_offset_ensure(mr, cache);
+ mesh_render_data_mat_offset_load(mr, cache);
+ }
+}
+
+static void mesh_render_data_mat_offset_load(MeshRenderData *mr,
+ const MeshBufferExtractionCache *cache)
+{
+ mr->mat_offsets.tri = cache->mat_offsets.tri;
+ mr->mat_offsets.visible_tri_len = cache->mat_offsets.visible_tri_len;
+}
+
+static void mesh_render_data_mat_offset_ensure(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ if (cache->mat_offsets.tri) {
+ return;
+ }
+ mesh_render_data_mat_offset_build(mr, cache);
+}
+
+static void mesh_render_data_mat_offset_build(MeshRenderData *mr, MeshBufferExtractionCache *cache)
+{
+ size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
+ cache->mat_offsets.tri = MEM_callocN(mat_tri_idx_size, __func__);
- MEM_freeN(lvert_map);
+ /* Count how many triangles for each material. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ mesh_render_data_mat_offset_build_bm(mr, cache);
}
else {
- /* #BMesh */
- BMesh *bm = mr->bm;
- int elem_id;
- BMIter iter;
- BMVert *eve;
- BMEdge *ede;
-
- cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*cache->lverts), __func__);
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
- if (eve->e == NULL) {
- cache->lverts[cache->vert_loose_len++] = elem_id;
- }
- }
- if (cache->vert_loose_len < mr->vert_len) {
- cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
- }
+ mesh_render_data_mat_offset_build_mesh(mr, cache);
+ }
- cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
- BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
- if (ede->l == NULL) {
- cache->ledges[cache->edge_loose_len++] = elem_id;
- }
- }
- if (cache->edge_loose_len < mr->edge_len) {
- cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
- }
+ mesh_render_data_mat_offset_apply_offset(mr, cache);
+}
+
+typedef struct MatOffsetUserData {
+ MeshRenderData *mr;
+ /** This struct is extended during allocation to hold mat_tri_len for each material. */
+ int mat_tri_len[0];
+} MatOffsetUserData;
+
+static void mesh_render_data_mat_offset_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ MatOffsetUserData *dst = chunk_join;
+ MatOffsetUserData *src = chunk;
+ int *dst_mat_len = dst->mat_tri_len;
+ int *src_mat_len = src->mat_tri_len;
+ for (int i = 0; i < dst->mr->mat_len; i++) {
+ dst_mat_len[i] += src_mat_len[i];
}
}
+static void mesh_render_data_mat_offset_build_threaded(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache,
+ int face_len,
+ TaskParallelRangeFunc range_func)
+{
+ /* Extending the #MatOffsetUserData with an int per material slot. */
+ size_t userdata_size = sizeof(MatOffsetUserData) +
+ (mr->mat_len) * sizeof(*cache->mat_offsets.tri);
+ MatOffsetUserData *userdata = MEM_callocN(userdata_size, __func__);
+ userdata->mr = mr;
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.userdata_chunk = userdata;
+ settings.userdata_chunk_size = userdata_size;
+ settings.min_iter_per_thread = MIN_RANGE_LEN;
+ settings.func_reduce = mesh_render_data_mat_offset_reduce;
+ BLI_task_parallel_range(0, face_len, NULL, range_func, &settings);
+
+ memcpy(cache->mat_offsets.tri,
+ &userdata->mat_tri_len,
+ (mr->mat_len) * sizeof(*cache->mat_offsets.tri));
+ MEM_freeN(userdata);
+}
+
+static void mesh_render_data_mat_offset_bm_range(void *__restrict UNUSED(userdata),
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
+{
+ MatOffsetUserData *mat_offset_userdata = tls->userdata_chunk;
+ MeshRenderData *mr = mat_offset_userdata->mr;
+ int *mat_tri_len = mat_offset_userdata->mat_tri_len;
+
+ BMesh *bm = mr->bm;
+ BMFace *efa = BM_face_at_index(bm, iter);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ int mat = min_ii(efa->mat_nr, mr->mat_len - 1);
+ mat_tri_len[mat] += efa->len - 2;
+ }
+}
+
+static void mesh_render_data_mat_offset_build_bm(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ BMesh *bm = mr->bm;
+ mesh_render_data_mat_offset_build_threaded(
+ mr, cache, bm->totface, mesh_render_data_mat_offset_bm_range);
+}
+
+static void mesh_render_data_mat_offset_mesh_range(void *__restrict UNUSED(userdata),
+ const int iter,
+ const TaskParallelTLS *__restrict tls)
+{
+ MatOffsetUserData *mat_offset_userdata = tls->userdata_chunk;
+ const MeshRenderData *mr = mat_offset_userdata->mr;
+ int *mat_tri_len = mat_offset_userdata->mat_tri_len;
+
+ const MPoly *mp = &mr->mpoly[iter];
+ if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
+ int mat = min_ii(mp->mat_nr, mr->mat_len - 1);
+ mat_tri_len[mat] += mp->totloop - 2;
+ }
+}
+
+static void mesh_render_data_mat_offset_build_mesh(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ mesh_render_data_mat_offset_build_threaded(
+ mr, cache, mr->poly_len, mesh_render_data_mat_offset_mesh_range);
+}
+
+static void mesh_render_data_mat_offset_apply_offset(MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ int *mat_tri_len = cache->mat_offsets.tri;
+ int ofs = mat_tri_len[0];
+ mat_tri_len[0] = 0;
+ for (int i = 1; i < mr->mat_len; i++) {
+ int tmp = mat_tri_len[i];
+ mat_tri_len[i] = ofs;
+ ofs += tmp;
+ }
+ cache->mat_offsets.visible_tri_len = ofs;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
+ * \{ */
+
/**
* Part of the creation of the #MeshRenderData that happens in a thread.
*/
@@ -136,9 +348,23 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ /* NOTE(campbell): It's possible to skip allocating tessellation,
+ * the tessellation can be calculated as part of the iterator, see: P2188.
+ * The overall advantage is small (around 1%), so keep this as-is. */
mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
+ if (mr->poly_normals != NULL) {
+ BKE_mesh_recalc_looptri_with_normals(me->mloop,
+ me->mpoly,
+ me->mvert,
+ me->totloop,
+ me->totpoly,
+ mr->mlooptri,
+ mr->poly_normals);
+ }
+ else {
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
+ }
}
}
else {
@@ -159,16 +385,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
- mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
- BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
- NULL,
- mr->vert_len,
- mr->mloop,
- mr->mpoly,
- mr->loop_len,
- mr->poly_len,
- mr->poly_normals,
- true);
+ BKE_mesh_ensure_normals_for_display(mr->me);
+ mr->poly_normals = CustomData_get_layer(&mr->me->pdata, CD_NORMAL);
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
@@ -358,14 +576,13 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
void mesh_render_data_free(MeshRenderData *mr)
{
MEM_SAFE_FREE(mr->mlooptri);
- MEM_SAFE_FREE(mr->poly_normals);
MEM_SAFE_FREE(mr->loop_normals);
- /* Loose geometry are owned by MeshBufferExtractionCache. */
+ /* Loose geometry are owned by #MeshBufferExtractionCache. */
mr->ledges = NULL;
mr->lverts = NULL;
MEM_freeN(mr);
}
-/** \} */ \ No newline at end of file
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 3cc71e47f28..3b70490509d 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -67,12 +67,109 @@
#include "ED_uvedit.h"
#include "draw_cache_extract.h"
+#include "draw_cache_extract_mesh_private.h"
#include "draw_cache_inline.h"
#include "draw_cache_impl.h" /* own include */
+MDEPS_CREATE(vbo_lnor, batch.surface, batch.wire_loops, batch.edit_lnor, surface_per_mat);
+MDEPS_CREATE(vbo_pos_nor,
+ batch.surface,
+ batch.surface_weights,
+ batch.all_verts,
+ batch.all_edges,
+ batch.loose_edges,
+ batch.edge_detection,
+ batch.wire_loops,
+ batch.wire_edges,
+ batch.edit_vnor,
+ batch.edit_lnor,
+ batch.edit_vertices,
+ batch.edit_edges,
+ batch.edit_triangles,
+ batch.edit_selection_verts,
+ batch.edit_selection_edges,
+ batch.edit_selection_faces,
+ batch.edit_mesh_analysis,
+ batch.sculpt_overlays,
+ surface_per_mat);
+MDEPS_CREATE(vbo_uv,
+ batch.surface,
+ batch.wire_loops_uvs,
+ batch.edituv_faces,
+ batch.edituv_faces_stretch_area,
+ batch.edituv_faces_stretch_angle,
+ batch.edituv_edges,
+ batch.edituv_verts,
+ surface_per_mat);
+MDEPS_CREATE(vbo_vcol, batch.surface, surface_per_mat);
+MDEPS_CREATE(vbo_sculpt_data, batch.sculpt_overlays);
+MDEPS_CREATE(vbo_weights, batch.surface_weights);
+MDEPS_CREATE(vbo_edge_fac, batch.wire_edges);
+MDEPS_CREATE(vbo_mesh_analysis, batch.edit_mesh_analysis);
+MDEPS_CREATE(vbo_tan, surface_per_mat);
+MDEPS_CREATE(vbo_orco, surface_per_mat);
+MDEPS_CREATE(vbo_edit_data, batch.edit_triangles, batch.edit_edges, batch.edit_vertices);
+MDEPS_CREATE(vbo_fdots_pos, batch.edit_fdots, batch.edit_selection_fdots);
+MDEPS_CREATE(vbo_fdots_nor, batch.edit_fdots);
+MDEPS_CREATE(vbo_skin_roots, batch.edit_skin_roots);
+MDEPS_CREATE(vbo_vert_idx, batch.edit_selection_verts);
+MDEPS_CREATE(vbo_edge_idx, batch.edit_selection_edges);
+MDEPS_CREATE(vbo_poly_idx, batch.edit_selection_faces);
+MDEPS_CREATE(vbo_fdot_idx, batch.edit_selection_fdots);
+MDEPS_CREATE(vbo_edituv_data,
+ batch.edituv_faces,
+ batch.edituv_faces_stretch_area,
+ batch.edituv_faces_stretch_angle,
+ batch.edituv_edges,
+ batch.edituv_verts);
+MDEPS_CREATE(vbo_edituv_stretch_area, batch.edituv_faces_stretch_area);
+MDEPS_CREATE(vbo_edituv_stretch_angle, batch.edituv_faces_stretch_angle);
+MDEPS_CREATE(vbo_fdots_uv, batch.edituv_fdots);
+MDEPS_CREATE(vbo_fdots_edituv_data, batch.edituv_fdots);
+
+MDEPS_CREATE(ibo_tris,
+ batch.surface,
+ batch.sculpt_overlays,
+ batch.surface_weights,
+ batch.edit_mesh_analysis,
+ batch.edit_triangles,
+ batch.edit_lnor,
+ batch.edit_selection_faces);
+MDEPS_CREATE(
+ ibo_lines, batch.all_edges, batch.wire_edges, batch.edit_edges, batch.edit_selection_edges);
+MDEPS_CREATE(ibo_lines_loose, batch.loose_edges);
+MDEPS_CREATE(ibo_lines_adjacency, batch.edge_detection);
+MDEPS_CREATE(ibo_lines_paint_mask, batch.wire_loops);
+MDEPS_CREATE(ibo_tris_per_mat, surface_per_mat);
+MDEPS_CREATE(ibo_points, batch.edit_vnor, batch.edit_selection_verts, batch.edit_vertices);
+MDEPS_CREATE(ibo_fdots, batch.edit_fdots, batch.edit_selection_fdots);
+MDEPS_CREATE(ibo_edituv_tris,
+ batch.edituv_faces,
+ batch.edituv_faces_stretch_area,
+ batch.edituv_faces_stretch_angle);
+MDEPS_CREATE(ibo_edituv_lines, batch.edituv_edges, batch.wire_loops_uvs);
+MDEPS_CREATE(ibo_edituv_points, batch.edituv_verts);
+MDEPS_CREATE(ibo_edituv_fdots, batch.edituv_fdots);
+
+static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache);
static void mesh_batch_cache_clear(Mesh *me);
+static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map)
+{
+ for (int i = 0; i < MBC_BATCH_LEN; i++) {
+ DRWBatchFlag batch_requested = (1u << i);
+ if (batch_map & batch_requested) {
+ GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]);
+ cache->batch_ready &= ~batch_requested;
+ }
+ }
+
+ if (batch_map & (1u << MBC_BATCH_INDEX(surface_per_mat))) {
+ mesh_batch_cache_discard_surface_batches(cache);
+ }
+}
+
/* Return true is all layers in _b_ are inside _a_. */
BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
@@ -562,14 +659,8 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco);
}
- /* Discard batches using vbo.uv. */
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
-
- mesh_batch_cache_discard_surface_batches(cache);
+ DRWBatchFlag batch_map = MDEPS_CREATE_MAP(vbo_uv, vbo_tan, vbo_vcol, vbo_orco);
+ mesh_batch_cache_discard_batch(cache, batch_map);
mesh_cd_layers_type_clear(&cache->cd_used);
}
@@ -587,13 +678,17 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
- GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
+ DRWBatchFlag batch_map = MDEPS_CREATE_MAP(vbo_edituv_stretch_angle,
+ vbo_edituv_stretch_area,
+ vbo_uv,
+ vbo_edituv_data,
+ vbo_fdots_uv,
+ vbo_fdots_edituv_data,
+ ibo_edituv_tris,
+ ibo_edituv_lines,
+ ibo_edituv_points,
+ ibo_edituv_fdots);
+ mesh_batch_cache_discard_batch(cache, batch_map);
cache->tot_area = 0.0f;
cache->tot_uv_area = 0.0f;
@@ -603,9 +698,6 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
/* We discarded the vbo.uv so we need to reset the cd_used flag. */
cache->cd_used.uv = 0;
cache->cd_used.edit_uv = 0;
-
- /* Discard other batches that uses vbo.uv */
- mesh_batch_cache_discard_surface_batches(cache);
}
static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
@@ -618,14 +710,13 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
- GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
- cache->batch_ready &= ~MBC_EDITUV;
+ DRWBatchFlag batch_map = MDEPS_CREATE_MAP(vbo_edituv_data,
+ vbo_fdots_edituv_data,
+ ibo_edituv_tris,
+ ibo_edituv_lines,
+ ibo_edituv_points,
+ ibo_edituv_fdots);
+ mesh_batch_cache_discard_batch(cache, batch_map);
}
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
@@ -634,25 +725,16 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
if (cache == NULL) {
return;
}
+ DRWBatchFlag batch_map;
switch (mode) {
case BKE_MESH_BATCH_DIRTY_SELECT:
FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edit_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_triangles);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_vertices);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_fdots);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_faces);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_fdots);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_mesh_analysis);
- cache->batch_ready &= ~(MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES | MBC_EDIT_EDGES |
- MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS |
- MBC_EDIT_SELECTION_FACES | MBC_EDIT_SELECTION_EDGES |
- MBC_EDIT_SELECTION_VERTS | MBC_EDIT_MESH_ANALYSIS);
+ batch_map = MDEPS_CREATE_MAP(vbo_edit_data, vbo_fdots_nor);
+ mesh_batch_cache_discard_batch(cache, batch_map);
+
/* Because visible UVs depends on edit mode selection, discard topology. */
mesh_batch_cache_discard_uvedit_select(cache);
break;
@@ -664,20 +746,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.surface);
- /* Discard batches using vbo.pos_nor. */
- GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops);
- GPU_BATCH_DISCARD_SAFE(cache->batch.wire_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.all_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.all_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.loose_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edge_detection);
- GPU_BATCH_DISCARD_SAFE(cache->batch.surface_weights);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_mesh_analysis);
- /* Discard batches using vbo.lnor. */
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_lnor);
- mesh_batch_cache_discard_surface_batches(cache);
- cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS);
+ batch_map = MDEPS_CREATE_MAP(ibo_lines_paint_mask, vbo_pos_nor, vbo_lnor);
+ mesh_batch_cache_discard_batch(cache, batch_map);
break;
case BKE_MESH_BATCH_DIRTY_ALL:
cache->is_dirty = true;
@@ -694,13 +764,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
- cache->batch_ready &= ~MBC_EDITUV;
+ batch_map = MDEPS_CREATE_MAP(vbo_edituv_data, vbo_fdots_edituv_data);
+ mesh_batch_cache_discard_batch(cache, batch_map);
break;
default:
BLI_assert(0);
@@ -721,10 +786,12 @@ static void mesh_buffer_cache_clear(MeshBufferCache *mbufcache)
static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extraction_cache)
{
- MEM_SAFE_FREE(extraction_cache->lverts);
- MEM_SAFE_FREE(extraction_cache->ledges);
- extraction_cache->edge_loose_len = 0;
- extraction_cache->vert_loose_len = 0;
+ MEM_SAFE_FREE(extraction_cache->loose_geom.verts);
+ MEM_SAFE_FREE(extraction_cache->loose_geom.edges);
+ extraction_cache->loose_geom.edge_len = 0;
+ extraction_cache->loose_geom.vert_len = 0;
+
+ MEM_SAFE_FREE(extraction_cache->mat_offsets.tri);
}
static void mesh_batch_cache_clear(Mesh *me)
@@ -1232,7 +1299,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* Don't check `DRW_object_is_in_edit_mode(ob)` here because it means the same mesh
* may draw with edit-mesh data and regular mesh data.
- * In this case the custom-data layers used wont always match in `me->runtime.batch_cache`.
+ * In this case the custom-data layers used won't always match in `me->runtime.batch_cache`.
* If we want to display regular mesh data, we should have a separate cache for the edit-mesh.
* See T77359. */
const bool is_editmode = (me->edit_mesh != NULL) &&
@@ -1370,6 +1437,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MeshBufferCache *mbufcache = &cache->final;
/* Initialize batches and request VBO's & IBO's. */
+ MDEPS_ASSERT(batch.surface, ibo_tris, vbo_lnor, vbo_pos_nor, vbo_uv, vbo_vcol);
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbufcache->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
@@ -1382,43 +1450,52 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol);
}
}
+ MDEPS_ASSERT(batch.all_verts, vbo_pos_nor);
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.all_verts, &mbufcache->vbo.pos_nor);
}
+ MDEPS_ASSERT(batch.sculpt_overlays, ibo_tris, vbo_pos_nor, vbo_sculpt_data);
if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.sculpt_overlays, &mbufcache->ibo.tris);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbufcache->vbo.sculpt_data);
}
+ MDEPS_ASSERT(batch.all_edges, ibo_lines, vbo_pos_nor);
if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.all_edges, &mbufcache->ibo.lines);
DRW_vbo_request(cache->batch.all_edges, &mbufcache->vbo.pos_nor);
}
+ MDEPS_ASSERT(batch.loose_edges, ibo_lines_loose, vbo_pos_nor);
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(NULL, &mbufcache->ibo.lines);
DRW_ibo_request(cache->batch.loose_edges, &mbufcache->ibo.lines_loose);
DRW_vbo_request(cache->batch.loose_edges, &mbufcache->vbo.pos_nor);
}
+ MDEPS_ASSERT(batch.edge_detection, ibo_lines_adjacency, vbo_pos_nor);
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
DRW_ibo_request(cache->batch.edge_detection, &mbufcache->ibo.lines_adjacency);
DRW_vbo_request(cache->batch.edge_detection, &mbufcache->vbo.pos_nor);
}
+ MDEPS_ASSERT(batch.surface_weights, ibo_tris, vbo_pos_nor, vbo_weights);
if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface_weights, &mbufcache->ibo.tris);
DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.weights);
}
+ MDEPS_ASSERT(batch.wire_loops, ibo_lines_paint_mask, vbo_lnor, vbo_pos_nor);
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor);
}
+ MDEPS_ASSERT(batch.wire_edges, ibo_lines, vbo_pos_nor, vbo_edge_fac);
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_edges, &mbufcache->ibo.lines);
DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.edge_fac);
}
+ MDEPS_ASSERT(batch.wire_loops_uvs, ibo_edituv_lines, vbo_uv);
if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops_uvs, &mbufcache->ibo.edituv_lines);
/* For paint overlay. Active layer should have been queried. */
@@ -1426,6 +1503,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
DRW_vbo_request(cache->batch.wire_loops_uvs, &mbufcache->vbo.uv);
}
}
+ MDEPS_ASSERT(batch.edit_mesh_analysis, ibo_tris, vbo_pos_nor, vbo_mesh_analysis);
if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbufcache->ibo.tris);
DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.pos_nor);
@@ -1433,6 +1511,14 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
/* Per Material */
+ MDEPS_ASSERT(surface_per_mat,
+ ibo_tris_per_mat,
+ vbo_lnor,
+ vbo_pos_nor,
+ vbo_uv,
+ vbo_tan,
+ vbo_vcol,
+ vbo_orco);
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->surface_per_mat[i], &mbufcache->tris_per_mat[i]);
@@ -1457,55 +1543,66 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbufcache = (do_cage) ? &cache->cage : &cache->final;
/* Edit Mesh */
+ MDEPS_ASSERT(batch.edit_triangles, ibo_tris, vbo_pos_nor, vbo_edit_data);
if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_triangles, &mbufcache->ibo.tris);
DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.edit_data);
}
+ MDEPS_ASSERT(batch.edit_vertices, ibo_points, vbo_pos_nor, vbo_edit_data);
if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vertices, &mbufcache->ibo.points);
DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.edit_data);
}
+ MDEPS_ASSERT(batch.edit_edges, ibo_lines, vbo_pos_nor, vbo_edit_data);
if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_edges, &mbufcache->ibo.lines);
DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.edit_data);
}
+ MDEPS_ASSERT(batch.edit_vnor, ibo_points, vbo_pos_nor);
if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vnor, &mbufcache->ibo.points);
DRW_vbo_request(cache->batch.edit_vnor, &mbufcache->vbo.pos_nor);
}
+ MDEPS_ASSERT(batch.edit_lnor, ibo_tris, vbo_pos_nor, vbo_lnor);
if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_lnor, &mbufcache->ibo.tris);
DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.lnor);
}
+ MDEPS_ASSERT(batch.edit_fdots, ibo_fdots, vbo_fdots_pos, vbo_fdots_nor);
if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_fdots, &mbufcache->ibo.fdots);
DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos);
DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor);
}
+ MDEPS_ASSERT(batch.edit_skin_roots, vbo_skin_roots);
if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.edit_skin_roots, &mbufcache->vbo.skin_roots);
}
/* Selection */
+ MDEPS_ASSERT(batch.edit_selection_verts, ibo_points, vbo_pos_nor, vbo_vert_idx);
if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_verts, &mbufcache->ibo.points);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.vert_idx);
}
+ MDEPS_ASSERT(batch.edit_selection_edges, ibo_lines, vbo_pos_nor, vbo_edge_idx);
if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_selection_edges, &mbufcache->ibo.lines);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.edge_idx);
}
+ MDEPS_ASSERT(batch.edit_selection_faces, ibo_tris, vbo_pos_nor, vbo_poly_idx);
if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_selection_faces, &mbufcache->ibo.tris);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.poly_idx);
}
+ MDEPS_ASSERT(batch.edit_selection_fdots, ibo_fdots, vbo_fdots_pos, vbo_fdot_idx);
if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_fdots, &mbufcache->ibo.fdots);
DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdots_pos);
@@ -1520,39 +1617,90 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbufcache = (do_uvcage) ? &cache->uv_cage : &cache->final;
/* Edit UV */
+ MDEPS_ASSERT(batch.edituv_faces, ibo_edituv_tris, vbo_uv, vbo_edituv_data);
if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces, &mbufcache->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.edituv_data);
}
+ MDEPS_ASSERT(batch.edituv_faces_stretch_area,
+ ibo_edituv_tris,
+ vbo_uv,
+ vbo_edituv_data,
+ vbo_edituv_stretch_area);
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_stretch_area);
}
+ MDEPS_ASSERT(batch.edituv_faces_stretch_angle,
+ ibo_edituv_tris,
+ vbo_uv,
+ vbo_edituv_data,
+ vbo_edituv_stretch_angle);
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_stretch_angle);
}
+ MDEPS_ASSERT(batch.edituv_edges, ibo_edituv_lines, vbo_uv, vbo_edituv_data);
if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines);
DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.edituv_data);
}
+ MDEPS_ASSERT(batch.edituv_verts, ibo_edituv_points, vbo_uv, vbo_edituv_data);
if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_verts, &mbufcache->ibo.edituv_points);
DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.edituv_data);
}
+ MDEPS_ASSERT(batch.edituv_fdots, ibo_edituv_fdots, vbo_fdots_uv, vbo_fdots_edituv_data);
if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_fdots, &mbufcache->ibo.edituv_fdots);
DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_uv);
DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_edituv_data);
}
+ MDEPS_ASSERT_MAP(vbo_lnor);
+ MDEPS_ASSERT_MAP(vbo_pos_nor);
+ MDEPS_ASSERT_MAP(vbo_uv);
+ MDEPS_ASSERT_MAP(vbo_vcol);
+ MDEPS_ASSERT_MAP(vbo_sculpt_data);
+ MDEPS_ASSERT_MAP(vbo_weights);
+ MDEPS_ASSERT_MAP(vbo_edge_fac);
+ MDEPS_ASSERT_MAP(vbo_mesh_analysis);
+ MDEPS_ASSERT_MAP(vbo_tan);
+ MDEPS_ASSERT_MAP(vbo_orco);
+ MDEPS_ASSERT_MAP(vbo_edit_data);
+ MDEPS_ASSERT_MAP(vbo_fdots_pos);
+ MDEPS_ASSERT_MAP(vbo_fdots_nor);
+ MDEPS_ASSERT_MAP(vbo_skin_roots);
+ MDEPS_ASSERT_MAP(vbo_vert_idx);
+ MDEPS_ASSERT_MAP(vbo_edge_idx);
+ MDEPS_ASSERT_MAP(vbo_poly_idx);
+ MDEPS_ASSERT_MAP(vbo_fdot_idx);
+ MDEPS_ASSERT_MAP(vbo_edituv_data);
+ MDEPS_ASSERT_MAP(vbo_edituv_stretch_area);
+ MDEPS_ASSERT_MAP(vbo_edituv_stretch_angle);
+ MDEPS_ASSERT_MAP(vbo_fdots_uv);
+ MDEPS_ASSERT_MAP(vbo_fdots_edituv_data);
+
+ MDEPS_ASSERT_MAP(ibo_tris);
+ MDEPS_ASSERT_MAP(ibo_lines);
+ MDEPS_ASSERT_MAP(ibo_lines_loose);
+ MDEPS_ASSERT_MAP(ibo_lines_adjacency);
+ MDEPS_ASSERT_MAP(ibo_lines_paint_mask);
+ MDEPS_ASSERT_MAP(ibo_tris_per_mat);
+ MDEPS_ASSERT_MAP(ibo_points);
+ MDEPS_ASSERT_MAP(ibo_fdots);
+ MDEPS_ASSERT_MAP(ibo_edituv_tris);
+ MDEPS_ASSERT_MAP(ibo_edituv_lines);
+ MDEPS_ASSERT_MAP(ibo_edituv_points);
+ MDEPS_ASSERT_MAP(ibo_edituv_fdots);
+
/* Meh loose Scene const correctness here. */
const bool use_subsurf_fdots = scene ? BKE_modifiers_uses_subsurf_facedots(scene, ob) : false;
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 585e171adc5..d101df737ff 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -43,26 +43,26 @@
#include "GPU_vertex_buffer.h"
#include "draw_hair_private.h"
+#include "draw_shader.h"
#ifndef __APPLE__
# define USE_TRANSFORM_FEEDBACK
# define USE_COMPUTE_SHADERS
#endif
-BLI_INLINE bool drw_hair_use_compute_shaders(void)
+BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
{
#ifdef USE_COMPUTE_SHADERS
- return GPU_compute_shader_support();
-#else
- return false;
+ if (GPU_compute_shader_support()) {
+ return PART_REFINE_SHADER_COMPUTE;
+ }
#endif
+#ifdef USE_TRANSFORM_FEEDBACK
+ return PART_REFINE_SHADER_TRANSFORM_FEEDBACK;
+#endif
+ return PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND;
}
-typedef enum ParticleRefineShader {
- PART_REFINE_CATMULL_ROM = 0,
- PART_REFINE_MAX_SHADER,
-} ParticleRefineShader;
-
#ifndef USE_TRANSFORM_FEEDBACK
typedef struct ParticleRefineCall {
struct ParticleRefineCall *next;
@@ -79,89 +79,11 @@ static int g_tf_target_height;
static GPUVertBuf *g_dummy_vbo = NULL;
static GPUTexture *g_dummy_texture = NULL;
-static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL};
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
-extern char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_hair_refine_vert_glsl[];
-extern char datatoc_common_hair_refine_comp_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-
-/* TODO(jbakker): move shader creation to `draw_shaders` and add test cases. */
-/* TODO(jbakker): replace defines with `constexpr` to check compilation on all OS's.
- * Currently the `__APPLE__` code-path does not compile on other platforms and vice versa. */
-#ifdef USE_COMPUTE_SHADERS
-static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement))
-{
- GPUShader *sh = NULL;
- sh = GPU_shader_create_compute(datatoc_common_hair_refine_comp_glsl,
- datatoc_common_hair_lib_glsl,
- "#define HAIR_PHASE_SUBDIV\n",
- __func__);
- return sh;
-}
-#endif
-
-#ifdef USE_TRANSFORM_FEEDBACK
-static GPUShader *hair_refine_shader_transform_feedback_create(
- ParticleRefineShader UNUSED(refinement))
-{
- GPUShader *sh = NULL;
-
- char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
- datatoc_common_hair_refine_vert_glsl);
- const char *var_names[1] = {"finalColor"};
- sh = DRW_shader_create_with_transform_feedback(
- shader_src, NULL, "#define HAIR_PHASE_SUBDIV\n", GPU_SHADER_TFB_POINTS, var_names, 1);
- MEM_freeN(shader_src);
-
- return sh;
-}
-#endif
-
-static GPUShader *hair_refine_shader_transform_feedback_workaround_create(
- ParticleRefineShader UNUSED(refinement))
-{
- GPUShader *sh = NULL;
-
- char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
- datatoc_common_hair_refine_vert_glsl);
- sh = DRW_shader_create(shader_src,
- NULL,
- datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- "#define blender_srgb_to_framebuffer_space(a) a\n"
- "#define HAIR_PHASE_SUBDIV\n"
- "#define TF_WORKAROUND\n");
- MEM_freeN(shader_src);
-
- return sh;
-}
-
static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
{
- if (g_refine_shaders[refinement]) {
- return g_refine_shaders[refinement];
- }
-
-#ifdef USE_COMPUTE_SHADERS
- if (drw_hair_use_compute_shaders()) {
- g_refine_shaders[refinement] = hair_refine_shader_compute_create(refinement);
- if (g_refine_shaders[refinement]) {
- return g_refine_shaders[refinement];
- }
- }
-#endif
-
-#ifdef USE_TRANSFORM_FEEDBACK
- g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_create(refinement);
- if (g_refine_shaders[refinement]) {
- return g_refine_shaders[refinement];
- }
-#endif
-
- g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_workaround_create(
- refinement);
- return g_refine_shaders[refinement];
+ return DRW_shader_hair_refine_get(refinement, drw_hair_shader_type_get());
}
void DRW_hair_init(void)
@@ -265,7 +187,7 @@ static ParticleHairCache *drw_hair_particle_cache_get(
}
if (update) {
- if (drw_hair_use_compute_shaders()) {
+ if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
drw_hair_particle_cache_update_compute(cache, subdiv);
}
else {
@@ -473,7 +395,7 @@ void DRW_hair_update(void)
#else
/* Just render the pass when using compute shaders or transform feedback. */
DRW_draw_pass(g_tf_pass);
- if (drw_hair_use_compute_shaders()) {
+ if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
}
#endif
@@ -481,10 +403,6 @@ void DRW_hair_update(void)
void DRW_hair_free(void)
{
- for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
- DRW_SHADER_FREE_SAFE(g_refine_shaders[i]);
- }
-
GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
}
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 28bd5d4dfb5..1f58d8d0ead 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -23,11 +23,20 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MAX_LAYER_NAME_CT 4 /* u0123456789, u, au, a0123456789 */
#define MAX_LAYER_NAME_LEN (GPU_MAX_SAFE_ATTR_NAME + 2)
#define MAX_THICKRES 2 /* see eHairType */
#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */
+typedef enum ParticleRefineShader {
+ PART_REFINE_CATMULL_ROM = 0,
+ PART_REFINE_MAX_SHADER,
+} ParticleRefineShader;
+
struct ModifierData;
struct Object;
struct ParticleHairCache;
@@ -91,3 +100,7 @@ bool hair_ensure_procedural_data(struct Object *object,
struct ParticleHairCache **r_hair_cache,
int subdiv,
int thickness_res);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 37f6bbf52b5..8a805409b27 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -87,6 +87,7 @@
#include "draw_manager_profiling.h"
#include "draw_manager_testing.h"
#include "draw_manager_text.h"
+#include "draw_shader.h"
/* only for callbacks */
#include "draw_cache_impl.h"
@@ -2987,6 +2988,7 @@ void DRW_engines_free(void)
DRW_TEXTURE_FREE_SAFE(g_select_buffer.texture_depth);
GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer_depth_only);
+ DRW_shaders_free();
DRW_hair_free();
DRW_shape_cache_free();
DRW_stats_free();
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 3b852e7f8c8..56909969dd7 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1572,8 +1572,8 @@ static void draw_frustum_culling_planes_calc(const float (*persmat)[4], float (*
planes_from_projmat(persmat,
frustum_planes[0],
frustum_planes[5],
- frustum_planes[3],
frustum_planes[1],
+ frustum_planes[3],
frustum_planes[4],
frustum_planes[2]);
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index 9bfc8d98fe4..783ec1b1d7d 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -41,7 +41,7 @@
#define MAX_TIMER_NAME 32
#define MAX_NESTED_TIMER 8
-#define CHUNK_SIZE 8
+#define MIM_RANGE_LEN 8
#define GPU_TIMER_FALLOFF 0.1
typedef struct DRWTimer {
@@ -82,7 +82,7 @@ void DRW_stats_begin(void)
if (DTP.is_recording && DTP.timers == NULL) {
DTP.chunk_count = 1;
- DTP.timer_count = DTP.chunk_count * CHUNK_SIZE;
+ DTP.timer_count = DTP.chunk_count * MIM_RANGE_LEN;
DTP.timers = MEM_callocN(sizeof(DRWTimer) * DTP.timer_count, "DRWTimer stack");
}
else if (!DTP.is_recording && DTP.timers != NULL) {
@@ -99,7 +99,7 @@ static DRWTimer *drw_stats_timer_get(void)
if (UNLIKELY(DTP.timer_increment >= DTP.timer_count)) {
/* Resize the stack. */
DTP.chunk_count++;
- DTP.timer_count = DTP.chunk_count * CHUNK_SIZE;
+ DTP.timer_count = DTP.chunk_count * MIM_RANGE_LEN;
DTP.timers = MEM_recallocN(DTP.timers, sizeof(DRWTimer) * DTP.timer_count);
}
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c
new file mode 100644
index 00000000000..9c756065353
--- /dev/null
+++ b/source/blender/draw/intern/draw_shader.c
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
+
+#include "GPU_batch.h"
+#include "GPU_index_buffer.h"
+#include "GPU_vertex_buffer.h"
+
+#include "draw_shader.h"
+
+extern char datatoc_common_hair_lib_glsl[];
+
+extern char datatoc_common_hair_refine_vert_glsl[];
+extern char datatoc_common_hair_refine_comp_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
+static struct {
+ struct GPUShader *hair_refine_sh[PART_REFINE_MAX_SHADER];
+} e_data = {{NULL}};
+
+/* -------------------------------------------------------------------- */
+/** \name Hair refinement
+ * \{ */
+
+static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement))
+{
+ GPUShader *sh = NULL;
+ sh = GPU_shader_create_compute(datatoc_common_hair_refine_comp_glsl,
+ datatoc_common_hair_lib_glsl,
+ "#define HAIR_PHASE_SUBDIV\n",
+ __func__);
+ return sh;
+}
+
+static GPUShader *hair_refine_shader_transform_feedback_create(
+ ParticleRefineShader UNUSED(refinement))
+{
+ GPUShader *sh = NULL;
+
+ char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
+ datatoc_common_hair_refine_vert_glsl);
+ const char *var_names[1] = {"finalColor"};
+ sh = DRW_shader_create_with_transform_feedback(
+ shader_src, NULL, "#define HAIR_PHASE_SUBDIV\n", GPU_SHADER_TFB_POINTS, var_names, 1);
+ MEM_freeN(shader_src);
+
+ return sh;
+}
+
+static GPUShader *hair_refine_shader_transform_feedback_workaround_create(
+ ParticleRefineShader UNUSED(refinement))
+{
+ GPUShader *sh = NULL;
+
+ char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
+ datatoc_common_hair_refine_vert_glsl);
+ sh = DRW_shader_create(shader_src,
+ NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ "#define blender_srgb_to_framebuffer_space(a) a\n"
+ "#define HAIR_PHASE_SUBDIV\n"
+ "#define TF_WORKAROUND\n");
+ MEM_freeN(shader_src);
+
+ return sh;
+}
+
+GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
+ eParticleRefineShaderType sh_type)
+{
+ if (e_data.hair_refine_sh[refinement] == NULL) {
+ GPUShader *sh = NULL;
+ switch (sh_type) {
+ case PART_REFINE_SHADER_COMPUTE:
+ sh = hair_refine_shader_compute_create(refinement);
+ break;
+ case PART_REFINE_SHADER_TRANSFORM_FEEDBACK:
+ sh = hair_refine_shader_transform_feedback_create(refinement);
+ break;
+ case PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND:
+ sh = hair_refine_shader_transform_feedback_workaround_create(refinement);
+ break;
+ default:
+ BLI_assert(!"Incorrect shader type");
+ }
+ e_data.hair_refine_sh[refinement] = sh;
+ }
+
+ return e_data.hair_refine_sh[refinement];
+}
+
+/** \} */
+
+void DRW_shaders_free(void)
+{
+ for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
+ DRW_SHADER_FREE_SAFE(e_data.hair_refine_sh[i]);
+ }
+}
diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h
new file mode 100644
index 00000000000..f9fa452671b
--- /dev/null
+++ b/source/blender/draw/intern/draw_shader.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.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#pragma once
+
+#include "draw_hair_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GPUShader;
+
+typedef enum eParticleRefineShaderType {
+ PART_REFINE_SHADER_TRANSFORM_FEEDBACK,
+ PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND,
+ PART_REFINE_SHADER_COMPUTE,
+} eParticleRefineShaderType;
+
+/* draw_shader.c */
+struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
+ eParticleRefineShaderType sh_type);
+void DRW_shaders_free(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index 20b0ec738ee..2dff101c71f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -37,15 +37,14 @@ struct MeshExtract_EditUvElem_Data {
bool sync_selection;
};
-static void *extract_edituv_tris_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_edituv_tris_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
- MEM_callocN(sizeof(*data), __func__));
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- return data;
}
BLI_INLINE void edituv_tri_add(
@@ -93,17 +92,17 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
- MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_tris()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_tris_init;
extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh;
extractor.finish = extract_edituv_tris_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_tris);
return extractor;
@@ -115,15 +114,14 @@ constexpr MeshExtract create_extractor_edituv_tris()
/** \name Extract Edit UV Line Indices around faces
* \{ */
-static void *extract_edituv_lines_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_edituv_lines_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
- MEM_callocN(sizeof(*data), __func__));
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->loop_len, mr->loop_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- return data;
}
BLI_INLINE void edituv_edge_add(
@@ -135,7 +133,7 @@ BLI_INLINE void edituv_edge_add(
}
static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -184,17 +182,17 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
- MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_lines()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_lines_init;
extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh;
extractor.finish = extract_edituv_lines_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_lines);
return extractor;
@@ -206,15 +204,14 @@ constexpr MeshExtract create_extractor_edituv_lines()
/** \name Extract Edit UV Points Indices
* \{ */
-static void *extract_edituv_points_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_edituv_points_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
- MEM_callocN(sizeof(*data), __func__));
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->loop_len, mr->loop_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- return data;
}
BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
@@ -228,7 +225,7 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
}
static void extract_edituv_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@@ -269,17 +266,17 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
- MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_points()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_points_init;
extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh;
extractor.finish = extract_edituv_points_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_points);
return extractor;
@@ -291,15 +288,14 @@ constexpr MeshExtract create_extractor_edituv_points()
/** \name Extract Edit UV Face-dots Indices
* \{ */
-static void *extract_edituv_fdots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_edituv_fdots_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
- MEM_callocN(sizeof(*data), __func__));
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
- return data;
}
BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
@@ -316,7 +312,7 @@ BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
}
static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int f_index,
void *_data)
{
@@ -366,17 +362,17 @@ static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
- MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_fdots()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_fdots_init;
extractor.iter_poly_bm = extract_edituv_fdots_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh;
extractor.finish = extract_edituv_fdots_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_fdots);
return extractor;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index 9bd918dc9a5..c21725ffa32 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -32,17 +32,17 @@ namespace blender::draw {
/** \name Extract Face-dots Indices
* \{ */
-static void *extract_fdots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf))
+static void extract_fdots_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
- return elb;
}
static void extract_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int f_index,
void *_userdata)
{
@@ -93,17 +93,17 @@ static void extract_fdots_finish(const MeshRenderData *UNUSED(mr),
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
- MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_fdots()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_fdots_init;
extractor.iter_poly_bm = extract_fdots_iter_poly_bm;
extractor.iter_poly_mesh = extract_fdots_iter_poly_mesh;
extractor.finish = extract_fdots_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.fdots);
return extractor;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 74a3d3825c5..2c2603af1b2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -31,28 +31,19 @@ namespace blender::draw {
/** \name Extract Edges Indices
* \{ */
-static void *extract_lines_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf))
+static void extract_lines_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
/* Put loose edges at the end. */
GPU_indexbuf_init(
elb, GPU_PRIM_LINES, mr->edge_len + mr->edge_loose_len, mr->loop_len + mr->loop_loose_len);
- return elb;
-}
-
-static void *extract_lines_task_init(void *_userdata)
-{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
- GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
- MEM_mallocN(sizeof(*sub_builder), __func__));
- GPU_indexbuf_subbuilder_init(elb, sub_builder);
- return sub_builder;
}
static void extract_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@@ -109,7 +100,7 @@ static void extract_lines_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_lines_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *data)
{
@@ -147,12 +138,11 @@ static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr,
GPU_indexbuf_set_line_restart(elb, e_index);
}
-static void extract_lines_task_finish(void *_userdata, void *_task_userdata)
+static void extract_lines_task_reduce(void *_userdata_to, void *_userdata_from)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
- GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
- GPU_indexbuf_subbuilder_finish(elb, sub_builder);
- MEM_freeN(sub_builder);
+ GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
+ GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
+ GPU_indexbuf_join(elb_to, elb_from);
}
static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
@@ -163,21 +153,20 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
- MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_lines()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_lines_init;
- extractor.task_init = extract_lines_task_init;
extractor.iter_poly_bm = extract_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
- extractor.task_finish = extract_lines_task_finish;
+ extractor.task_reduce = extract_lines_task_reduce;
extractor.finish = extract_lines_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines);
return extractor;
@@ -209,21 +198,20 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
extract_lines_loose_subbuffer(mr, cache);
- MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_lines_with_lines_loose()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_lines_init;
- extractor.task_init = extract_lines_task_init;
extractor.iter_poly_bm = extract_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
- extractor.task_finish = extract_lines_task_finish;
+ extractor.task_reduce = extract_lines_task_reduce;
extractor.finish = extract_lines_with_lines_loose_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines);
return extractor;
@@ -235,21 +223,22 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose()
/** \name Extract Loose Edges Sub Buffer
* \{ */
-static void *extract_lines_loose_only_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf)
+static void extract_lines_loose_only_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
{
BLI_assert(buf == cache->final.ibo.lines_loose);
UNUSED_VARS_NDEBUG(buf);
extract_lines_loose_subbuffer(mr, cache);
- return NULL;
}
constexpr MeshExtract create_extractor_lines_loose_only()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_lines_loose_only_init;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_loose);
return extractor;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index 6140ae86c96..35b60002c1f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -41,26 +41,25 @@ struct MeshExtract_LineAdjacency_Data {
EdgeHash *eh;
bool is_manifold;
/* Array to convert vert index to any loop index of this vert. */
- uint vert_to_loop[0];
+ uint *vert_to_loop;
};
-static void *extract_lines_adjacency_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf))
+static void extract_lines_adjacency_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
{
/* Similar to poly_to_tri_count().
* There is always (loop + triangle - 1) edges inside a polygon.
* Accumulate for all polys and you get : */
uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
- size_t vert_to_loop_size = sizeof(uint) * mr->vert_len;
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data);
+ data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__));
- MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(
- MEM_callocN(sizeof(*data) + vert_to_loop_size, __func__));
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
data->is_manifold = true;
- return data;
}
BLI_INLINE void lines_adjacency_triangle(
@@ -169,7 +168,7 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
cache->is_manifold = data->is_manifold;
GPU_indexbuf_build_in_place(&data->elb, ibo);
- MEM_freeN(data);
+ MEM_freeN(data->vert_to_loop);
}
#undef NO_EDGE
@@ -178,12 +177,13 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
constexpr MeshExtract create_extractor_lines_adjacency()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_lines_adjacency_init;
extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh;
extractor.finish = extract_lines_adjacency_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_adjacency);
return extractor;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
index 6bbd0188f65..277f9d69c2f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
@@ -37,18 +37,17 @@ namespace blender::draw {
struct MeshExtract_LinePaintMask_Data {
GPUIndexBufBuilder elb;
/** One bit per edge set if face is selected. */
- BLI_bitmap select_map[0];
+ BLI_bitmap *select_map;
};
-static void *extract_lines_paint_mask_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_lines_paint_mask_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
- MeshExtract_LinePaintMask_Data *data = static_cast<MeshExtract_LinePaintMask_Data *>(
- MEM_callocN(sizeof(*data) + bitmap_size, __func__));
+ MeshExtract_LinePaintMask_Data *data = static_cast<MeshExtract_LinePaintMask_Data *>(tls_data);
+ data->select_map = BLI_BITMAP_NEW(mr->edge_len, __func__);
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->edge_len, mr->loop_len);
- return data;
}
static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
@@ -101,18 +100,19 @@ static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_LinePaintMask_Data *data = static_cast<MeshExtract_LinePaintMask_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
- MEM_freeN(data);
+ MEM_freeN(data->select_map);
}
/** \} */
constexpr MeshExtract create_extractor_lines_paint_mask()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_lines_paint_mask_init;
extractor.iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh;
extractor.finish = extract_lines_paint_mask_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(MeshExtract_LinePaintMask_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_paint_mask);
return extractor;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 9220198d799..cee0c224aab 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -32,25 +32,16 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Point Indices
* \{ */
-static void *extract_points_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf))
+static void extract_points_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->vert_len, mr->loop_len + mr->loop_loose_len);
- return elb;
}
-static void *extract_points_task_init(void *_userdata)
-{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
- GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
- MEM_mallocN(sizeof(*sub_builder), __func__));
- GPU_indexbuf_subbuilder_init(elb, sub_builder);
- return sub_builder;
-}
-
-BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index)
+BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, const BMVert *eve, int l_index)
{
const int v_index = BM_elem_index_get(eve);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
@@ -78,7 +69,7 @@ BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
}
static void extract_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
- BMFace *f,
+ const BMFace *f,
const int UNUSED(f_index),
void *_userdata)
{
@@ -107,7 +98,7 @@ static void extract_points_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_points_iter_ledge_bm(const MeshRenderData *mr,
- BMEdge *eed,
+ const BMEdge *eed,
const int ledge_index,
void *_userdata)
{
@@ -127,7 +118,7 @@ static void extract_points_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_points_iter_lvert_bm(const MeshRenderData *mr,
- BMVert *eve,
+ const BMVert *eve,
const int lvert_index,
void *_userdata)
{
@@ -146,12 +137,11 @@ static void extract_points_iter_lvert_mesh(const MeshRenderData *mr,
vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
}
-static void extract_points_task_finish(void *_userdata, void *_task_userdata)
+static void extract_points_task_reduce(void *_userdata_to, void *_userdata_from)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
- GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
- GPU_indexbuf_subbuilder_finish(elb, sub_builder);
- MEM_freeN(sub_builder);
+ GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
+ GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
+ GPU_indexbuf_join(elb_to, elb_from);
}
static void extract_points_finish(const MeshRenderData *UNUSED(mr),
@@ -162,24 +152,23 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
- MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_points()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_points_init;
- extractor.task_init = extract_points_task_init;
extractor.iter_poly_bm = extract_points_iter_poly_bm;
extractor.iter_poly_mesh = extract_points_iter_poly_mesh;
extractor.iter_ledge_bm = extract_points_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_points_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_points_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh;
- extractor.task_finish = extract_points_task_finish;
+ extractor.task_reduce = extract_points_task_reduce;
extractor.finish = extract_points_finish;
extractor.use_threading = true;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points);
return extractor;
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index acfffdacb88..93f71f920eb 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -33,57 +33,19 @@ namespace blender::draw {
struct MeshExtract_Tri_Data {
GPUIndexBufBuilder elb;
- int *tri_mat_start;
+ const int *tri_mat_start;
int *tri_mat_end;
};
-static void *extract_tris_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_tris_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(
- MEM_callocN(sizeof(*data), __func__));
-
- size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
- data->tri_mat_start = static_cast<int *>(MEM_callocN(mat_tri_idx_size, __func__));
- data->tri_mat_end = static_cast<int *>(MEM_callocN(mat_tri_idx_size, __func__));
-
- int *mat_tri_len = data->tri_mat_start;
- /* Count how many triangle for each material. */
- if (mr->extract_type == MR_EXTRACT_BMESH) {
- BMIter iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- int mat = min_ii(efa->mat_nr, mr->mat_len - 1);
- mat_tri_len[mat] += efa->len - 2;
- }
- }
- }
- else {
- const MPoly *mp = mr->mpoly;
- for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
- if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
- int mat = min_ii(mp->mat_nr, mr->mat_len - 1);
- mat_tri_len[mat] += mp->totloop - 2;
- }
- }
- }
- /* Accumulate triangle lengths per material to have correct offsets. */
- int ofs = mat_tri_len[0];
- mat_tri_len[0] = 0;
- for (int i = 1; i < mr->mat_len; i++) {
- int tmp = mat_tri_len[i];
- mat_tri_len[i] = ofs;
- ofs += tmp;
- }
-
- memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size);
-
- int visible_tri_tot = ofs;
- GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len);
-
- return data;
+ MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(tls_data);
+ data->tri_mat_start = mr->mat_offsets.tri;
+ data->tri_mat_end = static_cast<int *>(MEM_dupallocN(data->tri_mat_start));
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->mat_offsets.visible_tri_len, mr->loop_len);
}
static void extract_tris_iter_looptri_bm(const MeshRenderData *mr,
@@ -148,19 +110,18 @@ static void extract_tris_finish(const MeshRenderData *mr,
GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len);
}
}
- MEM_freeN(data->tri_mat_start);
MEM_freeN(data->tri_mat_end);
- MEM_freeN(data);
}
constexpr MeshExtract create_extractor_tris()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_tris_init;
extractor.iter_looptri_bm = extract_tris_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_iter_looptri_mesh;
extractor.finish = extract_tris_finish;
- extractor.data_type = MR_DATA_NONE;
+ extractor.data_type = MR_DATA_MAT_OFFSETS;
+ extractor.data_size = sizeof(MeshExtract_Tri_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris);
return extractor;
@@ -171,22 +132,13 @@ constexpr MeshExtract create_extractor_tris()
/** \name Extract Triangles Indices (single material)
* \{ */
-static void *extract_tris_single_mat_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(ibo))
+static void extract_tris_single_mat_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(ibo),
+ void *tls_data)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
- return elb;
-}
-
-static void *extract_tris_single_mat_task_init(void *_userdata)
-{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
- GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
- MEM_mallocN(sizeof(*sub_builder), __func__));
- GPU_indexbuf_subbuilder_init(elb, sub_builder);
- return sub_builder;
}
static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
@@ -222,12 +174,11 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr,
}
}
-static void extract_tris_single_mat_task_finish(void *_userdata, void *_task_userdata)
+static void extract_tris_single_mat_task_reduce(void *_userdata_to, void *_userdata_from)
{
- GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
- GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
- GPU_indexbuf_subbuilder_finish(elb, sub_builder);
- MEM_freeN(sub_builder);
+ GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
+ GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
+ GPU_indexbuf_join(elb_to, elb_from);
}
static void extract_tris_single_mat_finish(const MeshRenderData *mr,
@@ -246,7 +197,7 @@ static void extract_tris_single_mat_finish(const MeshRenderData *mr,
for (int i = 0; i < mr->mat_len; i++) {
/* These IBOs have not been queried yet but we create them just in case they are needed
* later since they are not tracked by mesh_buffer_cache_create_requested(). */
- if (mbc->tris_per_mat[i] == NULL) {
+ if (mbc->tris_per_mat[i] == nullptr) {
mbc->tris_per_mat[i] = GPU_indexbuf_calloc();
}
/* Multiply by 3 because these are triangle indices. */
@@ -254,19 +205,18 @@ static void extract_tris_single_mat_finish(const MeshRenderData *mr,
GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, 0, len);
}
}
- MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_tris_single_mat()
{
- MeshExtract extractor = {0};
+ MeshExtract extractor = {nullptr};
extractor.init = extract_tris_single_mat_init;
- extractor.task_init = extract_tris_single_mat_task_init;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
- extractor.task_finish = extract_tris_single_mat_task_finish;
+ extractor.task_reduce = extract_tris_single_mat_task_reduce;
extractor.finish = extract_tris_single_mat_finish;
extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris);
return extractor;
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index c96f22859ca..cce69714f5e 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -3,17 +3,22 @@
#include "testing/testing.h"
#include "draw_testing.hh"
-#include "intern/draw_manager_testing.h"
#include "GPU_context.h"
+#include "GPU_index_buffer.h"
#include "GPU_init_exit.h"
#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_vertex_buffer.h"
+
+#include "intern/draw_manager_testing.h"
#include "engines/eevee/eevee_private.h"
#include "engines/gpencil/gpencil_engine.h"
#include "engines/image/image_private.h"
#include "engines/overlay/overlay_private.h"
#include "engines/workbench/workbench_private.h"
+#include "intern/draw_shader.h"
namespace blender::draw {
@@ -366,4 +371,20 @@ TEST_F(DrawTest, eevee_glsl_shaders_static)
EEVEE_shaders_free();
}
+static void test_draw_shaders(eParticleRefineShaderType sh_type)
+{
+ DRW_shaders_free();
+ EXPECT_NE(DRW_shader_hair_refine_get(PART_REFINE_CATMULL_ROM, sh_type), nullptr);
+ DRW_shaders_free();
+}
+
+TEST_F(DrawTest, draw_glsl_shaders)
+{
+#ifndef __APPLE__
+ test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK);
+ test_draw_shaders(PART_REFINE_SHADER_COMPUTE);
+#endif
+ test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND);
+}
+
} // namespace blender::draw
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 64082b08da9..061fe0b07c5 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1349,10 +1349,12 @@ static void join_groups_action_temp(bAction *act)
/* BLI_movelisttolist() doesn't touch first->prev and last->next pointers in its "dst" list.
* Ensure that after the reshuffling the list is properly terminated. */
- FCurve *act_fcurves_first = act->curves.first;
- act_fcurves_first->prev = NULL;
- FCurve *act_fcurves_last = act->curves.last;
- act_fcurves_last->next = NULL;
+ if (!BLI_listbase_is_empty(&act->curves)) {
+ FCurve *act_fcurves_first = act->curves.first;
+ act_fcurves_first->prev = NULL;
+ FCurve *act_fcurves_last = act->curves.last;
+ act_fcurves_last->next = NULL;
+ }
}
/* Change the order of anim-channels within action
@@ -3441,12 +3443,14 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- /* NOTE: don't save settings, otherwise, can end up with some weird behavior (sticky extend) */
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); /* SHIFTKEY */
+ /* NOTE: don't save settings, otherwise, can end up with some weird behavior (sticky extend)
+ *
+ * Key-map: Enable with `Shift`. */
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(
- ot->srna, "children_only", false, "Select Children Only", ""); /* CTRLKEY|SHIFTKEY */
+ /* Key-map: Enable with `Ctrl-Shift`. */
+ prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 17251587d3b..31284e41b18 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -109,8 +109,8 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
/* in other case we do standard depsgraph update, ideally
* we'd be calling property update functions here too ... */
DEG_id_tag_update(id,
- ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY |
- ID_RECALC_ANIMATION); /* XXX or do we want something more restrictive? */
+ /* XXX: or do we want something more restrictive? */
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
}
}
@@ -119,11 +119,10 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
void ANIM_id_update(Main *bmain, ID *id)
{
if (id) {
- DEG_id_tag_update_ex(
- bmain,
- id,
- ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY |
- ID_RECALC_ANIMATION); /* XXX or do we want something more restrictive? */
+ DEG_id_tag_update_ex(bmain,
+ id,
+ /* XXX: or do we want something more restrictive? */
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
}
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 87291974e08..b2d74376102 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -913,7 +913,7 @@ static tAnimCopybufItem *pastebuf_match_path_property(Main *bmain,
if (aci->rna_path && fcu->rna_path) {
/* find the property of the fcurve and compare against the end of the tAnimCopybufItem
* more involved since it needs to do path lookups.
- * This is not 100% reliable since the user could be editing the curves on a path that wont
+ * This is not 100% reliable since the user could be editing the curves on a path that won't
* resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
* this should work out ok.
*/
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 3902f6613a1..1d4936bdf5e 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -89,15 +89,14 @@ EditBone *ED_armature_ebone_add(bArmature *arm, const char *name)
bone->roll1 = 0.0f;
bone->roll2 = 0.0f;
bone->curve_in_x = 0.0f;
- bone->curve_in_y = 0.0f;
+ bone->curve_in_z = 0.0f;
bone->curve_out_x = 0.0f;
- bone->curve_out_y = 0.0f;
+ bone->curve_out_z = 0.0f;
bone->ease1 = 1.0f;
bone->ease2 = 1.0f;
- bone->scale_in_x = 1.0f;
- bone->scale_in_y = 1.0f;
- bone->scale_out_x = 1.0f;
- bone->scale_out_y = 1.0f;
+
+ copy_v3_fl(bone->scale_in, 1.0f);
+ copy_v3_fl(bone->scale_out, 1.0f);
return bone;
}
@@ -1265,6 +1264,10 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
ebone->bbone_prev_type = ebone_iter->bbone_prev_type;
ebone->bbone_next_type = ebone_iter->bbone_next_type;
+ ebone->bbone_flag = ebone_iter->bbone_flag;
+ ebone->bbone_prev_flag = ebone_iter->bbone_prev_flag;
+ ebone->bbone_next_flag = ebone_iter->bbone_next_flag;
+
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
@@ -1464,15 +1467,14 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
newbone->roll1 = ebone->roll1;
newbone->roll2 = ebone->roll2;
newbone->curve_in_x = ebone->curve_in_x;
- newbone->curve_in_y = ebone->curve_in_y;
+ newbone->curve_in_z = ebone->curve_in_z;
newbone->curve_out_x = ebone->curve_out_x;
- newbone->curve_out_y = ebone->curve_out_y;
+ newbone->curve_out_z = ebone->curve_out_z;
newbone->ease1 = ebone->ease1;
newbone->ease2 = ebone->ease2;
- newbone->scale_in_x = ebone->scale_in_x;
- newbone->scale_in_y = ebone->scale_in_y;
- newbone->scale_out_x = ebone->scale_out_x;
- newbone->scale_out_y = ebone->scale_out_y;
+
+ copy_v3_v3(newbone->scale_in, ebone->scale_in);
+ copy_v3_v3(newbone->scale_out, ebone->scale_out);
BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 4fff2ae03b0..d429e51061b 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -161,11 +161,11 @@ typedef struct tPChanFCurveLink {
/** old bbone values (to be restored along with the transform properties) */
float roll1, roll2;
/** (NOTE: we haven't renamed these this time, as their names are already long enough) */
- float curve_in_x, curve_in_y;
- float curve_out_x, curve_out_y;
+ float curve_in_x, curve_in_z;
+ float curve_out_x, curve_out_z;
float ease1, ease2;
- float scale_in_x, scale_in_y;
- float scale_out_x, scale_out_y;
+ float scale_in[3];
+ float scale_out[3];
/** copy of custom properties at start of operator (to be restored before each modal step) */
struct IDProperty *oldprops;
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index f86ec545712..fc9191967f8 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -486,8 +486,8 @@ void ED_object_vgroup_calc_from_armature(ReportList *reports,
defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
if (defbase_add) {
- /* its possible there are DWeight's outside the range of the current
- * objects deform groups, in this case the new groups wont be empty T33889. */
+ /* It's possible there are DWeights outside the range of the current
+ * object's deform groups. In this case the new groups won't be empty T33889. */
ED_vgroup_data_clamp_range(ob->data, defbase_tot);
}
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 3d1d8d0d1f1..ffcdb99c5a3 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -414,9 +414,8 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
eboflip->tail[2] = ebo->tail[2];
eboflip->rad_tail = ebo->rad_tail;
eboflip->curve_out_x = -ebo->curve_out_x;
- eboflip->curve_out_y = ebo->curve_out_y;
- eboflip->scale_out_x = ebo->scale_out_x;
- eboflip->scale_out_y = ebo->scale_out_y;
+ eboflip->curve_out_z = ebo->curve_out_z;
+ copy_v3_v3(eboflip->scale_out, ebo->scale_out);
eboflip->ease2 = ebo->ease2;
eboflip->roll2 = -ebo->roll2;
@@ -438,9 +437,8 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
eboflip->rad_head = ebo->rad_head;
eboflip->curve_in_x = -ebo->curve_in_x;
- eboflip->curve_in_y = ebo->curve_in_y;
- eboflip->scale_in_x = ebo->scale_in_x;
- eboflip->scale_in_y = ebo->scale_in_y;
+ eboflip->curve_in_z = ebo->curve_in_z;
+ copy_v3_v3(eboflip->scale_in, ebo->scale_in);
eboflip->ease1 = ebo->ease1;
eboflip->roll1 = -ebo->roll1;
@@ -542,19 +540,22 @@ static EditBone *make_boneList_recursive(ListBase *edbo,
eBone->roll1 = curBone->roll1;
eBone->roll2 = curBone->roll2;
eBone->curve_in_x = curBone->curve_in_x;
- eBone->curve_in_y = curBone->curve_in_y;
+ eBone->curve_in_z = curBone->curve_in_z;
eBone->curve_out_x = curBone->curve_out_x;
- eBone->curve_out_y = curBone->curve_out_y;
+ eBone->curve_out_z = curBone->curve_out_z;
eBone->ease1 = curBone->ease1;
eBone->ease2 = curBone->ease2;
- eBone->scale_in_x = curBone->scale_in_x;
- eBone->scale_in_y = curBone->scale_in_y;
- eBone->scale_out_x = curBone->scale_out_x;
- eBone->scale_out_y = curBone->scale_out_y;
+
+ copy_v3_v3(eBone->scale_in, curBone->scale_in);
+ copy_v3_v3(eBone->scale_out, curBone->scale_out);
eBone->bbone_prev_type = curBone->bbone_prev_type;
eBone->bbone_next_type = curBone->bbone_next_type;
+ eBone->bbone_flag = curBone->bbone_flag;
+ eBone->bbone_prev_flag = curBone->bbone_prev_flag;
+ eBone->bbone_next_flag = curBone->bbone_next_flag;
+
if (curBone->prop) {
eBone->prop = IDP_CopyProperty(curBone->prop);
}
@@ -757,19 +758,21 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
newBone->roll1 = eBone->roll1;
newBone->roll2 = eBone->roll2;
newBone->curve_in_x = eBone->curve_in_x;
- newBone->curve_in_y = eBone->curve_in_y;
+ newBone->curve_in_z = eBone->curve_in_z;
newBone->curve_out_x = eBone->curve_out_x;
- newBone->curve_out_y = eBone->curve_out_y;
+ newBone->curve_out_z = eBone->curve_out_z;
newBone->ease1 = eBone->ease1;
newBone->ease2 = eBone->ease2;
- newBone->scale_in_x = eBone->scale_in_x;
- newBone->scale_in_y = eBone->scale_in_y;
- newBone->scale_out_x = eBone->scale_out_x;
- newBone->scale_out_y = eBone->scale_out_y;
+ copy_v3_v3(newBone->scale_in, eBone->scale_in);
+ copy_v3_v3(newBone->scale_out, eBone->scale_out);
newBone->bbone_prev_type = eBone->bbone_prev_type;
newBone->bbone_next_type = eBone->bbone_next_type;
+ newBone->bbone_flag = eBone->bbone_flag;
+ newBone->bbone_prev_flag = eBone->bbone_prev_flag;
+ newBone->bbone_next_flag = eBone->bbone_next_flag;
+
if (eBone->prop) {
newBone->prop = IDP_CopyProperty(eBone->prop);
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 9300fcf193d..d32faf9a9ea 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -19,6 +19,28 @@
/** \file
* \ingroup edarmature
+ *
+ * Pose 'Sliding' Tools
+ * ====================
+ *
+ * - Push & Relax, Breakdowner
+
+ * These tools provide the animator with various capabilities
+ * for interactively controlling the spacing of poses, but also
+ * for 'pushing' and/or 'relaxing' extremes as they see fit.
+ *
+ * - Propagate
+
+ * This tool copies elements of the selected pose to successive
+ * keyframes, allowing the animator to go back and modify the poses
+ * for some "static" pose controls, without having to repeatedly
+ * doing a "next paste" dance.
+ *
+ * - Pose Sculpting (TODO)
+
+ * This is yet to be implemented, but the idea here is to use
+ * sculpting techniques to make it easier to pose rigs by allowing
+ * rigs to be manipulated using a familiar paint-based interface.
*/
#include "MEM_guardedalloc.h"
@@ -75,35 +97,48 @@
#define OVERSHOOT_RANGE_DELTA 0.2f
/* **************************************************** */
-/* == POSE 'SLIDING' TOOLS ==
- *
- * A) Push & Relax, Breakdowner
- * These tools provide the animator with various capabilities
- * for interactively controlling the spacing of poses, but also
- * for 'pushing' and/or 'relaxing' extremes as they see fit.
- *
- * B) Propagate
- * This tool copies elements of the selected pose to successive
- * keyframes, allowing the animator to go back and modify the poses
- * for some "static" pose controls, without having to repeatedly
- * doing a "next paste" dance.
- *
- * C) Pose Sculpting
- * This is yet to be implemented, but the idea here is to use
- * sculpting techniques to make it easier to pose rigs by allowing
- * rigs to be manipulated using a familiar paint-based interface.
- */
-/* **************************************************** */
/* A) Push & Relax, Breakdowner */
-/* Temporary data shared between these operators */
+/** Axis Locks. */
+typedef enum ePoseSlide_AxisLock {
+ PS_LOCK_X = (1 << 0),
+ PS_LOCK_Y = (1 << 1),
+ PS_LOCK_Z = (1 << 2),
+} ePoseSlide_AxisLock;
+
+/** Pose Sliding Modes. */
+typedef enum ePoseSlide_Modes {
+ /** Exaggerate the pose. */
+ POSESLIDE_PUSH = 0,
+ /** soften the pose. */
+ POSESLIDE_RELAX,
+ /** Slide between the endpoint poses, finding a 'soft' spot. */
+ POSESLIDE_BREAKDOWN,
+ POSESLIDE_PUSH_REST,
+ POSESLIDE_RELAX_REST,
+} ePoseSlide_Modes;
+
+/** Transforms/Channels to Affect. */
+typedef enum ePoseSlide_Channels {
+ PS_TFM_ALL = 0, /* All transforms and properties */
+
+ PS_TFM_LOC, /* Loc/Rot/Scale */
+ PS_TFM_ROT,
+ PS_TFM_SIZE,
+
+ PS_TFM_BBONE_SHAPE, /* Bendy Bones */
+
+ PS_TFM_PROPS, /* Custom Properties */
+} ePoseSlide_Channels;
+
+/** Temporary data shared between these operators. */
typedef struct tPoseSlideOp {
/** current scene */
Scene *scene;
/** area that we're operating in (needed for modal()) */
ScrArea *area;
- /** region that we're operating in (needed for modal()) */
- ARegion *region;
+ /** Header of the region used for drawing the slider. */
+ ARegion *region_header;
/** len of the PoseSlideObject array. */
uint objects_len;
@@ -120,76 +155,57 @@ typedef struct tPoseSlideOp {
/** frame after current frame (blend-to) - global time */
int nextFrame;
- /** sliding mode (ePoseSlide_Modes) */
- short mode;
+ /** Sliding Mode. */
+ ePoseSlide_Modes mode;
/** unused for now, but can later get used for storing runtime settings.... */
short flag;
/* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */
int overlay_flag;
- /** which transforms/channels are affected (ePoseSlide_Channels) */
- short channels;
- /** axis-limits for transforms (ePoseSlide_AxisLock) */
- short axislock;
+ /** Which transforms/channels are affected. */
+ ePoseSlide_Channels channels;
+ /** Axis-limits for transforms. */
+ ePoseSlide_AxisLock axislock;
- /* Allow overshoot or clamp between 0% and 100%. */
+ /** Allow overshoot or clamp between 0% and 100%. */
bool overshoot;
- /* Reduces percentage delta from mouse movement. */
+ /** Reduces factor delta from mouse movement. */
bool precision;
- /* Move percentage in 10% steps. */
+ /** Move factor in 10% steps. */
bool increments;
- /* Draw callback handler. */
+ /** Draw callback handler. */
void *draw_handle;
- /* Accumulative, unclamped and unrounded percentage. */
- float raw_percentage;
+ /** Accumulative, unclamped and unrounded factor. */
+ float raw_factor;
- /* 0-1 value for determining the influence of whatever is relevant. */
- float percentage;
+ /** 0-1 value for determining the influence of whatever is relevant. */
+ float factor;
- /* Last cursor position in screen space used for mouse movement delta calculation. */
+ /** Last cursor position in screen space used for mouse movement delta calculation. */
int last_cursor_x;
- /* Numeric input. */
+ /** Numeric input. */
NumInput num;
struct tPoseSlideObject *ob_data_array;
} tPoseSlideOp;
typedef struct tPoseSlideObject {
- Object *ob; /* active object that Pose Info comes from */
- float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
- float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
+ /** Active object that Pose Info comes from. */
+ Object *ob;
+ /** `prevFrame`, but in local action time (for F-Curve look-ups to work). */
+ float prevFrameF;
+ /** `nextFrame`, but in local action time (for F-Curve look-ups to work). */
+ float nextFrameF;
bool valid;
} tPoseSlideObject;
-/* Pose Sliding Modes */
-typedef enum ePoseSlide_Modes {
- POSESLIDE_PUSH = 0, /* exaggerate the pose... */
- POSESLIDE_RELAX, /* soften the pose... */
- POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
- POSESLIDE_PUSH_REST,
- POSESLIDE_RELAX_REST,
-} ePoseSlide_Modes;
-
-/* Transforms/Channels to Affect */
-typedef enum ePoseSlide_Channels {
- PS_TFM_ALL = 0, /* All transforms and properties */
-
- PS_TFM_LOC, /* Loc/Rot/Scale */
- PS_TFM_ROT,
- PS_TFM_SIZE,
-
- PS_TFM_BBONE_SHAPE, /* Bendy Bones */
-
- PS_TFM_PROPS, /* Custom Properties */
-} ePoseSlide_Channels;
-
-/* Property enum for ePoseSlide_Channels */
+/** Property enum for #ePoseSlide_Channels. */
static const EnumPropertyItem prop_channels_types[] = {
{PS_TFM_ALL,
"ALL",
@@ -204,13 +220,6 @@ static const EnumPropertyItem prop_channels_types[] = {
{0, NULL, 0, NULL, NULL},
};
-/* Axis Locks */
-typedef enum ePoseSlide_AxisLock {
- PS_LOCK_X = (1 << 0),
- PS_LOCK_Y = (1 << 1),
- PS_LOCK_Z = (1 << 2),
-} ePoseSlide_AxisLock;
-
/* Property enum for ePoseSlide_AxisLock */
static const EnumPropertyItem prop_axis_lock_types[] = {
{0, "FREE", 0, "Free", "All axes are affected"},
@@ -248,22 +257,22 @@ static void draw_overshoot_triangle(const uint8_t color[4],
immUnbindProgram();
}
-static void draw_ticks(const float start_percentage,
- const float end_percentage,
- const struct vec2f line_start,
+static void draw_ticks(const float start_factor,
+ const float end_factor,
+ const float line_start[2],
const float base_tick_height,
const float line_width,
const uint8_t color_overshoot[4],
const uint8_t color_line[4])
{
- /* Use percentage represented as 0-100 int to avoid floating point precision problems. */
+ /* Use factor represented as 0-100 int to avoid floating point precision problems. */
const int tick_increment = 10;
- /* Round initial_tick_percentage up to the next tick_increment. */
- int tick_percentage = ceil((start_percentage * 100) / tick_increment) * tick_increment;
- float tick_height = base_tick_height;
+ /* Round initial_tick_factor up to the next tick_increment. */
+ int tick_percentage = ceil((start_factor * 100) / tick_increment) * tick_increment;
- while (tick_percentage <= (int)(end_percentage * 100)) {
+ while (tick_percentage <= (int)(end_factor * 100)) {
+ float tick_height;
/* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit
* smaller and the rest is the minimum size. */
if (tick_percentage % 100 == 0) {
@@ -276,12 +285,14 @@ static void draw_ticks(const float start_percentage,
tick_height = base_tick_height * 0.5;
}
- const float x = line_start.x +
- (((float)tick_percentage / 100) - start_percentage) * SLIDE_PIXEL_DISTANCE;
- const struct rctf tick_rect = {.xmin = x - (line_width / 2),
- .xmax = x + (line_width / 2),
- .ymin = line_start.y - (tick_height / 2),
- .ymax = line_start.y + (tick_height / 2)};
+ const float x = line_start[0] +
+ (((float)tick_percentage / 100) - start_factor) * SLIDE_PIXEL_DISTANCE;
+ const rctf tick_rect = {
+ .xmin = x - (line_width / 2),
+ .xmax = x + (line_width / 2),
+ .ymin = line_start[1] - (tick_height / 2),
+ .ymax = line_start[1] + (tick_height / 2),
+ };
if (tick_percentage < 0 || tick_percentage > 100) {
UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255);
@@ -293,73 +304,83 @@ static void draw_ticks(const float start_percentage,
}
}
-static void draw_main_line(const struct rctf main_line_rect,
- const float percentage,
+static void draw_main_line(const rctf *main_line_rect,
+ const float factor,
const bool overshoot,
const uint8_t color_overshoot[4],
const uint8_t color_line[4])
{
if (overshoot) {
/* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */
- const float line_zero_percent = main_line_rect.xmin -
- ((percentage - 0.5f - OVERSHOOT_RANGE_DELTA) *
+ const float line_zero_percent = main_line_rect->xmin -
+ ((factor - 0.5f - OVERSHOOT_RANGE_DELTA) *
SLIDE_PIXEL_DISTANCE);
const float clamped_line_zero_percent = clamp_f(
- line_zero_percent, main_line_rect.xmin, main_line_rect.xmax);
+ line_zero_percent, main_line_rect->xmin, main_line_rect->xmax);
const float clamped_line_hundred_percent = clamp_f(
- line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect.xmin, main_line_rect.xmax);
-
- const struct rctf left_overshoot_line_rect = {.xmin = main_line_rect.xmin,
- .xmax = clamped_line_zero_percent,
- .ymin = main_line_rect.ymin,
- .ymax = main_line_rect.ymax};
- const struct rctf right_overshoot_line_rect = {.xmin = clamped_line_hundred_percent,
- .xmax = main_line_rect.xmax,
- .ymin = main_line_rect.ymin,
- .ymax = main_line_rect.ymax};
+ line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect->xmin, main_line_rect->xmax);
+
+ const rctf left_overshoot_line_rect = {
+ .xmin = main_line_rect->xmin,
+ .xmax = clamped_line_zero_percent,
+ .ymin = main_line_rect->ymin,
+ .ymax = main_line_rect->ymax,
+ };
+ const rctf right_overshoot_line_rect = {
+ .xmin = clamped_line_hundred_percent,
+ .xmax = main_line_rect->xmax,
+ .ymin = main_line_rect->ymin,
+ .ymax = main_line_rect->ymax,
+ };
UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255);
UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255);
- const struct rctf non_overshoot_line_rect = {.xmin = clamped_line_zero_percent,
- .xmax = clamped_line_hundred_percent,
- .ymin = main_line_rect.ymin,
- .ymax = main_line_rect.ymax};
+ const rctf non_overshoot_line_rect = {
+ .xmin = clamped_line_zero_percent,
+ .xmax = clamped_line_hundred_percent,
+ .ymin = main_line_rect->ymin,
+ .ymax = main_line_rect->ymax,
+ };
UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255);
}
else {
- UI_draw_roundbox_3ub_alpha(&main_line_rect, true, 0, color_line, 255);
+ UI_draw_roundbox_3ub_alpha(main_line_rect, true, 0, color_line, 255);
}
}
static void draw_backdrop(const int fontid,
- const struct rctf main_line_rect,
+ const rctf *main_line_rect,
const float color_bg[4],
const short region_y_size,
const float base_tick_height)
{
float string_pixel_size[2];
- const char *percentage_placeholder = "000%%";
+ const char *percentage_string_placeholder = "000%%";
BLF_width_and_height(fontid,
- percentage_placeholder,
- sizeof(percentage_placeholder),
+ percentage_string_placeholder,
+ sizeof(percentage_string_placeholder),
&string_pixel_size[0],
&string_pixel_size[1]);
- const struct vec2f pad = {.x = (region_y_size - base_tick_height) / 2, .y = 2.0f * U.pixelsize};
- const struct rctf backdrop_rect = {.xmin = main_line_rect.xmin - string_pixel_size[0] - pad.x,
- .xmax = main_line_rect.xmax + pad.x,
- .ymin = pad.y,
- .ymax = region_y_size - pad.y};
+ const float pad[2] = {(region_y_size - base_tick_height) / 2, 2.0f * U.pixelsize};
+ const rctf backdrop_rect = {
+ .xmin = main_line_rect->xmin - string_pixel_size[0] - pad[0],
+ .xmax = main_line_rect->xmax + pad[0],
+ .ymin = pad[1],
+ .ymax = region_y_size - pad[1],
+ };
UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg);
}
-/* Draw an on screen Slider for a Pose Slide Operator. */
+/**
+ * Draw an on screen Slider for a Pose Slide Operator.
+ */
static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg)
{
tPoseSlideOp *pso = arg;
/* Only draw in region from which the Operator was started. */
- if (region != pso->region) {
+ if (region != pso->region_header) {
return;
}
@@ -392,28 +413,30 @@ static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion
const float base_tick_height = 12.0 * U.pixelsize;
const float line_y = region->winy / 2;
- struct rctf main_line_rect = {.xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2),
- .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2),
- .ymin = line_y - line_width / 2,
- .ymax = line_y + line_width / 2};
- float line_start_percentage = 0;
- int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->percentage;
+ rctf main_line_rect = {
+ .xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2),
+ .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2),
+ .ymin = line_y - line_width / 2,
+ .ymax = line_y + line_width / 2,
+ };
+ float line_start_factor = 0;
+ int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->factor;
if (pso->overshoot) {
main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA;
- line_start_percentage = pso->percentage - 0.5f - OVERSHOOT_RANGE_DELTA;
+ line_start_factor = pso->factor - 0.5f - OVERSHOOT_RANGE_DELTA;
handle_pos_x = region->winx / 2;
}
- draw_backdrop(fontid, main_line_rect, color_bg, pso->region->winy, base_tick_height);
+ draw_backdrop(fontid, &main_line_rect, color_bg, pso->region_header->winy, base_tick_height);
- draw_main_line(main_line_rect, pso->percentage, pso->overshoot, color_overshoot, color_line);
+ draw_main_line(&main_line_rect, pso->factor, pso->overshoot, color_overshoot, color_line);
- const float percentage_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1;
- const struct vec2f line_start_position = {.x = main_line_rect.xmin, .y = line_y};
- draw_ticks(line_start_percentage,
- line_start_percentage + percentage_range,
+ const float factor_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1;
+ const float line_start_position[2] = {main_line_rect.xmin, line_y};
+ draw_ticks(line_start_factor,
+ line_start_factor + factor_range,
line_start_position,
base_tick_height,
line_width,
@@ -423,68 +446,70 @@ static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion
/* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100%
* range.*/
if (pso->overshoot) {
- if (pso->percentage > 1 + OVERSHOOT_RANGE_DELTA + 0.5) {
+ if (pso->factor > 1 + OVERSHOOT_RANGE_DELTA + 0.5) {
draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y);
}
- if (pso->percentage < 0 - OVERSHOOT_RANGE_DELTA - 0.5) {
+ if (pso->factor < 0 - OVERSHOOT_RANGE_DELTA - 0.5) {
draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y);
}
}
char percentage_string[256];
- /* Draw handle indicating current percentage. */
- const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width),
- .xmax = handle_pos_x + (line_width),
- .ymin = line_y - (base_tick_height / 2),
- .ymax = line_y + (base_tick_height / 2)};
+ /* Draw handle indicating current factor. */
+ const rctf handle_rect = {
+ .xmin = handle_pos_x - (line_width),
+ .xmax = handle_pos_x + (line_width),
+ .ymin = line_y - (base_tick_height / 2),
+ .ymax = line_y + (base_tick_height / 2),
+ };
UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255);
- BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100);
+ BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->factor * 100);
/* Draw percentage string. */
- float percentage_pixel_size[2];
+ float percentage_string_pixel_size[2];
BLF_width_and_height(fontid,
percentage_string,
sizeof(percentage_string),
- &percentage_pixel_size[0],
- &percentage_pixel_size[1]);
+ &percentage_string_pixel_size[0],
+ &percentage_string_pixel_size[1]);
BLF_position(fontid,
- main_line_rect.xmin - 24.0 * U.pixelsize - percentage_pixel_size[0] / 2,
- (region->winy / 2) - percentage_pixel_size[1] / 2,
+ main_line_rect.xmin - 24.0 * U.pixelsize - percentage_string_pixel_size[0] / 2,
+ (region->winy / 2) - percentage_string_pixel_size[1] / 2,
0.0f);
BLF_draw(fontid, percentage_string, sizeof(percentage_string));
}
-/* operator init */
+/** Operator custom-data initialization. */
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
tPoseSlideOp *pso;
- /* init slide-op data */
+ /* Init slide-op data. */
pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
- /* get info from context */
+ /* Get info from context. */
pso->scene = CTX_data_scene(C);
- pso->area = CTX_wm_area(C); /* only really needed when doing modal() */
- pso->region = CTX_wm_region(C); /* only really needed when doing modal() */
+ pso->area = CTX_wm_area(C); /* Only really needed when doing modal(). */
+ pso->region_header = CTX_wm_region(C); /* Only really needed when doing modal(). */
pso->cframe = pso->scene->r.cfra;
pso->mode = mode;
- /* set range info from property values - these may get overridden for the invoke() */
- pso->percentage = RNA_float_get(op->ptr, "percentage");
- pso->raw_percentage = pso->percentage;
+ /* Set range info from property values - these may get overridden for the invoke(). */
+ pso->factor = RNA_float_get(op->ptr, "factor");
+ pso->raw_factor = pso->factor;
pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
- /* get the set of properties/axes that can be operated on */
+ /* Get the set of properties/axes that can be operated on. */
pso->channels = RNA_enum_get(op->ptr, "channels");
pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
- /* for each Pose-Channel which gets affected, get the F-Curves for that channel
- * and set the relevant transform flags... */
+ /* For each Pose-Channel which gets affected, get the F-Curves for that channel
+ * and set the relevant transform flags. */
poseAnim_mapping_get(C, &pso->pfLinks);
Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
@@ -504,43 +529,44 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
ob_data->ob = ob_iter;
ob_data->valid = true;
- /* apply NLA mapping corrections so the frame lookups work */
+ /* Apply NLA mapping corrections so the frame look-ups work. */
ob_data->prevFrameF = BKE_nla_tweakedit_remap(
ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
ob_data->nextFrameF = BKE_nla_tweakedit_remap(
ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
- /* set depsgraph flags */
- /* make sure the lock is set OK, unlock can be accidentally saved? */
+ /* Set depsgraph flags. */
+ /* Make sure the lock is set OK, unlock can be accidentally saved? */
ob_data->ob->pose->flag |= POSE_LOCKED;
ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
}
MEM_freeN(objects);
- /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
- * to the caller of this (usually only invoke() will do it, to make things more efficient).
- */
+ /* Do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
+ * to the caller of this (usually only invoke() will do it, to make things more efficient). */
BLI_dlrbTree_init(&pso->keys);
/* Initialize numeric input. */
initNumInput(&pso->num);
- pso->num.idx_max = 0; /* one axis */
+ pso->num.idx_max = 0; /* One axis. */
pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
- pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
+ pso->num.unit_type[0] = B_UNIT_NONE; /* Percentages don't have any units. */
/* Register UI drawing callback. */
ARegion *region_header = BKE_area_find_region_type(pso->area, RGN_TYPE_HEADER);
if (region_header != NULL) {
- pso->region = region_header;
+ pso->region_header = region_header;
pso->draw_handle = ED_region_draw_cb_activate(
region_header->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL);
}
- /* return status is whether we've got all the data we were requested to get */
+ /* Return status is whether we've got all the data we were requested to get. */
return 1;
}
-/* exiting the operator - free data */
+/**
+ * Exiting the operator (free data).
+ */
static void pose_slide_exit(wmOperator *op)
{
tPoseSlideOp *pso = op->customdata;
@@ -550,34 +576,33 @@ static void pose_slide_exit(wmOperator *op)
v3d->overlay.flag = pso->overlay_flag;
/* Remove UI drawing callback. */
- ED_region_draw_cb_exit(pso->region->type, pso->draw_handle);
+ ED_region_draw_cb_exit(pso->region_header->type, pso->draw_handle);
- /* if data exists, clear its data and exit */
- if (pso) {
- /* free the temp pchan links and their data */
- poseAnim_mapping_free(&pso->pfLinks);
+ /* Free the temp pchan links and their data. */
+ poseAnim_mapping_free(&pso->pfLinks);
- /* free RB-BST for keyframes (if it contained data) */
- BLI_dlrbTree_free(&pso->keys);
+ /* Free RB-BST for keyframes (if it contained data). */
+ BLI_dlrbTree_free(&pso->keys);
- if (pso->ob_data_array != NULL) {
- MEM_freeN(pso->ob_data_array);
- }
-
- /* free data itself */
- MEM_freeN(pso);
+ if (pso->ob_data_array != NULL) {
+ MEM_freeN(pso->ob_data_array);
}
- /* cleanup */
+ /* Free data itself. */
+ MEM_freeN(pso);
+
+ /* Cleanup. */
op->customdata = NULL;
}
/* ------------------------------------ */
-/* helper for apply() / reset() - refresh the data */
+/**
+ * Helper for apply() / reset() - refresh the data.
+ */
static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
{
- /* wrapper around the generic version, allowing us to add some custom stuff later still */
+ /* Wrapper around the generic version, allowing us to add some custom stuff later still. */
for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
if (ob_data->valid) {
@@ -609,7 +634,9 @@ static bool pose_frame_range_from_object_get(tPoseSlideOp *pso,
return false;
}
-/* helper for apply() - perform sliding for some value */
+/**
+ * Helper for apply() - perform sliding for some value.
+ */
static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, float *val)
{
float prevFrameF, nextFrameF;
@@ -619,17 +646,17 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo
pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
- /* get keyframe values for endpoint poses to blend with */
- /* previous/start */
+ /* Get keyframe values for endpoint poses to blend with. */
+ /* Previous/start. */
sVal = evaluate_fcurve(fcu, prevFrameF);
- /* next/end */
+ /* Next/end. */
eVal = evaluate_fcurve(fcu, nextFrameF);
- /* calculate the relative weights of the endpoints */
+ /* Calculate the relative weights of the endpoints. */
if (pso->mode == POSESLIDE_BREAKDOWN) {
- /* get weights from the percentage control */
- w1 = pso->percentage; /* this must come second */
- w2 = 1.0f - w1; /* this must come first */
+ /* Get weights from the factor control. */
+ w1 = pso->factor; /* This must come second. */
+ w2 = 1.0f - w1; /* This must come first. */
}
else {
/* - these weights are derived from the relative distance of these
@@ -652,30 +679,37 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo
* the value the current frame is closer to.
*/
switch (pso->mode) {
- case POSESLIDE_PUSH: /* make the current pose more pronounced */
+ case POSESLIDE_PUSH: /* Make the current pose more pronounced. */
{
/* Slide the pose away from the breakdown pose in the timeline */
- (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage;
+ (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor;
break;
}
- case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
+ case POSESLIDE_RELAX: /* Make the current pose more like its surrounding ones. */
{
/* Slide the pose towards the breakdown pose in the timeline */
- (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage;
+ (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor;
break;
}
- case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
+ case POSESLIDE_BREAKDOWN: /* Make the current pose slide around between the endpoints. */
{
/* Perform simple linear interpolation -
- * coefficient for start must come from pso->percentage. */
+ * coefficient for start must come from pso->factor. */
/* TODO: make this use some kind of spline interpolation instead? */
(*val) = ((sVal * w2) + (eVal * w1));
break;
}
+ /* Those are handled in pose_slide_rest_pose_apply. */
+ case POSESLIDE_PUSH_REST:
+ case POSESLIDE_RELAX_REST: {
+ break;
+ }
}
}
-/* helper for apply() - perform sliding for some 3-element vector */
+/**
+ * Helper for apply() - perform sliding for some 3-element vector.
+ */
static void pose_slide_apply_vec3(tPoseSlideOp *pso,
tPChanFCurveLink *pfl,
float vec[3],
@@ -684,30 +718,32 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso,
LinkData *ld = NULL;
char *path = NULL;
- /* get the path to use... */
+ /* Get the path to use. */
path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
- /* using this path, find each matching F-Curve for the variables we're interested in */
+ /* Using this path, find each matching F-Curve for the variables we're interested in. */
while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
FCurve *fcu = (FCurve *)ld->data;
const int idx = fcu->array_index;
const int lock = pso->axislock;
- /* check if this F-Curve is ok given the current axis locks */
+ /* Check if this F-Curve is ok given the current axis locks. */
BLI_assert(fcu->array_index < 3);
if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
((lock & PS_LOCK_Z) && (idx == 2))) {
- /* just work on these channels one by one... there's no interaction between values */
+ /* Just work on these channels one by one... there's no interaction between values. */
pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
}
}
- /* free the temp path we got */
+ /* Free the temp path we got. */
MEM_freeN(path);
}
-/* helper for apply() - perform sliding for custom properties or bbone properties */
+/**
+ * Helper for apply() - perform sliding for custom properties or bbone properties.
+ */
static void pose_slide_apply_props(tPoseSlideOp *pso,
tPChanFCurveLink *pfl,
const char prop_prefix[])
@@ -716,7 +752,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso,
LinkData *ld;
int len = strlen(pfl->pchan_path);
- /* setup pointer RNA for resolving paths */
+ /* Setup pointer RNA for resolving paths. */
RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
/* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
@@ -732,22 +768,21 @@ static void pose_slide_apply_props(tPoseSlideOp *pso,
continue;
}
- /* do we have a match?
- * - bPtr is the RNA Path with the standard part chopped off
- * - pPtr is the chunk of the path which is left over
+ /* Do we have a match?
+ * - bPtr is the RNA Path with the standard part chopped off.
+ * - pPtr is the chunk of the path which is left over.
*/
bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
pPtr = strstr(bPtr, prop_prefix);
if (pPtr) {
- /* use RNA to try and get a handle on this property, then, assuming that it is just
- * numerical, try and grab the value as a float for temp editing before setting back
- */
+ /* Use RNA to try and get a handle on this property, then, assuming that it is just
+ * numerical, try and grab the value as a float for temp editing before setting back. */
PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
if (prop) {
switch (RNA_property_type(prop)) {
- /* continuous values that can be smoothly interpolated... */
+ /* Continuous values that can be smoothly interpolated. */
case PROP_FLOAT: {
float tval = RNA_property_float_get(&ptr, prop);
pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
@@ -761,7 +796,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso,
break;
}
- /* values which can only take discrete values */
+ /* Values which can only take discrete values. */
case PROP_BOOLEAN: {
float tval = (float)RNA_property_boolean_get(&ptr, prop);
pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
@@ -770,14 +805,13 @@ static void pose_slide_apply_props(tPoseSlideOp *pso,
break;
}
case PROP_ENUM: {
- /* don't handle this case - these don't usually represent interchangeable
- * set of values which should be interpolated between
- */
+ /* Don't handle this case - these don't usually represent interchangeable
+ * set of values which should be interpolated between. */
break;
}
default:
- /* cannot handle */
+ /* Cannot handle. */
// printf("Cannot Pose Slide non-numerical property\n");
break;
}
@@ -786,7 +820,9 @@ static void pose_slide_apply_props(tPoseSlideOp *pso,
}
}
-/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
+/**
+ * Helper for apply() - perform sliding for quaternion rotations (using quat blending).
+ */
static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
{
FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
@@ -801,17 +837,17 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
return;
}
- /* get the path to use - this should be quaternion rotations only (needs care) */
+ /* Get the path to use - this should be quaternion rotations only (needs care). */
path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
- /* get the current frame number */
+ /* Get the current frame number. */
cframe = (float)pso->cframe;
- /* using this path, find each matching F-Curve for the variables we're interested in */
+ /* Using this path, find each matching F-Curve for the variables we're interested in. */
while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
FCurve *fcu = (FCurve *)ld->data;
- /* assign this F-Curve to one of the relevant pointers... */
+ /* Assign this F-Curve to one of the relevant pointers. */
switch (fcu->array_index) {
case 3: /* z */
fcu_z = fcu;
@@ -828,14 +864,14 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
}
}
- /* only if all channels exist, proceed */
+ /* Only if all channels exist, proceed. */
if (fcu_w && fcu_x && fcu_y && fcu_z) {
float quat_final[4];
- /* perform blending */
+ /* Perform blending. */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* Just perform the interpolation between quat_prev and
- * quat_next using pso->percentage as a guide. */
+ * quat_next using pso->factor as a guide. */
float quat_prev[4];
float quat_next[4];
@@ -852,7 +888,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
normalize_qt(quat_prev);
normalize_qt(quat_next);
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->factor);
}
else {
/* POSESLIDE_PUSH and POSESLIDE_RELAX. */
@@ -870,11 +906,11 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
normalize_qt(quat_curr);
if (pso->mode == POSESLIDE_PUSH) {
- interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->percentage);
+ interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->factor);
}
else {
BLI_assert(pso->mode == POSESLIDE_RELAX);
- interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->percentage);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->factor);
}
}
@@ -882,7 +918,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat);
}
- /* free the path now */
+ /* Free the path now. */
MEM_freeN(path);
}
@@ -895,11 +931,11 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo
((lock & PS_LOCK_Z) && (idx == 2))) {
float diff_val = default_value - vec[idx];
if (pso->mode == POSESLIDE_RELAX_REST) {
- vec[idx] += pso->percentage * diff_val;
+ vec[idx] += pso->factor * diff_val;
}
else {
/* Push */
- vec[idx] -= pso->percentage * diff_val;
+ vec[idx] -= pso->factor * diff_val;
}
}
}
@@ -917,56 +953,58 @@ static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4]
for (int idx = 0; idx < 4; idx++) {
float diff_val = default_values[idx] - vec[idx];
if (pso->mode == POSESLIDE_RELAX_REST) {
- vec[idx] += pso->percentage * diff_val;
+ vec[idx] += pso->factor * diff_val;
}
else {
/* Push */
- vec[idx] -= pso->percentage * diff_val;
+ vec[idx] -= pso->factor * diff_val;
}
}
}
-/* apply() - perform the pose sliding between the current pose and the rest pose */
+/**
+ * apply() - perform the pose sliding between the current pose and the rest pose.
+ */
static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso)
{
tPChanFCurveLink *pfl;
- /* for each link, handle each set of transforms */
+ /* For each link, handle each set of transforms. */
for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
- /* valid transforms for each PoseChannel should have been noted already
- * - sliding the pose should be a straightforward exercise for location+rotation,
+ /* Valid transforms for each #bPoseChannel should have been noted already.
+ * - Sliding the pose should be a straightforward exercise for location+rotation,
* but rotations get more complicated since we may want to use quaternion blending
- * for quaternions instead...
+ * for quaternions instead.
*/
bPoseChannel *pchan = pfl->pchan;
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
- /* calculate these for the 'location' vector, and use location curves */
+ /* Calculate these for the 'location' vector, and use location curves. */
pose_slide_rest_pose_apply_vec3(pso, pchan->loc, 0.0f);
}
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
- /* calculate these for the 'scale' vector, and use scale curves */
+ /* Calculate these for the 'scale' vector, and use scale curves. */
pose_slide_rest_pose_apply_vec3(pso, pchan->size, 1.0f);
}
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
- /* everything depends on the rotation mode */
+ /* Everything depends on the rotation mode. */
if (pchan->rotmode > 0) {
- /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
+ /* Eulers - so calculate these for the 'eul' vector, and use euler_rotation curves. */
pose_slide_rest_pose_apply_vec3(pso, pchan->eul, 0.0f);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, false);
}
else {
- /* quaternions - use quaternion blending */
+ /* Quaternions - use quaternion blending. */
pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, true);
}
}
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
- /* bbone properties - they all start a "bbone_" prefix */
+ /* Bbone properties - they all start a "bbone_" prefix. */
/* TODO Not implemented */
// pose_slide_apply_props(pso, pfl, "bbone_");
}
@@ -979,18 +1017,20 @@ static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso)
}
}
- /* depsgraph updates + redraws */
+ /* Depsgraph updates + redraws. */
pose_slide_refresh(C, pso);
}
-/* apply() - perform the pose sliding based on weighting various poses */
+/**
+ * apply() - perform the pose sliding based on weighting various poses.
+ */
static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
{
tPChanFCurveLink *pfl;
/* Sanitize the frame ranges. */
if (pso->prevFrame == pso->nextFrame) {
- /* move out one step either side */
+ /* Move out one step either side. */
pso->prevFrame--;
pso->nextFrame++;
@@ -1001,7 +1041,7 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
continue;
}
- /* apply NLA mapping corrections so the frame lookups work */
+ /* Apply NLA mapping corrections so the frame look-ups work. */
ob_data->prevFrameF = BKE_nla_tweakedit_remap(
ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
ob_data->nextFrameF = BKE_nla_tweakedit_remap(
@@ -1009,9 +1049,9 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
- /* for each link, handle each set of transforms */
+ /* For each link, handle each set of transforms. */
for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
- /* valid transforms for each PoseChannel should have been noted already
+ /* Valid transforms for each #bPoseChannel should have been noted already
* - sliding the pose should be a straightforward exercise for location+rotation,
* but rotations get more complicated since we may want to use quaternion blending
* for quaternions instead...
@@ -1019,32 +1059,32 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
bPoseChannel *pchan = pfl->pchan;
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
- /* calculate these for the 'location' vector, and use location curves */
+ /* Calculate these for the 'location' vector, and use location curves. */
pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
}
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
- /* calculate these for the 'scale' vector, and use scale curves */
+ /* Calculate these for the 'scale' vector, and use scale curves. */
pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
}
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
- /* everything depends on the rotation mode */
+ /* Everything depends on the rotation mode. */
if (pchan->rotmode > 0) {
- /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
+ /* Eulers - so calculate these for the 'eul' vector, and use euler_rotation curves. */
pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
/* TODO: need to figure out how to do this! */
}
else {
- /* quaternions - use quaternion blending */
+ /* Quaternions - use quaternion blending. */
pose_slide_apply_quat(pso, pfl);
}
}
if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
- /* bbone properties - they all start a "bbone_" prefix */
+ /* Bbone properties - they all start a "bbone_" prefix. */
pose_slide_apply_props(pso, pfl, "bbone_");
}
@@ -1055,28 +1095,35 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
- /* depsgraph updates + redraws */
+ /* Depsgraph updates + redraws. */
pose_slide_refresh(C, pso);
}
-/* perform auto-key-framing after changes were made + confirmed */
+/**
+ * Perform auto-key-framing after changes were made + confirmed.
+ */
static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
{
- /* wrapper around the generic call */
+ /* Wrapper around the generic call. */
poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
}
-/* reset changes made to current pose */
+/**
+ * Reset changes made to current pose.
+ */
static void pose_slide_reset(tPoseSlideOp *pso)
{
- /* wrapper around the generic call, so that custom stuff can be added later */
+ /* Wrapper around the generic call, so that custom stuff can be added later. */
poseAnim_mapping_reset(&pso->pfLinks);
}
/* ------------------------------------ */
-/* Draw percentage indicator in workspace footer. */
-/* TODO: Include hints about locks here... */
+/**
+ * Draw percentage indicator in status-bar.
+ *
+ * TODO: Include hints about locks here.
+ */
static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
{
char status_str[UI_MAX_DRAW_STR];
@@ -1100,25 +1147,25 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
break;
default:
- /* unknown */
+ /* Unknown. */
strcpy(mode_str, TIP_("Sliding-Tool"));
break;
}
switch (pso->axislock) {
case PS_LOCK_X:
- BLI_strncpy(axis_str, TIP_("[X]/Y/Z axis only (X to clear)"), sizeof(axis_str));
+ STRNCPY(axis_str, TIP_("[X]/Y/Z axis only (X to clear)"));
break;
case PS_LOCK_Y:
- BLI_strncpy(axis_str, TIP_("X/[Y]/Z axis only (Y to clear)"), sizeof(axis_str));
+ STRNCPY(axis_str, TIP_("X/[Y]/Z axis only (Y to clear)"));
break;
case PS_LOCK_Z:
- BLI_strncpy(axis_str, TIP_("X/Y/[Z] axis only (Z to clear)"), sizeof(axis_str));
+ STRNCPY(axis_str, TIP_("X/Y/[Z] axis only (Z to clear)"));
break;
default:
if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
- BLI_strncpy(axis_str, TIP_("X/Y/Z = Axis Constraint"), sizeof(axis_str));
+ STRNCPY(axis_str, TIP_("X/Y/Z = Axis Constraint"));
}
else {
axis_str[0] = '\0';
@@ -1146,43 +1193,38 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
axis_str);
break;
case PS_TFM_BBONE_SHAPE:
- BLI_strncpy(limits_str,
- TIP_("G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s"),
- sizeof(limits_str));
+ STRNCPY(limits_str, TIP_("G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s"));
break;
case PS_TFM_PROPS:
- BLI_strncpy(limits_str,
- TIP_("G/R/S/B/[C] - Custom Properties only (C to clear) | %s"),
- sizeof(limits_str));
+ STRNCPY(limits_str, TIP_("G/R/S/B/[C] - Custom Properties only (C to clear) | %s"));
break;
default:
- BLI_strncpy(
- limits_str, TIP_("G/R/S/B/C - Limit to Transform/Property Set"), sizeof(limits_str));
+ STRNCPY(limits_str, TIP_("G/R/S/B/C - Limit to Transform/Property Set"));
break;
}
if (pso->overshoot) {
- BLI_strncpy(overshoot_str, TIP_("[E] - Disable overshoot"), sizeof(overshoot_str));
+ STRNCPY(overshoot_str, TIP_("[E] - Disable overshoot"));
}
else {
- BLI_strncpy(overshoot_str, TIP_("E - Enable overshoot"), sizeof(overshoot_str));
+ STRNCPY(overshoot_str, TIP_("[E] - Enable overshoot"));
}
if (pso->precision) {
- BLI_strncpy(precision_str, TIP_("[Shift] - Precision active"), sizeof(precision_str));
+ STRNCPY(precision_str, TIP_("[Shift] - Precision active"));
}
else {
- BLI_strncpy(precision_str, TIP_("Shift - Hold for precision"), sizeof(precision_str));
+ STRNCPY(precision_str, TIP_("Shift - Hold for precision"));
}
if (pso->increments) {
- BLI_strncpy(increments_str, TIP_("[Ctrl] - Increments active"), sizeof(increments_str));
+ STRNCPY(increments_str, TIP_("[Ctrl] - Increments active"));
}
else {
- BLI_strncpy(increments_str, TIP_("Ctrl - Hold for 10% increments"), sizeof(increments_str));
+ STRNCPY(increments_str, TIP_("Ctrl - Hold for 10% increments"));
}
- BLI_strncpy(bone_vis_str, TIP_("[H] - Toggle bone visibility"), sizeof(increments_str));
+ STRNCPY(bone_vis_str, TIP_("[H] - Toggle bone visibility"));
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
@@ -1208,57 +1250,59 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
ED_area_status_text(pso->area, "");
}
-/* common code for invoke() methods */
+/**
+ * Common code for invoke() methods.
+ */
static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
tPChanFCurveLink *pfl;
wmWindow *win = CTX_wm_window(C);
- /* for each link, add all its keyframes to the search tree */
+ /* For each link, add all its keyframes to the search tree. */
for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
LinkData *ld;
- /* do this for each F-Curve */
+ /* Do this for each F-Curve. */
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
}
}
- /* cancel if no keyframes found... */
+ /* Cancel if no keyframes found. */
if (pso->keys.root) {
ActKeyColumn *ak;
float cframe = (float)pso->cframe;
- /* firstly, check if the current frame is a keyframe... */
+ /* Firstly, check if the current frame is a keyframe. */
ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
if (ak == NULL) {
- /* current frame is not a keyframe, so search */
+ /* Current frame is not a keyframe, so search. */
ActKeyColumn *pk = (ActKeyColumn *)BLI_dlrbTree_search_prev(
&pso->keys, compare_ak_cfraPtr, &cframe);
ActKeyColumn *nk = (ActKeyColumn *)BLI_dlrbTree_search_next(
&pso->keys, compare_ak_cfraPtr, &cframe);
- /* new set the frames */
- /* prev frame */
+ /* New set the frames. */
+ /* Prev frame. */
pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
- /* next frame */
+ /* Next frame. */
pso->nextFrame = (nk) ? (nk->cfra) : (pso->cframe + 1);
RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
}
else {
- /* current frame itself is a keyframe, so just take keyframes on either side */
- /* prev frame */
+ /* Current frame itself is a keyframe, so just take keyframes on either side. */
+ /* Prev frame. */
pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
- /* next frame */
+ /* Next frame. */
pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
}
- /* apply NLA mapping corrections so the frame lookups work */
+ /* Apply NLA mapping corrections so the frame look-ups work. */
for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
if (ob_data->valid) {
@@ -1275,8 +1319,8 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
return OPERATOR_CANCELLED;
}
- /* initial apply for operator... */
- /* TODO: need to calculate percentage for initial round too... */
+ /* Initial apply for operator. */
+ /* TODO: need to calculate factor for initial round too. */
if (!ELEM(pso->mode, POSESLIDE_PUSH_REST, POSESLIDE_RELAX_REST)) {
pose_slide_apply(C, pso);
}
@@ -1284,16 +1328,16 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
pose_slide_rest_pose_apply(C, pso);
}
- /* depsgraph updates + redraws */
+ /* Depsgraph updates + redraws. */
pose_slide_refresh(C, pso);
- /* set cursor to indicate modal */
+ /* Set cursor to indicate modal. */
WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
- /* header print */
+ /* Header print. */
pose_slide_draw_status(C, pso);
- /* add a modal handler for this operator */
+ /* Add a modal handler for this operator. */
WM_event_add_modal_handler(C, op);
/* Hide Bone Overlay. */
@@ -1304,31 +1348,32 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
return OPERATOR_RUNNING_MODAL;
}
-/* Calculate percentage based on mouse movement, clamp or round to increments if
- * enabled by the user. Store the new percentage value.
+/**
+ * Calculate factor based on mouse movement, clamp or round to increments if
+ * enabled by the user. Store the new factor value.
*/
-static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso,
- wmOperator *op,
- const wmEvent *event)
+static void pose_slide_mouse_update_factor(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event)
{
- const float percentage_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE));
- /* Reduced percentage delta in precision mode (shift held). */
- pso->raw_percentage += pso->precision ? (percentage_delta / 8) : percentage_delta;
- pso->percentage = pso->raw_percentage;
+ const float factor_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE));
+ /* Reduced factor delta in precision mode (shift held). */
+ pso->raw_factor += pso->precision ? (factor_delta / 8) : factor_delta;
+ pso->factor = pso->raw_factor;
pso->last_cursor_x = event->x;
if (!pso->overshoot) {
- pso->percentage = clamp_f(pso->percentage, 0, 1);
+ pso->factor = clamp_f(pso->factor, 0, 1);
}
if (pso->increments) {
- pso->percentage = round(pso->percentage * 10) / 10;
+ pso->factor = round(pso->factor * 10) / 10;
}
- RNA_float_set(op->ptr, "percentage", pso->percentage);
+ RNA_float_set(op->ptr, "factor", pso->factor);
}
-/* handle an event to toggle channels mode */
+/**
+ * Handle an event to toggle channels mode.
+ */
static void pose_slide_toggle_channels_mode(wmOperator *op,
tPoseSlideOp *pso,
ePoseSlide_Channels channel)
@@ -1349,7 +1394,9 @@ static void pose_slide_toggle_channels_mode(wmOperator *op,
RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
}
-/* handle an event to toggle axis locks - returns whether any change in state is needed */
+/**
+ * Handle an event to toggle axis locks - returns whether any change in state is needed.
+ */
static bool pose_slide_toggle_axis_locks(wmOperator *op,
tPoseSlideOp *pso,
ePoseSlide_AxisLock axis)
@@ -1376,7 +1423,9 @@ static bool pose_slide_toggle_axis_locks(wmOperator *op,
return true;
}
-/* common code for modal() */
+/**
+ * Operator `modal()` callback.
+ */
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
@@ -1386,11 +1435,11 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
const bool has_numinput = hasNumInput(&pso->num);
switch (event->type) {
- case LEFTMOUSE: /* confirm */
+ case LEFTMOUSE: /* Confirm. */
case EVT_RETKEY:
case EVT_PADENTER: {
if (event->val == KM_PRESS) {
- /* return to normal cursor and header status */
+ /* Return to normal cursor and header status. */
ED_workspace_status_text(C, NULL);
ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
@@ -1398,48 +1447,48 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Depsgraph updates + redraws. Redraw needed to remove UI. */
pose_slide_refresh(C, pso);
- /* insert keyframes as required... */
+ /* Insert keyframes as required. */
pose_slide_autoKeyframe(C, pso);
pose_slide_exit(op);
- /* done! */
+ /* Done! */
return OPERATOR_FINISHED;
}
break;
}
- case EVT_ESCKEY: /* cancel */
+ case EVT_ESCKEY: /* Cancel. */
case RIGHTMOUSE: {
if (event->val == KM_PRESS) {
- /* return to normal cursor and header status */
+ /* Return to normal cursor and header status. */
ED_workspace_status_text(C, NULL);
ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
- /* reset transforms back to original state */
+ /* Reset transforms back to original state. */
pose_slide_reset(pso);
/* Depsgraph updates + redraws.*/
pose_slide_refresh(C, pso);
- /* clean up temp data */
+ /* Clean up temp data. */
pose_slide_exit(op);
- /* canceled! */
+ /* Canceled! */
return OPERATOR_CANCELLED;
}
break;
}
- /* Percentage Change... */
- case MOUSEMOVE: /* calculate new position */
+ /* Factor Change... */
+ case MOUSEMOVE: /* Calculate new position. */
{
- /* only handle mousemove if not doing numinput */
+ /* Only handle mouse-move if not doing numinput. */
if (has_numinput == false) {
- /* update percentage based on position of mouse */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* Update factor based on position of mouse. */
+ pose_slide_mouse_update_factor(pso, op, event);
- /* update pose to reflect the new values (see below) */
+ /* Update pose to reflect the new values (see below). */
do_pose_update = true;
}
break;
@@ -1451,12 +1500,12 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab percentage from numeric input, and store this new value for redo
* NOTE: users see ints, while internally we use a 0-1 float
*/
- value = pso->percentage * 100.0f;
+ value = pso->factor * 100.0f;
applyNumInput(&pso->num, &value);
- pso->percentage = value / 100.0f;
- CLAMP(pso->percentage, 0.0f, 1.0f);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
+ pso->factor = value / 100.0f;
+ CLAMP(pso->factor, 0.0f, 1.0f);
+ RNA_float_set(op->ptr, "factor", pso->factor);
/* Update pose to reflect the new values (see below) */
do_pose_update = true;
@@ -1571,8 +1620,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else {
- /* unhandled event - maybe it was some view manipulation? */
- /* allow to pass through */
+ /* Unhandled event - maybe it was some view manipulation? */
+ /* Allow to pass through. */
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
}
}
@@ -1581,13 +1630,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Perform pose updates - in response to some user action
* (e.g. pressing a key or moving the mouse). */
if (do_pose_update) {
- /* update percentage indicator in header */
+ /* Update percentage indicator in header. */
pose_slide_draw_status(C, pso);
- /* reset transforms (to avoid accumulation errors) */
+ /* Reset transforms (to avoid accumulation errors). */
pose_slide_reset(pso);
- /* apply... */
+ /* Apply. */
if (!ELEM(pso->mode, POSESLIDE_PUSH_REST, POSESLIDE_RELAX_REST)) {
pose_slide_apply(C, pso);
}
@@ -1596,21 +1645,25 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- /* still running... */
+ /* Still running. */
return OPERATOR_RUNNING_MODAL;
}
-/* common code for cancel() */
+/**
+ * Common code for cancel()
+ */
static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op)
{
- /* cleanup and done */
+ /* Cleanup and done. */
pose_slide_exit(op);
}
-/* common code for exec() methods */
+/**
+ * Common code for exec() methods.
+ */
static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
- /* settings should have been set up ok for applying, so just apply! */
+ /* Settings should have been set up ok for applying, so just apply! */
if (!ELEM(pso->mode, POSESLIDE_PUSH_REST, POSESLIDE_RELAX_REST)) {
pose_slide_apply(C, pso);
}
@@ -1618,10 +1671,10 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
pose_slide_rest_pose_apply(C, pso);
}
- /* insert keyframes if needed */
+ /* Insert keyframes if needed. */
pose_slide_autoKeyframe(C, pso);
- /* cleanup and done */
+ /* Cleanup and done. */
pose_slide_exit(op);
return OPERATOR_FINISHED;
@@ -1635,11 +1688,11 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
PropertyRNA *prop;
prop = RNA_def_float_factor(ot->srna,
- "percentage",
+ "factor",
0.5f,
0.0f,
1.0f,
- "Percentage",
+ "Factor",
"Weighting factor for which keyframe is favored more",
0.0,
1.0);
@@ -1685,12 +1738,14 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
/* ------------------------------------ */
-/* invoke() - for 'push from breakdown' mode */
+/**
+ * Operator `invoke()` callback for 'push from breakdown' mode.
+ */
static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
- /* initialize data */
+ /* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1700,19 +1755,21 @@ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *ev
pso->last_cursor_x = event->x;
- /* Initialize percentage so that it won't pop on first mouse move. */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* Initialize factor so that it won't pop on first mouse move. */
+ pose_slide_mouse_update_factor(pso, op, event);
- /* do common setup work */
+ /* Do common setup work. */
return pose_slide_invoke_common(C, op, pso);
}
-/* exec() - for push */
+/**
+ * Operator `exec()` callback - for push.
+ */
static int pose_slide_push_exec(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso;
- /* initialize data (from RNA-props) */
+ /* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1720,7 +1777,7 @@ static int pose_slide_push_exec(bContext *C, wmOperator *op)
pso = op->customdata;
- /* do common exec work */
+ /* Do common exec work. */
return pose_slide_exec_common(C, op, pso);
}
@@ -1747,12 +1804,14 @@ void POSE_OT_push(wmOperatorType *ot)
/* ........................ */
-/* invoke() - for 'relax to breakdown' mode */
+/**
+ * Invoke callback - for 'relax to breakdown' mode.
+ */
static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
- /* initialize data */
+ /* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1762,19 +1821,21 @@ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *e
pso->last_cursor_x = event->x;
- /* Initialize percentage so that it won't pop on first mouse move. */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* Initialize factor so that it won't pop on first mouse move. */
+ pose_slide_mouse_update_factor(pso, op, event);
- /* do common setup work */
+ /* Do common setup work. */
return pose_slide_invoke_common(C, op, pso);
}
-/* exec() - for relax */
+/**
+ * Operator exec() - for relax.
+ */
static int pose_slide_relax_exec(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso;
- /* initialize data (from RNA-props) */
+ /* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1782,7 +1843,7 @@ static int pose_slide_relax_exec(bContext *C, wmOperator *op)
pso = op->customdata;
- /* do common exec work */
+ /* Do common exec work. */
return pose_slide_exec_common(C, op, pso);
}
@@ -1808,12 +1869,14 @@ void POSE_OT_relax(wmOperatorType *ot)
}
/* ........................ */
-/* invoke() - for 'push from rest pose' mode */
+/**
+ * Operator `invoke()` - for 'push from rest pose' mode.
+ */
static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
- /* initialize data */
+ /* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1823,19 +1886,21 @@ static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEven
pso->last_cursor_x = event->x;
- /* Initialize percentage so that it won't pop on first mouse move. */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* Initialize factor so that it won't pop on first mouse move. */
+ pose_slide_mouse_update_factor(pso, op, event);
/* do common setup work */
return pose_slide_invoke_common(C, op, pso);
}
-/* exec() - for push */
+/**
+ * Operator `exec()` - for push.
+ */
static int pose_slide_push_rest_exec(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso;
- /* initialize data (from RNA-props) */
+ /* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1843,7 +1908,7 @@ static int pose_slide_push_rest_exec(bContext *C, wmOperator *op)
pso = op->customdata;
- /* do common exec work */
+ /* Do common exec work. */
return pose_slide_exec_common(C, op, pso);
}
@@ -1870,12 +1935,14 @@ void POSE_OT_push_rest(wmOperatorType *ot)
/* ........................ */
-/* invoke() - for 'relax' mode */
+/**
+ * Operator `invoke()` - for 'relax' mode.
+ */
static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
- /* initialize data */
+ /* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1885,19 +1952,21 @@ static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEve
pso->last_cursor_x = event->x;
- /* Initialize percentage so that it won't pop on first mouse move. */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* Initialize factor so that it won't pop on first mouse move. */
+ pose_slide_mouse_update_factor(pso, op, event);
- /* do common setup work */
+ /* Do common setup work. */
return pose_slide_invoke_common(C, op, pso);
}
-/* exec() - for relax */
+/**
+ * Operator `exec()` - for relax.
+ */
static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso;
- /* initialize data (from RNA-props) */
+ /* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1905,7 +1974,7 @@ static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op)
pso = op->customdata;
- /* do common exec work */
+ /* Do common exec work. */
return pose_slide_exec_common(C, op, pso);
}
@@ -1932,12 +2001,14 @@ void POSE_OT_relax_rest(wmOperatorType *ot)
/* ........................ */
-/* invoke() - for 'breakdown' mode */
+/**
+ * Operator `invoke()` - for 'breakdown' mode.
+ */
static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
- /* initialize data */
+ /* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1947,19 +2018,21 @@ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEven
pso->last_cursor_x = event->x;
- /* Initialize percentage so that it won't pop on first mouse move. */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* Initialize factor so that it won't pop on first mouse move. */
+ pose_slide_mouse_update_factor(pso, op, event);
- /* do common setup work */
+ /* Do common setup work. */
return pose_slide_invoke_common(C, op, pso);
}
-/* exec() - for breakdown */
+/**
+ * Operator exec() - for breakdown.
+ */
static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso;
- /* initialize data (from RNA-props) */
+ /* Initialize data (from RNA-props). */
if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
pose_slide_exit(op);
return OPERATOR_CANCELLED;
@@ -1967,7 +2040,7 @@ static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
pso = op->customdata;
- /* do common exec work */
+ /* Do common exec work. */
return pose_slide_exec_common(C, op, pso);
}
@@ -1997,36 +2070,39 @@ void POSE_OT_breakdown(wmOperatorType *ot)
/* "termination conditions" - i.e. when we stop */
typedef enum ePosePropagate_Termination {
- /* stop after the current hold ends */
+ /** Stop after the current hold ends. */
POSE_PROPAGATE_SMART_HOLDS = 0,
- /* only do on the last keyframe */
+ /** Only do on the last keyframe. */
POSE_PROPAGATE_LAST_KEY,
- /* stop after the next keyframe */
+ /** Stop after the next keyframe. */
POSE_PROPAGATE_NEXT_KEY,
- /* stop after the specified frame */
+ /** Stop after the specified frame. */
POSE_PROPAGATE_BEFORE_FRAME,
- /* stop when we run out of keyframes */
+ /** Stop when we run out of keyframes. */
POSE_PROPAGATE_BEFORE_END,
- /* only do on keyframes that are selected */
+ /** Only do on keyframes that are selected. */
POSE_PROPAGATE_SELECTED_KEYS,
- /* only do on the frames where markers are selected */
+ /** Only do on the frames where markers are selected. */
POSE_PROPAGATE_SELECTED_MARKERS,
} ePosePropagate_Termination;
-/* Termination data needed for some modes -
- * assumes only one of these entries will be needed at a time. */
+/**
+ * Termination data needed for some modes -
+ * assumes only one of these entries will be needed at a time.
+ */
typedef union tPosePropagate_ModeData {
- /* smart holds + before frame: frame number to stop on */
+ /** Smart holds + before frame: frame number to stop on. */
float end_frame;
- /* selected markers: listbase for CfraElem's marking these frames */
+ /** Selected markers: listbase for CfraElem's marking these frames. */
ListBase sel_markers;
} tPosePropagate_ModeData;
/* --------------------------------- */
-/* get frame on which the "hold" for the bone ends
+/**
+ * Get frame on which the "hold" for the bone ends.
* XXX: this may not really work that well if a bone moves on some channels and not others
* if this happens to be a major issue, scrap this, and just make this happen
* independently per F-Curve
@@ -2040,7 +2116,7 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st
LinkData *ld;
float endFrame = startFrame;
- /* set up optimized data-structures for searching for relevant keyframes + holds */
+ /* Set up optimized data-structures for searching for relevant keyframes + holds. */
BLI_dlrbTree_init(&keys);
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
@@ -2048,7 +2124,7 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st
fcurve_to_keylist(adt, fcu, &keys, 0);
}
- /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
+ /* Find the long keyframe (i.e. hold), and hence obtain the endFrame value
* - the best case would be one that starts on the frame itself
*/
ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(
@@ -2062,67 +2138,68 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st
* otherwise forget it, as we'd be overwriting some valid data.
*/
if (ab == NULL) {
- /* we've got case 1, so try the one after */
+ /* We've got case 1, so try the one after. */
ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* try the block before this frame then as last resort */
+ /* Try the block before this frame then as last resort. */
ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
}
}
- /* whatever happens, stop searching now... */
+ /* Whatever happens, stop searching now.... */
if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* restrict range to just the frame itself
- * i.e. everything is in motion, so no holds to safely overwrite
- */
+ /* Restrict range to just the frame itself
+ * i.e. everything is in motion, so no holds to safely overwrite. */
ab = NULL;
}
- /* check if we can go any further than we've already gone */
+ /* Check if we can go any further than we've already gone. */
if (ab) {
- /* go to next if it is also valid and meets "extension" criteria */
+ /* Go to next if it is also valid and meets "extension" criteria. */
while (ab->next) {
ActKeyColumn *abn = ab->next;
- /* must be valid */
+ /* Must be valid. */
if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
break;
}
- /* should have the same number of curves */
+ /* Should have the same number of curves. */
if (ab->totblock != abn->totblock) {
break;
}
- /* we can extend the bounds to the end of this "next" block now */
+ /* We can extend the bounds to the end of this "next" block now. */
ab = abn;
}
- /* end frame can now take the value of the end of the block */
+ /* End frame can now take the value of the end of the block. */
endFrame = ab->next->cfra;
}
- /* free temp memory */
+ /* Free temp memory. */
BLI_dlrbTree_free(&keys);
- /* return the end frame we've found */
+ /* Return the end frame we've found. */
return endFrame;
}
-/* get reference value from F-Curve using RNA */
+/**
+ * Get reference value from F-Curve using RNA.
+ */
static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value)
{
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
bool found = false;
- /* base pointer is always the object -> id_ptr */
+ /* Base pointer is always the `object -> id_ptr`. */
RNA_id_pointer_create(&ob->id, &id_ptr);
- /* resolve the property... */
+ /* Resolve the property. */
if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
if (RNA_property_array_check(prop)) {
- /* array */
+ /* Array. */
if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
found = true;
switch (RNA_property_type(prop)) {
@@ -2142,7 +2219,7 @@ static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value)
}
}
else {
- /* not an array */
+ /* Not an array. */
found = true;
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
@@ -2167,7 +2244,9 @@ static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value)
return found;
}
-/* propagate just works along each F-Curve in turn */
+/**
+ * Propagate just works along each F-Curve in turn.
+ */
static void pose_propagate_fcurve(
wmOperator *op, Object *ob, FCurve *fcu, float startFrame, tPosePropagate_ModeData modeData)
{
@@ -2176,31 +2255,31 @@ static void pose_propagate_fcurve(
BezTriple *bezt;
float refVal = 0.0f;
bool keyExists;
- int i, match;
+ int i;
bool first = true;
- /* skip if no keyframes to edit */
+ /* Skip if no keyframes to edit. */
if ((fcu->bezt == NULL) || (fcu->totvert < 2)) {
return;
}
- /* find the reference value from bones directly, which means that the user
+ /* Find the reference value from bones directly, which means that the user
* doesn't need to firstly keyframe the pose (though this doesn't mean that
- * they can't either)
- */
+ * they can't either). */
if (!pose_propagate_get_refVal(ob, fcu, &refVal)) {
return;
}
- /* find the first keyframe to start propagating from
+ /* Find the first keyframe to start propagating from:
* - if there's a keyframe on the current frame, we probably want to save this value there too
- * since it may be as of yet unkeyed
+ * since it may be as of yet un-keyed
* - if starting before the starting frame, don't touch the key, as it may have had some valid
* values
* - if only doing selected keyframes, start from the first one
*/
if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
- match = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
+ const int match = BKE_fcurve_bezt_binarysearch_index(
+ fcu->bezt, startFrame, fcu->totvert, &keyExists);
if (fcu->bezt[match].vec[1][0] < startFrame) {
i = match + 1;
@@ -2210,58 +2289,58 @@ static void pose_propagate_fcurve(
}
}
else {
- /* selected - start from first keyframe */
+ /* Selected - start from first keyframe. */
i = 0;
}
for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
- /* additional termination conditions based on the operator 'mode' property go here... */
+ /* Additional termination conditions based on the operator 'mode' property go here. */
if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
- /* stop if keyframe is outside the accepted range */
+ /* Stop if keyframe is outside the accepted range. */
if (bezt->vec[1][0] > modeData.end_frame) {
break;
}
}
else if (mode == POSE_PROPAGATE_NEXT_KEY) {
- /* stop after the first keyframe has been processed */
+ /* Stop after the first keyframe has been processed. */
if (first == false) {
break;
}
}
else if (mode == POSE_PROPAGATE_LAST_KEY) {
- /* only affect this frame if it will be the last one */
+ /* Only affect this frame if it will be the last one. */
if (i != (fcu->totvert - 1)) {
continue;
}
}
else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
- /* only allow if there's a marker on this frame */
+ /* Only allow if there's a marker on this frame. */
CfraElem *ce = NULL;
- /* stop on matching marker if there is one */
+ /* Stop on matching marker if there is one. */
for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
if (ce->cfra == round_fl_to_int(bezt->vec[1][0])) {
break;
}
}
- /* skip this keyframe if no marker */
+ /* Skip this keyframe if no marker. */
if (ce == NULL) {
continue;
}
}
else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
- /* only allow if this keyframe is already selected - skip otherwise */
+ /* Only allow if this keyframe is already selected - skip otherwise. */
if (BEZT_ISSEL_ANY(bezt) == 0) {
continue;
}
}
- /* just flatten handles, since values will now be the same either side... */
+ /* Just flatten handles, since values will now be the same either side. */
/* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
- /* select keyframe to indicate that it's been changed */
+ /* Select keyframe to indicate that it's been changed. */
bezt->f2 |= SELECT;
first = false;
}
@@ -2281,7 +2360,7 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
tPosePropagate_ModeData modeData;
const int mode = RNA_enum_get(op->ptr, "mode");
- /* isolate F-Curves related to the selected bones */
+ /* Isolate F-Curves related to the selected bones. */
poseAnim_mapping_get(C, &pflinks);
if (BLI_listbase_is_empty(&pflinks)) {
@@ -2292,42 +2371,41 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* mode-specific data preprocessing (requiring no access to curves) */
+ /* Mode-specific data preprocessing (requiring no access to curves). */
if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
- /* get a list of selected markers */
+ /* Get a list of selected markers. */
ED_markers_make_cfra_list(&scene->markers, &modeData.sel_markers, SELECT);
}
else {
- /* assume everything else wants endFrame */
+ /* Assume everything else wants endFrame. */
modeData.end_frame = RNA_float_get(op->ptr, "end_frame");
}
- /* for each bone, perform the copying required */
+ /* For each bone, perform the copying required. */
for (pfl = pflinks.first; pfl; pfl = pfl->next) {
LinkData *ld;
- /* mode-specific data preprocessing (requiring access to all curves) */
+ /* Mode-specific data preprocessing (requiring access to all curves). */
if (mode == POSE_PROPAGATE_SMART_HOLDS) {
- /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
- * from the keyframe that occurs after the current frame
- */
+ /* We store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
+ * from the keyframe that occurs after the current frame. */
modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
}
- /* go through propagating pose to keyframes, curve by curve */
+ /* Go through propagating pose to keyframes, curve by curve. */
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
}
}
- /* free temp data */
+ /* Free temp data. */
poseAnim_mapping_free(&pflinks);
if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
BLI_freelistN(&modeData.sel_markers);
}
- /* updates + notifiers */
+ /* Updates + notifiers. */
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
poseAnim_mapping_refresh(C, scene, ob);
}
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 43ab20eb71c..6466773daac 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -144,26 +144,25 @@ static void applyarmature_transfer_properties(EditBone *curbone,
if (pchan->bone->segments > 1) {
/* Combine rest/pose values. */
curbone->curve_in_x += pchan_eval->curve_in_x;
- curbone->curve_in_y += pchan_eval->curve_in_y;
+ curbone->curve_in_z += pchan_eval->curve_in_z;
curbone->curve_out_x += pchan_eval->curve_out_x;
- curbone->curve_out_y += pchan_eval->curve_out_y;
+ curbone->curve_out_z += pchan_eval->curve_out_z;
curbone->roll1 += pchan_eval->roll1;
curbone->roll2 += pchan_eval->roll2;
curbone->ease1 += pchan_eval->ease1;
curbone->ease2 += pchan_eval->ease2;
- curbone->scale_in_x *= pchan_eval->scale_in_x;
- curbone->scale_in_y *= pchan_eval->scale_in_y;
- curbone->scale_out_x *= pchan_eval->scale_out_x;
- curbone->scale_out_y *= pchan_eval->scale_out_y;
+ mul_v3_v3(curbone->scale_in, pchan_eval->scale_in);
+ mul_v3_v3(curbone->scale_out, pchan_eval->scale_out);
/* Reset pose values. */
pchan->curve_in_x = pchan->curve_out_x = 0.0f;
- pchan->curve_in_y = pchan->curve_out_y = 0.0f;
+ pchan->curve_in_z = pchan->curve_out_z = 0.0f;
pchan->roll1 = pchan->roll2 = 0.0f;
pchan->ease1 = pchan->ease2 = 0.0f;
- pchan->scale_in_x = pchan->scale_in_y = 1.0f;
- pchan->scale_out_x = pchan->scale_out_y = 1.0f;
+
+ copy_v3_fl(pchan->scale_in, 1.0f);
+ copy_v3_fl(pchan->scale_out, 1.0f);
}
/* Clear transform values for pchan. */
@@ -699,18 +698,17 @@ static bPoseChannel *pose_bone_do_paste(Object *ob,
/* B-Bone posing options should also be included... */
pchan->curve_in_x = chan->curve_in_x;
- pchan->curve_in_y = chan->curve_in_y;
+ pchan->curve_in_z = chan->curve_in_z;
pchan->curve_out_x = chan->curve_out_x;
- pchan->curve_out_y = chan->curve_out_y;
+ pchan->curve_out_z = chan->curve_out_z;
pchan->roll1 = chan->roll1;
pchan->roll2 = chan->roll2;
pchan->ease1 = chan->ease1;
pchan->ease2 = chan->ease2;
- pchan->scale_in_x = chan->scale_in_x;
- pchan->scale_in_y = chan->scale_in_y;
- pchan->scale_out_x = chan->scale_out_x;
- pchan->scale_out_y = chan->scale_out_y;
+
+ copy_v3_v3(pchan->scale_in, chan->scale_in);
+ copy_v3_v3(pchan->scale_out, chan->scale_out);
/* paste flipped pose? */
if (flip) {
@@ -972,8 +970,9 @@ static void pchan_clear_scale(bPoseChannel *pchan)
pchan->ease1 = 0.0f;
pchan->ease2 = 0.0f;
- pchan->scale_in_x = pchan->scale_in_y = 1.0f;
- pchan->scale_out_x = pchan->scale_out_y = 1.0f;
+
+ copy_v3_fl(pchan->scale_in, 1.0f);
+ copy_v3_fl(pchan->scale_out, 1.0f);
}
/* Clear the scale. When X-mirror is enabled,
* also clear the scale of the mirrored pose channel. */
@@ -1136,9 +1135,9 @@ static void pchan_clear_rot(bPoseChannel *pchan)
pchan->roll2 = 0.0f;
pchan->curve_in_x = 0.0f;
- pchan->curve_in_y = 0.0f;
+ pchan->curve_in_z = 0.0f;
pchan->curve_out_x = 0.0f;
- pchan->curve_out_y = 0.0f;
+ pchan->curve_out_z = 0.0f;
}
/* Clear the rotation. When X-mirror is enabled,
* also clear the rotation of the mirrored pose channel. */
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 75348c2b196..8eae5288f7a 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -116,15 +116,14 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks,
pfl->roll1 = pchan->roll1;
pfl->roll2 = pchan->roll2;
pfl->curve_in_x = pchan->curve_in_x;
- pfl->curve_in_y = pchan->curve_in_y;
+ pfl->curve_in_z = pchan->curve_in_z;
pfl->curve_out_x = pchan->curve_out_x;
- pfl->curve_out_y = pchan->curve_out_y;
+ pfl->curve_out_z = pchan->curve_out_z;
pfl->ease1 = pchan->ease1;
pfl->ease2 = pchan->ease2;
- pfl->scale_in_x = pchan->scale_in_x;
- pfl->scale_in_y = pchan->scale_in_y;
- pfl->scale_out_x = pchan->scale_out_x;
- pfl->scale_out_y = pchan->scale_out_y;
+
+ copy_v3_v3(pfl->scale_in, pchan->scale_in);
+ copy_v3_v3(pfl->scale_out, pchan->scale_out);
/* make copy of custom properties */
if (pchan->prop && (transFlags & ACT_TRANS_PROP)) {
@@ -251,15 +250,14 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
pchan->roll1 = pfl->roll1;
pchan->roll2 = pfl->roll2;
pchan->curve_in_x = pfl->curve_in_x;
- pchan->curve_in_y = pfl->curve_in_y;
+ pchan->curve_in_z = pfl->curve_in_z;
pchan->curve_out_x = pfl->curve_out_x;
- pchan->curve_out_y = pfl->curve_out_y;
+ pchan->curve_out_z = pfl->curve_out_z;
pchan->ease1 = pfl->ease1;
pchan->ease2 = pfl->ease2;
- pchan->scale_in_x = pfl->scale_in_x;
- pchan->scale_in_y = pfl->scale_in_y;
- pchan->scale_out_x = pfl->scale_out_x;
- pchan->scale_out_y = pfl->scale_out_y;
+
+ copy_v3_v3(pchan->scale_in, pfl->scale_in);
+ copy_v3_v3(pchan->scale_out, pfl->scale_out);
/* just overwrite values of properties from the stored copies (there should be some) */
if (pfl->oldprops) {
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 535ccaa06fd..2999ac784ba 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -6646,7 +6646,7 @@ void CURVE_OT_dissolve_verts(wmOperatorType *ot)
static bool nurb_bezt_flag_any(const Nurb *nu, const char flag_test)
{
- BezTriple *bezt = nu->bezt;
+ const BezTriple *bezt;
int i;
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index e4f2de1f741..febcf83116b 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -128,6 +128,7 @@ struct CurveDrawData {
} prev;
ViewContext vc;
+ ViewDepths *depths;
enum {
CURVE_DRAW_IDLE = 0,
CURVE_DRAW_PAINTING = 1,
@@ -188,7 +189,6 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
float r_normal_world[3])
{
ARegion *region = cdd->vc.region;
- RegionView3D *rv3d = cdd->vc.rv3d;
bool is_location_world_set = false;
@@ -204,7 +204,7 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
}
}
else {
- const ViewDepths *depths = rv3d->depths;
+ const ViewDepths *depths = cdd->depths;
if (depths && ((uint)mval_i[0] < depths->w) && ((uint)mval_i[1] < depths->h)) {
float depth_fl = 1.0f;
ED_view3d_depth_read_cached(depths, mval_i, 0, &depth_fl);
@@ -219,7 +219,7 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
if (surface_offset != 0.0f) {
const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
float normal[3];
- if (ED_view3d_depth_read_cached_normal(&cdd->vc, mval_i, normal)) {
+ if (ED_view3d_depth_read_cached_normal(region, depths, mval_i, normal)) {
madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
if (r_normal_world) {
copy_v3_v3(r_normal_world, normal);
@@ -387,7 +387,6 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C),
GPU_matrix_translate_3f(selem->location_local[0] - location_prev[0],
selem->location_local[1] - location_prev[1],
selem->location_local[2] - location_prev[2]);
- location_prev = selem->location_local;
const float radius = stroke_elem_radius(cdd, selem);
@@ -529,7 +528,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
if (ELEM(cps->surface_plane,
CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE)) {
- if (ED_view3d_depth_read_cached_normal(&cdd->vc, event->mval, normal)) {
+ if (ED_view3d_depth_read_cached_normal(cdd->vc.region, cdd->depths, event->mval, normal)) {
if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
float cross_a[3], cross_b[3];
cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
@@ -623,6 +622,9 @@ static void curve_draw_exit(wmOperator *op)
BLI_mempool_destroy(cdd->stroke_elem_pool);
}
+ if (cdd->depths) {
+ ED_view3d_depths_free(cdd->depths);
+ }
MEM_freeN(cdd);
op->customdata = NULL;
}
@@ -1085,10 +1087,14 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- ED_view3d_depth_override(
- cdd->vc.depsgraph, cdd->vc.region, cdd->vc.v3d, NULL, V3D_DEPTH_NO_GPENCIL, true);
+ ED_view3d_depth_override(cdd->vc.depsgraph,
+ cdd->vc.region,
+ cdd->vc.v3d,
+ NULL,
+ V3D_DEPTH_NO_GPENCIL,
+ &cdd->depths);
- if (cdd->vc.rv3d->depths != NULL) {
+ if (cdd->depths != NULL) {
cdd->project.use_depth = true;
}
else {
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index fe1c5efc747..3131ec70fb0 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -760,15 +760,15 @@ static void annotation_draw_data_all(Scene *scene,
int winy,
int cfra,
int dflag,
- const char spacetype)
+ const eSpace_Type space_type)
{
bGPdata *gpd_source = NULL;
if (scene) {
- if (spacetype == SPACE_VIEW3D) {
+ if (space_type == SPACE_VIEW3D) {
gpd_source = (scene->gpd ? scene->gpd : NULL);
}
- else if (spacetype == SPACE_CLIP && scene->clip) {
+ else if (space_type == SPACE_CLIP && scene->clip) {
/* currently drawing only gpencil data from either clip or track,
* but not both - XXX fix logic behind */
gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index c155587e95a..e3c6fd8f878 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -667,7 +667,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
(ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- false);
+ NULL);
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
@@ -1226,7 +1226,7 @@ static void annotation_stroke_doeraser(tGPsdata *p)
if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
- ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false);
+ ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
}
}
@@ -1706,7 +1706,7 @@ static void annotation_paint_strokeend(tGPsdata *p)
(ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- false);
+ NULL);
}
/* check if doing eraser or not */
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index 3271096c433..6d6f4bc4b40 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -462,8 +462,8 @@ static void gpencil_object_vgroup_calc_from_armature(const bContext *C,
defbase_add = gpencil_bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
if (defbase_add) {
- /* its possible there are DWeight's outside the range of the current
- * objects deform groups, in this case the new groups wont be empty */
+ /* It's possible there are DWeights outside the range of the current
+ * object's deform groups. In this case the new groups won't be empty */
ED_vgroup_data_clamp_range(ob->data, defbase_tot);
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index f29f5187015..21fa3ad3967 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -863,7 +863,7 @@ static void gpencil_duplicate_points(bGPdata *gpd,
start_idx = i;
}
}
- else {
+ if ((start_idx != -1) || (start_idx == gps->totpoints - 1)) {
size_t len = 0;
/* is this the end of current island yet?
@@ -4618,6 +4618,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
/* add layer if not created before */
if (gpl_dst == NULL) {
gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false, false);
+ BKE_gpencil_layer_copy_settings(gpl, gpl_dst);
}
/* add frame if not created before */
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index f74e211dd65..5c4e2de6aa8 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1373,7 +1373,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(tgpf->win, tgpf->region);
ED_view3d_depth_override(
- tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, false);
+ tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
/* Since strokes are so fine, when using their depth we need a margin
* otherwise they might get missed. */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index e40748e5f6e..638994bbc2a 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1744,7 +1744,7 @@ static void gpencil_stroke_doeraser(tGPsdata *p)
if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
- ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false);
+ ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
}
}
@@ -2334,7 +2334,7 @@ static void gpencil_paint_strokeend(tGPsdata *p)
(ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- false);
+ NULL);
}
/* check if doing eraser or not */
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 5f02bbf0a77..a2b4e5dee64 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -792,7 +792,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
(ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- false);
+ NULL);
depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points");
tGPspoint *ptc = &points2D[0];
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index e1776988186..55521ac4d15 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -1276,7 +1276,7 @@ static bool gpencil_stroke_do_circle_sel(bGPdata *gpd,
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
bGPDspoint pt_temp;
- gpencil_point_to_parent_space(pt_active, diff_mat, &pt_temp);
+ gpencil_point_to_parent_space(pt, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
/* do boundbox check first */
@@ -1847,7 +1847,7 @@ static bool gpencil_generic_stroke_select(bContext *C,
bGPDspoint *pt;
int i;
bool hit = false;
- for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* convert point coords to screenspace */
@@ -1889,7 +1889,7 @@ static bool gpencil_generic_stroke_select(bContext *C,
mval[0] = (box.xmax + box.xmin) / 2;
mval[1] = (box.ymax + box.ymin) / 2;
- whole = ED_gpencil_stroke_point_is_inside(gps_active, &gsc, mval, gpstroke_iter.diff_mat);
+ whole = ED_gpencil_stroke_point_is_inside(gps, &gsc, mval, gpstroke_iter.diff_mat);
}
/* if stroke mode expand selection. */
@@ -2252,7 +2252,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
int i;
/* firstly, check for hit-point */
- for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
bGPDspoint pt2;
diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c
index 482f7015720..12c38fb2744 100644
--- a/source/blender/editors/gpencil/gpencil_trace_utils.c
+++ b/source/blender/editors/gpencil/gpencil_trace_utils.c
@@ -281,7 +281,6 @@ void ED_gpencil_trace_data_to_strokes(Main *bmain,
mat_mask_idx = ob->totcol - 1;
}
- potrace_path_t *path = st->plist;
int n, *tag;
potrace_dpoint_t(*c)[3];
@@ -289,7 +288,7 @@ void ED_gpencil_trace_data_to_strokes(Main *bmain,
* good results using the Potrace data. */
const float scalef = 0.008f * scale;
/* Draw each curve. */
- path = st->plist;
+ potrace_path_t *path = st->plist;
while (path != NULL) {
n = path->curve.n;
tag = path->curve.tag;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index c9ef340b9d3..4da21bd05ee 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -680,7 +680,7 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
view3d_operator_needs_opengl(C);
view3d_region_operator_needs_opengl(win, region);
- ED_view3d_depth_override(depsgraph, region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false);
+ ED_view3d_depth_override(depsgraph, region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index 9ac6b6c1085..dde26c072d0 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -27,9 +27,10 @@ extern "C" {
#endif
struct Main;
+struct wmWindowManager;
/* info_stats.c */
-void ED_info_stats_clear(struct ViewLayer *view_layer);
+void ED_info_stats_clear(struct wmWindowManager *wm, struct ViewLayer *view_layer);
const char *ED_info_statusbar_string(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
@@ -41,6 +42,7 @@ const char *ED_info_statistics_string(struct Main *bmain,
void ED_info_draw_stats(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
+ struct View3D *v3d_local,
int x,
int *y,
int height);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index b8e9f6e8871..0e2be5eb568 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -36,6 +36,7 @@ struct BMFace;
struct BMLoop;
struct BMVert;
struct BMesh;
+struct BMeshNormalsUpdate_Params;
struct Base;
struct Depsgraph;
struct ID;
@@ -76,6 +77,8 @@ struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *
void EDBM_verts_mirror_cache_clear(struct BMEditMesh *em, struct BMVert *v);
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em);
+void EDBM_mesh_normals_update_ex(struct BMEditMesh *em,
+ const struct BMeshNormalsUpdate_Params *params);
void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
@@ -103,7 +106,14 @@ bool EDBM_vert_color_check(struct BMEditMesh *em);
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap);
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select);
-void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
+struct EDBMUpdate_Params {
+ uint calc_looptri : 1;
+ uint calc_normals : 1;
+ uint is_destructive : 1;
+};
+
+void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params);
+void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 67a50b83bd6..ba65840dc99 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -49,6 +49,11 @@ typedef enum {
} NodeBorder;
#define NODE_GRID_STEPS 5
+#define NODE_EDGE_PAN_INSIDE_PAD 2
+#define NODE_EDGE_PAN_OUTSIDE_PAD 0 /* Disable clamping for node panning, use whole screen. */
+#define NODE_EDGE_PAN_SPEED_RAMP 1
+#define NODE_EDGE_PAN_MAX_SPEED 40 /* In UI units per second, slower than default. */
+#define NODE_EDGE_PAN_DELAY 1.0f
/* space_node.c */
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 6f88ab4253a..1738c383328 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -295,12 +295,12 @@ void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C,
struct wmOperator *op,
const char view_align_axis,
- float loc[3],
- float rot[3],
- float scale[3],
- bool *enter_editmode,
- unsigned short *local_view_bits,
- bool *is_view_aligned);
+ float r_loc[3],
+ float r_rot[3],
+ float r_scale[3],
+ bool *r_enter_editmode,
+ unsigned short *r_local_view_bits,
+ bool *r_is_view_aligned);
struct Object *ED_object_add_type_with_obdata(struct bContext *C,
const int type,
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index e84298bd9c2..6d0172e724a 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -34,6 +34,7 @@ struct ParticleSystem;
struct Scene;
struct UndoType;
struct ViewLayer;
+struct wmGenericUserData;
struct bContext;
struct rcti;
@@ -68,7 +69,11 @@ void PE_update_object(struct Depsgraph *depsgraph,
bool PE_mouse_particles(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
-bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad);
+bool PE_circle_select(struct bContext *C,
+ struct wmGenericUserData *wm_userdata,
+ const int sel_op,
+ const int mval[2],
+ float rad);
int PE_lasso_select(struct bContext *C,
const int mcoords[][2],
const int mcoords_len,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index bdd7ec571dc..823050b46f7 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -215,7 +215,7 @@ void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
void ED_screen_full_restore(struct bContext *C, ScrArea *area);
-ScrArea *ED_screen_state_maximized_create(struct bContext *C);
+bScreen *ED_screen_state_maximized_create(struct bContext *C);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
@@ -317,6 +317,7 @@ bool ED_operator_animview_active(struct bContext *C);
bool ED_operator_outliner_active(struct bContext *C);
bool ED_operator_outliner_active_no_editobject(struct bContext *C);
bool ED_operator_file_active(struct bContext *C);
+bool ED_operator_spreadsheet_active(struct bContext *C);
bool ED_operator_action_active(struct bContext *C);
bool ED_operator_buttons_active(struct bContext *C);
bool ED_operator_node_active(struct bContext *C);
@@ -354,6 +355,7 @@ bool ED_operator_uvedit(struct bContext *C);
bool ED_operator_uvedit_space_image(struct bContext *C);
bool ED_operator_uvmap(struct bContext *C);
bool ED_operator_posemode_exclusive(struct bContext *C);
+bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext *C);
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h
index 11eff2d583b..606b4c9cad0 100644
--- a/source/blender/editors/include/ED_sequencer.h
+++ b/source/blender/editors/include/ED_sequencer.h
@@ -42,6 +42,8 @@ bool ED_space_sequencer_maskedit_poll(struct bContext *C);
bool ED_space_sequencer_check_show_imbuf(struct SpaceSeq *sseq);
bool ED_space_sequencer_check_show_strip(struct SpaceSeq *sseq);
+bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
+ const struct Scene *scene);
void ED_operatormacros_sequencer(void);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 52d69d12253..64883ed5f1d 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -90,8 +90,6 @@ typedef struct ViewDepths {
short x, y; /* only for temp use for sub-rects, added to region->winx/y */
float *depths;
double depth_range[2];
-
- bool damaged;
} ViewDepths;
/* Rotate 3D cursor on placement. */
@@ -154,19 +152,20 @@ void ED_view3d_depth_override(struct Depsgraph *depsgraph,
struct View3D *v3d,
struct Object *obact,
eV3DDepthOverrideMode mode,
- bool update_cache);
+ struct ViewDepths **r_depths);
+void ED_view3d_depths_free(ViewDepths *depths);
bool ED_view3d_depth_read_cached(const ViewDepths *vd,
const int mval[2],
int margin,
float *r_depth);
-bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
+bool ED_view3d_depth_read_cached_normal(const struct ARegion *region,
+ const ViewDepths *depths,
const int mval[2],
float r_normal[3]);
bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
const int mval[2],
const double depth,
float r_location_world[3]);
-void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
/* Projection */
#define IS_CLIPPED 12000
@@ -196,12 +195,38 @@ typedef enum {
V3D_PROJ_TEST_CLIP_NEAR = (1 << 2),
V3D_PROJ_TEST_CLIP_FAR = (1 << 3),
V3D_PROJ_TEST_CLIP_ZERO = (1 << 4),
+ /**
+ * Clip the contents of the data being iterated over.
+ * Currently this is only used to edges when projecting into screen space.
+ *
+ * Clamp the edge within the viewport limits defined by
+ * #V3D_PROJ_TEST_CLIP_WIN, #V3D_PROJ_TEST_CLIP_NEAR & #V3D_PROJ_TEST_CLIP_FAR.
+ * This resolves the problem of a visible edge having one of it's vertices
+ * behind the viewport. See: T32214.
+ *
+ * This is not default behavior as it may be important for the screen-space location
+ * of an edges vertex to represent that vertices location (instead of a location along the edge).
+ *
+ * \note Perspective views should enable #V3D_PROJ_TEST_CLIP_WIN along with
+ * #V3D_PROJ_TEST_CLIP_NEAR as the near-plane-clipped location of a point
+ * may become very large (even infinite) when projected into screen-space.
+ * Unless the that point happens to coincide with the camera's point of view.
+ *
+ * Use #V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT instead of #V3D_PROJ_TEST_CLIP_CONTENT,
+ * to avoid accidentally enabling near clipping without clipping by window bounds.
+ */
+ V3D_PROJ_TEST_CLIP_CONTENT = (1 << 5),
} eV3DProjTest;
#define V3D_PROJ_TEST_CLIP_DEFAULT \
(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
#define V3D_PROJ_TEST_ALL \
- (V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_FAR | V3D_PROJ_TEST_CLIP_ZERO)
+ (V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_FAR | V3D_PROJ_TEST_CLIP_ZERO | \
+ V3D_PROJ_TEST_CLIP_CONTENT)
+
+#define V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT \
+ (V3D_PROJ_TEST_CLIP_CONTENT | V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_FAR | \
+ V3D_PROJ_TEST_CLIP_WIN)
/* view3d_iterators.c */
@@ -404,7 +429,7 @@ bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
float r_ray_end[3],
const bool do_clip);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
- struct Object *ob,
+ const struct Object *ob,
float r_pmat[4][4]);
void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d,
const float obmat[4][4],
@@ -578,8 +603,8 @@ bool ED_view3d_area_user_region(const struct ScrArea *area,
struct ARegion **r_region);
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
-void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d);
-void ED_view3d_init_mats_rv3d_gl(struct Object *ob, struct RegionView3D *rv3d);
+void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d);
+void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d);
#ifdef DEBUG
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d);
void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 338b12f7985..df65c602fc4 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -290,18 +290,14 @@ enum {
/** Active right part of number button */
UI_BUT_ACTIVE_RIGHT = 1 << 22,
- /* (also used by search buttons to enforce shortcut display for their items). */
- /** Button has shortcut text. */
- UI_BUT_HAS_SHORTCUT = 1 << 23,
-
/** Reverse order of consecutive off/on icons */
- UI_BUT_ICON_REVERSE = 1 << 24,
+ UI_BUT_ICON_REVERSE = 1 << 23,
/** Value is animated, but the current value differs from the animated one. */
- UI_BUT_ANIMATED_CHANGED = 1 << 25,
+ UI_BUT_ANIMATED_CHANGED = 1 << 24,
/* Draw the checkbox buttons inverted. */
- UI_BUT_CHECKBOX_INVERT = 1 << 26,
+ UI_BUT_CHECKBOX_INVERT = 1 << 25,
};
/* scale fixed button widths by this to account for DPI */
@@ -723,6 +719,7 @@ void UI_but_drag_set_asset(uiBut *but,
const char *name,
const char *path,
int id_type,
+ int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,
float scale);
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 64f881052a1..999f42efe65 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -105,8 +105,12 @@ struct ScrArea;
struct bContext;
struct bScreen;
struct rctf;
+struct rcti;
+struct wmEvent;
struct wmGizmoGroupType;
struct wmKeyConfig;
+struct wmOperator;
+struct wmOperatorType;
typedef struct View2DScrollers View2DScrollers;
@@ -287,6 +291,77 @@ void UI_view2d_smooth_view(struct bContext *C,
/* Caller passes in own idname. */
void VIEW2D_GGT_navigate_impl(struct wmGizmoGroupType *gzgt, const char *idname);
+/* Edge pan */
+
+/**
+ * Custom-data for view panning operators.
+ */
+typedef struct View2DEdgePanData {
+ /** Screen where view pan was initiated. */
+ struct bScreen *screen;
+ /** Area where view pan was initiated. */
+ struct ScrArea *area;
+ /** Region where view pan was initiated. */
+ struct ARegion *region;
+ /** View2d we're operating in. */
+ struct View2D *v2d;
+
+ /** Inside distance in UI units from the edge of the region within which to start panning. */
+ float inside_pad;
+ /** Outside distance in UI units from the edge of the region at which to stop panning. */
+ float outside_pad;
+ /**
+ * Width of the zone in UI units where speed increases with distance from the edge.
+ * At the end of this zone max speed is reached.
+ */
+ float speed_ramp;
+ /** Maximum speed in UI units per second. */
+ float max_speed;
+ /** Delay in seconds before maximum speed is reached. */
+ float delay;
+
+ /** Amount to move view relative to zoom. */
+ float facx, facy;
+
+ /* Timers. */
+ double edge_pan_last_time;
+ double edge_pan_start_time_x, edge_pan_start_time_y;
+} View2DEdgePanData;
+
+bool UI_view2d_edge_pan_poll(struct bContext *C);
+
+void UI_view2d_edge_pan_init(struct bContext *C,
+ struct View2DEdgePanData *vpd,
+ float inside_pad,
+ float outside_pad,
+ float speed_ramp,
+ float max_speed,
+ float delay);
+
+void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd);
+
+/* Apply transform to view (i.e. adjust 'cur' rect). */
+void UI_view2d_edge_pan_apply(struct bContext *C, struct View2DEdgePanData *vpd, int x, int y);
+
+/* Apply transform to view using mouse events. */
+void UI_view2d_edge_pan_apply_event(struct bContext *C,
+ struct View2DEdgePanData *vpd,
+ const struct wmEvent *event);
+
+void UI_view2d_edge_pan_operator_properties(struct wmOperatorType *ot);
+
+void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
+ float inside_pad,
+ float outside_pad,
+ float speed_ramp,
+ float max_speed,
+ float delay);
+
+/* Initialize panning data with operator settings. */
+void UI_view2d_edge_pan_operator_init(struct bContext *C,
+ struct View2DEdgePanData *vpd,
+ struct wmOperator *op);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 421019bebb8..5011a50ed73 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -75,6 +75,7 @@ set(SRC
resources.c
view2d.c
view2d_draw.c
+ view2d_edge_pan.c
view2d_gizmo_navigate.c
view2d_ops.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index f6b2a6a1bc6..f5528638bec 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -985,12 +985,12 @@ bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBu
/**
* \warning This must run after other handlers have been added,
- * otherwise the handler wont be removed, see: T71112.
+ * otherwise the handler won't be removed, see: T71112.
*/
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
{
/* Running this command before end-block has run, means buttons that open menus
- * wont have those menus correctly positioned, see T83539. */
+ * won't have those menus correctly positioned, see T83539. */
BLI_assert(block->endblock);
bool done = false;
@@ -1160,7 +1160,6 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str
MEM_freeN(butstr_orig);
but->str = but->strdata;
but->flag |= UI_BUT_HAS_SEP_CHAR;
- but->drawflag |= UI_BUT_HAS_SHORTCUT;
ui_but_update(but);
}
@@ -3224,8 +3223,8 @@ void ui_but_range_set_hard(uiBut *but)
/* note: this could be split up into functions which handle arrays and not */
void ui_but_range_set_soft(uiBut *but)
{
- /* ideally we would not limit this but practically, its more than
- * enough worst case is very long vectors wont use a smart soft-range
+ /* Ideally we would not limit this, but practically it's more than
+ * enough. Worst case is very long vectors won't use a smart soft-range,
* which isn't so bad. */
if (but->rnaprop) {
@@ -6144,6 +6143,7 @@ void UI_but_drag_set_asset(uiBut *but,
const char *name,
const char *path,
int id_type,
+ int import_type,
int icon,
struct ImBuf *imb,
float scale)
@@ -6153,6 +6153,7 @@ void UI_but_drag_set_asset(uiBut *but,
BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name));
asset_drag->path = path;
asset_drag->id_type = id_type;
+ asset_drag->import_type = import_type;
but->dragtype = WM_DRAG_ASSET;
ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index b142e383df0..775e3923edc 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -1280,7 +1280,6 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but = block->buttons.last;
but->flag |= UI_BUT_HAS_SEP_CHAR;
- but->drawflag |= UI_BUT_HAS_SHORTCUT;
}
}
UI_popup_menu_end(C, pup);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5f98a501bec..1c55ce0f348 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1561,7 +1561,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
};
/* check if this is a different button,
- * chances are high the button wont move about :) */
+ * chances are high the button won't move about :) */
if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) {
if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) <
fabsf(drag_info->but_cent_start[1] - but_cent_new[1])) {
@@ -1939,7 +1939,7 @@ static bool ui_but_drag_init(bContext *C,
uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
ARegion *region_prev;
- /* call here because regular mouse-up event wont run,
+ /* call here because regular mouse-up event won't run,
* typically 'button_activate_exit()' handles this */
ui_apply_but_autokey(C, but);
@@ -3414,7 +3414,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
const int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
/* not a file?, strip non utf-8 chars */
if (strip) {
- /* wont happen often so isn't that annoying to keep it here for a while */
+ /* won't happen often so isn't that annoying to keep it here for a while */
printf("%s: invalid utf8 - stripped chars %d\n", __func__, strip);
}
}
@@ -3906,7 +3906,6 @@ static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data)
data->startvalue = ui_but_value_get(but);
data->origvalue = data->startvalue;
data->value = data->origvalue;
- but->editval = &data->value;
}
static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
@@ -3935,6 +3934,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
}
else {
ui_numedit_begin_set_values(but, data);
+ but->editval = &data->value;
float softmin = but->softmin;
float softmax = but->softmax;
@@ -9662,7 +9662,7 @@ static void ui_region_auto_open_clear(ARegion *region)
* This allows a menu to be open,
* but send key events to the parent if there's no active buttons.
*
- * Without this keyboard navigation from menu's wont work.
+ * Without this keyboard navigation from menus won't work.
*/
static bool ui_menu_pass_event_to_parent_if_nonactive(uiPopupBlockHandle *menu,
const uiBut *but,
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 0cf3ad59903..ce5c17a0718 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -803,7 +803,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
/* Special case when we do this for 'Sequence.lock'.
- * (if the sequence is locked, it wont be in "selected_editable_sequences"). */
+ * (if the sequence is locked, it won't be in "selected_editable_sequences"). */
const char *prop_id = RNA_property_identifier(prop);
if (STREQ(prop_id, "lock")) {
*r_lb = CTX_data_collection_get(C, "selected_sequences");
@@ -921,7 +921,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
* to handle situations like T41062... */
if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
/* Special case when we do this for 'Sequence.lock'.
- * (if the sequence is locked, it wont be in "selected_editable_sequences"). */
+ * (if the sequence is locked, it won't be in "selected_editable_sequences"). */
const char *prop_id = RNA_property_identifier(prop);
if (STREQ(prop_id, "lock")) {
*r_lb = CTX_data_collection_get(C, "selected_sequences");
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6505a7cd76a..6694535e3af 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -674,7 +674,7 @@ static bool panel_type_context_poll(ARegion *region,
const PanelType *panel_type,
const char *context)
{
- if (UI_panel_category_is_visible(region)) {
+ if (!BLI_listbase_is_empty(&region->panels_category)) {
return STREQ(panel_type->category, UI_panel_category_active_get(region, false));
}
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 987cde61f97..c35dbc5d7a6 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -95,7 +95,7 @@ typedef struct uiSearchboxData {
/** draw thumbnail previews, rather than list */
bool preview;
/** Use the #UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data). */
- bool use_sep;
+ bool use_shortcut_sep;
int prv_rows, prv_cols;
/**
* Show the active icon and text after the last instance of this string.
@@ -314,7 +314,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
data->items.name_prefix_offsets[data->active] :
0);
- const char *name_sep = data->use_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
+ const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) + 1 : data->items.maxstrlen);
@@ -535,7 +535,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
/* Never include the prefix in the button. */
(data->items.name_prefix_offsets ? data->items.name_prefix_offsets[a] :
0);
- const char *name_sep = data->use_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
+ const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) {
data->active = a;
break;
@@ -627,7 +627,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
char *name_sep_test = NULL;
uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE;
- if (data->use_sep) {
+ if (data->use_shortcut_sep) {
separator_type = UI_MENU_ITEM_SEPARATOR_SHORTCUT;
}
/* Only set for displaying additional hint (e.g. library name of a linked data-block). */
@@ -719,7 +719,10 @@ static void ui_searchbox_region_free_cb(ARegion *region)
region->regiondata = NULL;
}
-ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearch *search_but)
+static ARegion *ui_searchbox_create_generic_ex(bContext *C,
+ ARegion *butregion,
+ uiButSearch *search_but,
+ const bool use_shortcut_sep)
{
wmWindow *win = CTX_wm_window(C);
const uiStyle *style = UI_style_get();
@@ -759,12 +762,8 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearc
data->prv_cols = but->a2;
}
- /* Only show key shortcuts when needed (checking RNA prop pointer is useless here, a lot of
- * buttons are about data without having that pointer defined, let's rather try with optype!).
- * One can also enforce that behavior by setting
- * UI_BUT_HAS_SHORTCUT drawflag of search button. */
- if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) {
- data->use_sep = true;
+ if (but->optype != NULL || use_shortcut_sep) {
+ data->use_shortcut_sep = true;
}
data->sep_string = search_but->item_sep_string;
@@ -888,6 +887,11 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearc
return region;
}
+ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearch *search_but)
+{
+ return ui_searchbox_create_generic_ex(C, butregion, search_but, false);
+}
+
/**
* Similar to Python's `str.title` except...
*
@@ -973,8 +977,8 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
data->items.names[a],
0,
state,
- data->use_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT :
- UI_MENU_ITEM_SEPARATOR_NONE,
+ data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT :
+ UI_MENU_ITEM_SEPARATOR_NONE,
NULL);
}
}
@@ -996,8 +1000,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiButSearch *search_but)
{
- UI_but_drawflag_enable(&search_but->but, UI_BUT_HAS_SHORTCUT);
- ARegion *region = ui_searchbox_create_generic(C, butregion, search_but);
+ ARegion *region = ui_searchbox_create_generic_ex(C, butregion, search_but, true);
region->type->draw = ui_searchbox_region_draw_cb__operator;
@@ -1016,8 +1019,7 @@ static void ui_searchbox_region_draw_cb__menu(const bContext *UNUSED(C), ARegion
ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *search_but)
{
- UI_but_drawflag_enable(&search_but->but, UI_BUT_HAS_SHORTCUT);
- ARegion *region = ui_searchbox_create_generic(C, butregion, search_but);
+ ARegion *region = ui_searchbox_create_generic_ex(C, butregion, search_but, true);
if (false) {
region->type->draw = ui_searchbox_region_draw_cb__menu;
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index fe6a8b0d1a6..ce1109ad9df 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1949,8 +1949,8 @@ static bool widget_draw_text_underline_calc_position(const char *UNUSED(str),
/* Full width of this glyph including both bearings. */
const float width = glyph_bounds->xmin + BLI_rctf_size_x(glyph_bounds) + glyph_bounds->xmin;
ul_data->r_offset_px[0] = glyph_step_bounds->xmin + ((width - ul_data->width_px) * 0.5f);
- /* Two line-widths below the lower glyph bounds. */
- ul_data->r_offset_px[1] = glyph_bounds->ymin - U.pixelsize - U.pixelsize;
+ /* One line-width below the lower glyph bounds. */
+ ul_data->r_offset_px[1] = glyph_bounds->ymin - U.pixelsize;
/* Early exit. */
return false;
}
@@ -2131,14 +2131,15 @@ static void widget_draw_text(const uiFontStyle *fstyle,
transopts = ui_translate_buttons();
#endif
+ bool use_drawstr_right_as_hint = false;
+
/* cut string in 2 parts - only for menu entries */
- if ((but->drawflag & UI_BUT_HAS_SHORTCUT) && (but->editstr == NULL)) {
- if (but->flag & UI_BUT_HAS_SEP_CHAR) {
- drawstr_right = strrchr(drawstr, UI_SEP_CHAR);
- if (drawstr_right) {
- drawstr_left_len = (drawstr_right - drawstr);
- drawstr_right++;
- }
+ if (but->flag & UI_BUT_HAS_SEP_CHAR && (but->editstr == NULL)) {
+ drawstr_right = strrchr(drawstr, UI_SEP_CHAR);
+ if (drawstr_right) {
+ use_drawstr_right_as_hint = true;
+ drawstr_left_len = (drawstr_right - drawstr);
+ drawstr_right++;
}
}
@@ -2207,7 +2208,6 @@ static void widget_draw_text(const uiFontStyle *fstyle,
}
int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2));
- int ul_height = max_ii(fstyle->points * U.dpi_fac * 0.1f, U.pixelsize);
struct UnderlineData ul_data = {
.str_offset = ul_index,
@@ -2220,16 +2220,13 @@ static void widget_draw_text(const uiFontStyle *fstyle,
widget_draw_text_underline_calc_position,
&ul_data);
- GPU_blend(GPU_BLEND_ALPHA);
- const uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4ubv(wcol->text);
const int pos_x = rect->xmin + font_xofs + ul_data.r_offset_px[0];
const int pos_y = rect->ymin + font_yofs + ul_data.r_offset_px[1];
- immRecti(pos, pos_x, pos_y, pos_x + ul_width, pos_y - ul_height);
- immUnbindProgram();
- GPU_blend(GPU_BLEND_NONE);
+
+ /* Use text output because direct drawing doesn't always work. See T89246. */
+ BLF_position(fstyle->uifont_id, pos_x, pos_y, 0.0f);
+ BLF_color4ubv(fstyle->uifont_id, wcol->text);
+ BLF_draw(fstyle->uifont_id, "_", 2);
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
@@ -2243,7 +2240,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
if (drawstr_right) {
uchar col[4];
copy_v4_v4_uchar(col, wcol->text);
- if (but->drawflag & UI_BUT_HAS_SHORTCUT) {
+ if (use_drawstr_right_as_hint) {
col[3] *= 0.5f;
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index e4dad0f1a53..224993555bf 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -991,10 +991,11 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resiz
if (ELEM(0, width, height)) {
if (G.debug & G_DEBUG) {
+ /* XXX: temp debug info. */
printf("Error: View2D totRect set exiting: v2d=%p width=%d height=%d\n",
(void *)v2d,
width,
- height); /* XXX temp debug info */
+ height);
}
return;
}
diff --git a/source/blender/editors/interface/view2d_edge_pan.c b/source/blender/editors/interface/view2d_edge_pan.c
new file mode 100644
index 00000000000..ca32a754f1d
--- /dev/null
+++ b/source/blender/editors/interface/view2d_edge_pan.c
@@ -0,0 +1,345 @@
+/*
+ * 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) 2021 Blender Foundation
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spnode
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Edge Pan Operator Utilities
+ * \{ */
+
+bool UI_view2d_edge_pan_poll(bContext *C)
+{
+ ARegion *region = CTX_wm_region(C);
+
+ /* Check if there's a region in context to work with. */
+ if (region == NULL) {
+ return false;
+ }
+
+ View2D *v2d = &region->v2d;
+
+ /* Check that 2d-view can pan. */
+ if ((v2d->keepofs & V2D_LOCKOFS_X) && (v2d->keepofs & V2D_LOCKOFS_Y)) {
+ return false;
+ }
+
+ /* View can pan. */
+ return true;
+}
+
+void UI_view2d_edge_pan_init(bContext *C,
+ View2DEdgePanData *vpd,
+ float inside_pad,
+ float outside_pad,
+ float speed_ramp,
+ float max_speed,
+ float delay)
+{
+ if (!UI_view2d_edge_pan_poll(C)) {
+ return;
+ }
+
+ /* Set pointers to owners. */
+ vpd->screen = CTX_wm_screen(C);
+ vpd->area = CTX_wm_area(C);
+ vpd->region = CTX_wm_region(C);
+ vpd->v2d = &vpd->region->v2d;
+
+ BLI_assert(speed_ramp > 0.0f);
+ vpd->inside_pad = inside_pad;
+ vpd->outside_pad = outside_pad;
+ vpd->speed_ramp = speed_ramp;
+ vpd->max_speed = max_speed;
+ vpd->delay = delay;
+
+ /* Calculate translation factor, based on size of view. */
+ const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1);
+ const float winy = (float)(BLI_rcti_size_y(&vpd->region->winrct) + 1);
+ vpd->facx = (BLI_rctf_size_x(&vpd->v2d->cur)) / winx;
+ vpd->facy = (BLI_rctf_size_y(&vpd->v2d->cur)) / winy;
+
+ UI_view2d_edge_pan_reset(vpd);
+}
+
+void UI_view2d_edge_pan_reset(View2DEdgePanData *vpd)
+{
+ vpd->edge_pan_start_time_x = 0.0;
+ vpd->edge_pan_start_time_y = 0.0;
+ vpd->edge_pan_last_time = PIL_check_seconds_timer();
+}
+
+/**
+ * Reset the edge pan timers if the mouse isn't in the scroll zone and
+ * start the timers when the mouse enters a scroll zone.
+ */
+static void edge_pan_manage_delay_timers(View2DEdgePanData *vpd,
+ int pan_dir_x,
+ int pan_dir_y,
+ const double current_time)
+{
+ if (pan_dir_x == 0) {
+ vpd->edge_pan_start_time_x = 0.0;
+ }
+ else if (vpd->edge_pan_start_time_x == 0.0) {
+ vpd->edge_pan_start_time_x = current_time;
+ }
+ if (pan_dir_y == 0) {
+ vpd->edge_pan_start_time_y = 0.0;
+ }
+ else if (vpd->edge_pan_start_time_y == 0.0) {
+ vpd->edge_pan_start_time_y = current_time;
+ }
+}
+
+/**
+ * Used to calculate a "fade in" factor for edge panning to make the interaction feel smooth
+ * and more purposeful.
+ *
+ * \note Assumes a domain_min of 0.0f.
+ */
+static float smootherstep(const float domain_max, float x)
+{
+ x = clamp_f(x / domain_max, 0.0, 1.0);
+ return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
+}
+
+static float edge_pan_speed(View2DEdgePanData *vpd,
+ int event_loc,
+ bool x_dir,
+ const double current_time)
+{
+ ARegion *region = vpd->region;
+
+ /* Find the distance from the start of the drag zone. */
+ const int pad = vpd->inside_pad * U.widget_unit;
+ const int min = (x_dir ? region->winrct.xmin : region->winrct.ymin) + pad;
+ const int max = (x_dir ? region->winrct.xmax : region->winrct.ymax) - pad;
+ int distance = 0.0;
+ if (event_loc > max) {
+ distance = event_loc - max;
+ }
+ else if (event_loc < min) {
+ distance = min - event_loc;
+ }
+ else {
+ BLI_assert(!"Calculating speed outside of pan zones");
+ return 0.0f;
+ }
+ float distance_factor = distance / (vpd->speed_ramp * U.widget_unit);
+ CLAMP(distance_factor, 0.0f, 1.0f);
+
+ /* Apply a fade in to the speed based on a start time delay. */
+ const double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y;
+ const float delay_factor = smootherstep(vpd->delay, (float)(current_time - start_time));
+
+ return distance_factor * delay_factor * vpd->max_speed * U.widget_unit * (float)U.dpi_fac;
+}
+
+static void edge_pan_apply_delta(bContext *C, View2DEdgePanData *vpd, float dx, float dy)
+{
+ View2D *v2d = vpd->v2d;
+ if (!v2d) {
+ return;
+ }
+
+ /* Calculate amount to move view by. */
+ dx *= vpd->facx;
+ dy *= vpd->facy;
+
+ /* Only move view on an axis if change is allowed. */
+ if ((v2d->keepofs & V2D_LOCKOFS_X) == 0) {
+ v2d->cur.xmin += dx;
+ v2d->cur.xmax += dx;
+ }
+ if ((v2d->keepofs & V2D_LOCKOFS_Y) == 0) {
+ v2d->cur.ymin += dy;
+ v2d->cur.ymax += dy;
+ }
+
+ /* Inform v2d about changes after this operation. */
+ UI_view2d_curRect_changed(C, v2d);
+
+ /* Don't rebuild full tree in outliner, since we're just changing our view. */
+ ED_region_tag_redraw_no_rebuild(vpd->region);
+
+ /* Request updates to be done. */
+ WM_event_add_mousemove(CTX_wm_window(C));
+
+ UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY);
+}
+
+void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, int x, int y)
+{
+ ARegion *region = vpd->region;
+
+ rcti inside_rect, outside_rect;
+ inside_rect = region->winrct;
+ outside_rect = region->winrct;
+ BLI_rcti_pad(&inside_rect, -vpd->inside_pad * U.widget_unit, -vpd->inside_pad * U.widget_unit);
+ BLI_rcti_pad(&outside_rect, vpd->outside_pad * U.widget_unit, vpd->outside_pad * U.widget_unit);
+
+ int pan_dir_x = 0;
+ int pan_dir_y = 0;
+ if ((vpd->outside_pad == 0) || BLI_rcti_isect_pt(&outside_rect, x, y)) {
+ /* Find whether the mouse is beyond X and Y edges. */
+ if (x > inside_rect.xmax) {
+ pan_dir_x = 1;
+ }
+ else if (x < inside_rect.xmin) {
+ pan_dir_x = -1;
+ }
+ if (y > inside_rect.ymax) {
+ pan_dir_y = 1;
+ }
+ else if (y < inside_rect.ymin) {
+ pan_dir_y = -1;
+ }
+ }
+
+ const double current_time = PIL_check_seconds_timer();
+ edge_pan_manage_delay_timers(vpd, pan_dir_x, pan_dir_y, current_time);
+
+ /* Calculate the delta since the last time the operator was called. */
+ const float dtime = (float)(current_time - vpd->edge_pan_last_time);
+ float dx = 0.0f, dy = 0.0f;
+ if (pan_dir_x != 0) {
+ const float speed = edge_pan_speed(vpd, x, true, current_time);
+ dx = dtime * speed * (float)pan_dir_x;
+ }
+ if (pan_dir_y != 0) {
+ const float speed = edge_pan_speed(vpd, y, false, current_time);
+ dy = dtime * speed * (float)pan_dir_y;
+ }
+ vpd->edge_pan_last_time = current_time;
+
+ /* Pan, clamping inside the regions total bounds. */
+ edge_pan_apply_delta(C, vpd, dx, dy);
+}
+
+void UI_view2d_edge_pan_apply_event(bContext *C, View2DEdgePanData *vpd, const wmEvent *event)
+{
+ /* Only mouse-move events matter here, ignore others. */
+ if (event->type != MOUSEMOVE) {
+ return;
+ }
+
+ UI_view2d_edge_pan_apply(C, vpd, event->x, event->y);
+}
+
+void UI_view2d_edge_pan_operator_properties(wmOperatorType *ot)
+{
+ /* Default values for edge panning operators. */
+ UI_view2d_edge_pan_operator_properties_ex(ot,
+ /*inside_pad*/ 1.0f,
+ /*outside_pad*/ 0.0f,
+ /*speed_ramp*/ 1.0f,
+ /*max_speed*/ 500.0f,
+ /*delay*/ 1.0f);
+}
+
+void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
+ float inside_pad,
+ float outside_pad,
+ float speed_ramp,
+ float max_speed,
+ float delay)
+{
+ RNA_def_float(
+ ot->srna,
+ "inside_padding",
+ inside_pad,
+ 0.0f,
+ 100.0f,
+ "Inside Padding",
+ "Inside distance in UI units from the edge of the region within which to start panning",
+ 0.0f,
+ 100.0f);
+ RNA_def_float(
+ ot->srna,
+ "outside_padding",
+ outside_pad,
+ 0.0f,
+ 100.0f,
+ "Outside Padding",
+ "Outside distance in UI units from the edge of the region at which to stop panning",
+ 0.0f,
+ 100.0f);
+ RNA_def_float(ot->srna,
+ "speed_ramp",
+ speed_ramp,
+ 0.0f,
+ 100.0f,
+ "Speed Ramp",
+ "Width of the zone in UI units where speed increases with distance from the edge",
+ 0.0f,
+ 100.0f);
+ RNA_def_float(ot->srna,
+ "max_speed",
+ max_speed,
+ 0.0f,
+ 10000.0f,
+ "Max Speed",
+ "Maximum speed in UI units per second",
+ 0.0f,
+ 10000.0f);
+ RNA_def_float(ot->srna,
+ "delay",
+ delay,
+ 0.0f,
+ 10.0f,
+ "Delay",
+ "Delay in seconds before maximum speed is reached",
+ 0.0f,
+ 10.0f);
+}
+
+void UI_view2d_edge_pan_operator_init(bContext *C, View2DEdgePanData *vpd, wmOperator *op)
+{
+ UI_view2d_edge_pan_init(C,
+ vpd,
+ RNA_float_get(op->ptr, "inside_padding"),
+ RNA_float_get(op->ptr, "outside_padding"),
+ RNA_float_get(op->ptr, "speed_ramp"),
+ RNA_float_get(op->ptr, "max_speed"),
+ RNA_float_get(op->ptr, "delay"));
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 40c510af7e5..7ad28cd6069 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -341,162 +341,37 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
* passes through.
* \{ */
-/** Distance from the edge of the region within which to start panning. */
-#define EDGE_PAN_REGION_PAD (U.widget_unit)
-/** Speed factor in pixels per second per pixel of distance from edge pan zone beginning. */
-#define EDGE_PAN_SPEED_PER_PIXEL (25.0f * (float)U.dpi_fac)
-/** Delay before drag panning in seconds. */
-#define EDGE_PAN_DELAY 1.0f
-
/* set up modal operator and relevant settings */
static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- /* Set up customdata. */
- view_pan_init(C, op);
-
- v2dViewPanData *vpd = op->customdata;
-
- vpd->edge_pan_start_time_x = 0.0;
- vpd->edge_pan_start_time_y = 0.0;
- vpd->edge_pan_last_time = PIL_check_seconds_timer();
+ op->customdata = MEM_callocN(sizeof(View2DEdgePanData), "View2DEdgePanData");
+ View2DEdgePanData *vpd = op->customdata;
+ UI_view2d_edge_pan_operator_init(C, vpd, op);
WM_event_add_modal_handler(C, op);
return (OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH);
}
-/**
- * Reset the edge pan timers if the mouse isn't in the scroll zone and
- * start the timers when the mouse enters a scroll zone.
- */
-static void edge_pan_manage_delay_timers(v2dViewPanData *vpd,
- int pan_dir_x,
- int pan_dir_y,
- const double current_time)
-{
- if (pan_dir_x == 0) {
- vpd->edge_pan_start_time_x = 0.0;
- }
- else if (vpd->edge_pan_start_time_x == 0.0) {
- vpd->edge_pan_start_time_x = current_time;
- }
- if (pan_dir_y == 0) {
- vpd->edge_pan_start_time_y = 0.0;
- }
- else if (vpd->edge_pan_start_time_y == 0.0) {
- vpd->edge_pan_start_time_y = current_time;
- }
-}
-
-/**
- * Used to calculate a "fade in" factor for edge panning to make the interaction feel smooth
- * and more purposeful.
- *
- * \note Assumes a domain_min of 0.0f.
- */
-static float smootherstep(const float domain_max, float x)
-{
- x = clamp_f(x / domain_max, 0.0, 1.0);
- return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
-}
-
-static float edge_pan_speed(v2dViewPanData *vpd,
- int event_loc,
- bool x_dir,
- const double current_time)
-{
- ARegion *region = vpd->region;
-
- /* Find the distance from the start of the drag zone. */
- const int min = (x_dir ? region->winrct.xmin : region->winrct.ymin) + EDGE_PAN_REGION_PAD;
- const int max = (x_dir ? region->winrct.xmax : region->winrct.ymax) - EDGE_PAN_REGION_PAD;
- int distance = 0.0;
- if (event_loc > max) {
- distance = event_loc - max;
- }
- else if (event_loc < min) {
- distance = min - event_loc;
- }
- else {
- BLI_assert(!"Calculating speed outside of pan zones");
- return 0.0f;
- }
-
- /* Apply a fade in to the speed based on a start time delay. */
- const double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y;
- const float delay_factor = smootherstep(EDGE_PAN_DELAY, (float)(current_time - start_time));
-
- return distance * EDGE_PAN_SPEED_PER_PIXEL * delay_factor;
-}
-
static int view_edge_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- v2dViewPanData *vpd = op->customdata;
- ARegion *region = vpd->region;
+ View2DEdgePanData *vpd = op->customdata;
if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) {
- view_pan_exit(op);
+ MEM_SAFE_FREE(op->customdata);
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
- /* Only mousemove events matter here, ignore others. */
- if (event->type != MOUSEMOVE) {
- return OPERATOR_PASS_THROUGH;
- }
+
+ UI_view2d_edge_pan_apply_event(C, vpd, event);
/* This operator is supposed to run together with some drag action.
* On successful handling, always pass events on to other handlers. */
- const int success_retval = OPERATOR_PASS_THROUGH;
-
- const int outside_padding = RNA_int_get(op->ptr, "outside_padding") * UI_UNIT_X;
- rcti padding_rect;
- if (outside_padding != 0) {
- padding_rect = region->winrct;
- BLI_rcti_pad(&padding_rect, outside_padding, outside_padding);
- }
-
- int pan_dir_x = 0;
- int pan_dir_y = 0;
- if ((outside_padding == 0) || BLI_rcti_isect_pt(&padding_rect, event->x, event->y)) {
- /* Find whether the mouse is beyond X and Y edges. */
- if (event->x > region->winrct.xmax - EDGE_PAN_REGION_PAD) {
- pan_dir_x = 1;
- }
- else if (event->x < region->winrct.xmin + EDGE_PAN_REGION_PAD) {
- pan_dir_x = -1;
- }
- if (event->y > region->winrct.ymax - EDGE_PAN_REGION_PAD) {
- pan_dir_y = 1;
- }
- else if (event->y < region->winrct.ymin + EDGE_PAN_REGION_PAD) {
- pan_dir_y = -1;
- }
- }
-
- const double current_time = PIL_check_seconds_timer();
- edge_pan_manage_delay_timers(vpd, pan_dir_x, pan_dir_y, current_time);
-
- /* Calculate the delta since the last time the operator was called. */
- const float dtime = (float)(current_time - vpd->edge_pan_last_time);
- float dx = 0.0f, dy = 0.0f;
- if (pan_dir_x != 0) {
- const float speed = edge_pan_speed(vpd, event->x, true, current_time);
- dx = dtime * speed * (float)pan_dir_x;
- }
- if (pan_dir_y != 0) {
- const float speed = edge_pan_speed(vpd, event->y, false, current_time);
- dy = dtime * speed * (float)pan_dir_y;
- }
- vpd->edge_pan_last_time = current_time;
-
- /* Pan, clamping inside the regions's total bounds. */
- view_pan_apply_ex(C, vpd, dx, dy);
-
- return success_retval;
+ return OPERATOR_PASS_THROUGH;
}
static void view_edge_pan_cancel(bContext *UNUSED(C), wmOperator *op)
{
- view_pan_exit(op);
+ MEM_SAFE_FREE(op->customdata);
}
static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
@@ -510,26 +385,13 @@ static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
ot->invoke = view_edge_pan_invoke;
ot->modal = view_edge_pan_modal;
ot->cancel = view_edge_pan_cancel;
- ot->poll = view_pan_poll;
+ ot->poll = UI_view2d_edge_pan_poll;
/* operator is modal */
ot->flag = OPTYPE_INTERNAL;
- RNA_def_int(ot->srna,
- "outside_padding",
- 0,
- 0,
- 100,
- "Outside Padding",
- "Padding around the region in UI units within which panning is activated (0 to "
- "disable boundary)",
- 0,
- 100);
+ UI_view2d_edge_pan_operator_properties(ot);
}
-#undef EDGE_PAN_REGION_PAD
-#undef EDGE_PAN_SPEED_PER_PIXEL
-#undef EDGE_PAN_DELAY
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 81bf66da72c..4ce4a416796 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -291,7 +291,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
BLI_addtail(&shapes_tmp, mask_layer_shape_tmp);
}
- /* re-key, note: cant modify the keys here since it messes uop */
+ /* re-key, note: can't modify the keys here since it messes uop */
for (mask_layer_shape_tmp = shapes_tmp.first; mask_layer_shape_tmp;
mask_layer_shape_tmp = mask_layer_shape_tmp->next) {
BKE_mask_layer_evaluate(mask_layer, mask_layer_shape_tmp->frame, true);
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 18e231893d4..a64b90e15a3 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -95,7 +95,12 @@ static void make_prim_finish(bContext *C,
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
/* only recalc editmode tessface if we are staying in editmode */
- EDBM_update_generic(obedit->data, !exit_editmode, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = !exit_editmode,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
/* userdef */
if (exit_editmode) {
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index e7a99ca9e08..9efcf0963b4 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -357,7 +357,12 @@ static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op)
}
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
index 2bd5b9b26ca..35fff1f8f3a 100644
--- a/source/blender/editors/mesh/editmesh_automerge.c
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -76,7 +76,12 @@ void EDBM_automerge(Object *obedit, bool update, const char hflag, const float d
BMO_op_finish(bm, &weldop);
if ((totvert_prev != bm->totvert) && update) {
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
@@ -134,7 +139,12 @@ void EDBM_automerge_and_split(Object *obedit,
#endif
if (LIKELY(ok) && update) {
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 43492cd57af..110f1975d8d 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -403,9 +403,12 @@ static bool edbm_bevel_calc(wmOperator *op)
continue;
}
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
changed = true;
}
return changed;
@@ -454,7 +457,12 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op)
Object *obedit = opdata->ob_store[ob_index].ob;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, em, true);
- EDBM_update_generic(obedit->data, false, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
}
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index ea35d5a9e26..42cf36dda81 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -347,7 +347,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
BMOperator bmop_attr;
/* The fill normal sign is ignored as the face-winding is defined by surrounding faces.
- * The normal is passed so triangle fill wont have to calculate it. */
+ * The normal is passed so triangle fill won't have to calculate it. */
normalize_v3_v3(normal_fill, plane_no_local);
/* Fill */
@@ -383,7 +383,12 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
if (EDBM_op_finish(em, &bmop, op, true)) {
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
EDBM_selectmode_flush(em);
ret = OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index d5ddb7fc2c4..e03390780f9 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -319,9 +319,12 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", offset_local, BM_ELEM_SELECT);
}
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -448,11 +451,13 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
continue;
}
/* This normally happens when pushing undo but modal operators
- * like this one don't push undo data until after modal mode is
- * done.*/
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(obedit->data, true, true);
+ * like this one don't push undo data until after modal mode is done. */
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -502,13 +507,15 @@ static int edbm_extrude_context_exec(bContext *C, wmOperator *op)
}
edbm_extrude_mesh(obedit, em, op);
- /* This normally happens when pushing undo but modal operators
- * like this one don't push undo data until after modal mode is
- * done.*/
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(obedit->data, true, true);
+ /* This normally happens when pushing undo but modal operators
+ * like this one don't push undo data until after modal mode is done.*/
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -555,7 +562,12 @@ static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -603,7 +615,12 @@ static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -651,7 +668,12 @@ static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -884,11 +906,13 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
}
/* This normally happens when pushing undo but modal operators
- * like this one don't push undo data until after modal mode is
- * done. */
- EDBM_mesh_normals_update(vc.em);
-
- EDBM_update_generic(vc.obedit->data, true, true);
+ * like this one don't push undo data until after modal mode is done. */
+ EDBM_update(vc.obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c
index 4cffd12cb34..1ba6a0f42c6 100644
--- a/source/blender/editors/mesh/editmesh_extrude_screw.c
+++ b/source/blender/editors/mesh/editmesh_extrude_screw.c
@@ -155,7 +155,12 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index 187652ae00f..2146207308c 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -108,7 +108,12 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 73d79805f60..1c27ab00715 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -236,7 +236,12 @@ static void edbm_inset_cancel(bContext *C, wmOperator *op)
Object *obedit = opdata->ob_store[ob_index].ob;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, em, true);
- EDBM_update_generic(obedit->data, false, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
@@ -326,7 +331,12 @@ static bool edbm_inset_calc(wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
changed = true;
}
return changed;
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index d1f228e951a..f2691580a9d 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -116,8 +116,12 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec
}
}
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(me, true, true);
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
/* -------------------------------------------------------------------- */
@@ -963,8 +967,12 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
}
#endif
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
#ifdef USE_NET_ISLAND_CONNECT
/* we may have remaining isolated regions remaining,
@@ -1068,8 +1076,12 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BLI_ghash_free(face_edge_map, NULL, NULL);
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
BLI_stack_free(edges_loose);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index ae824cad50b..2ba1d30900a 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -272,8 +272,7 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
float v1[3], v2[3];
float planes[4][4];
- planes_from_projmat(
- (const float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL);
+ planes_from_projmat(kcd->projmat, planes[2], planes[0], planes[1], planes[3], NULL, NULL);
/* ray-cast all planes */
{
@@ -2805,8 +2804,12 @@ static void knifetool_finish_ex(KnifeTool_OpData *kcd)
knife_make_cuts(kcd);
EDBM_selectmode_flush(kcd->em);
- EDBM_mesh_normals_update(kcd->em);
- EDBM_update_generic(kcd->ob->data, true, true);
+ EDBM_update(kcd->ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
/* Re-tessellating makes this invalid, don't use again by accident. */
knifetool_free_bmbvh(kcd);
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 2057738221b..71319338a53 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -209,7 +209,12 @@ static void ringsel_finish(bContext *C, wmOperator *op)
/* when used in a macro the tessfaces will be recalculated anyway,
* this is needed here because modifiers depend on updated tessellation, see T45920 */
- EDBM_update_generic(lcd->ob->data, true, true);
+ EDBM_update(lcd->ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
if (is_single) {
/* de-select endpoints */
@@ -218,7 +223,7 @@ static void ringsel_finish(bContext *C, wmOperator *op)
EDBM_selectmode_flush_ex(lcd->em, SCE_SELECT_VERTEX);
}
- /* we cant slide multiple edges in vertex select mode */
+ /* we can't slide multiple edges in vertex select mode */
else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
}
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 7d849c096e7..993905462db 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -229,7 +229,7 @@ static int geometry_extract_apply(bContext *C,
/* Remove the mask from the new object so it can be sculpted directly after extracting. */
CustomData_free_layers(&new_ob_mesh->vdata, CD_PAINT_MASK, new_ob_mesh->totvert);
- BKE_mesh_copy_settings(new_ob_mesh, mesh);
+ BKE_mesh_copy_parameters_for_eval(new_ob_mesh, mesh);
if (params->apply_shrinkwrap) {
BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob);
@@ -567,7 +567,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
BKE_mesh_nomain_to_mesh(new_ob_mesh, new_ob->data, new_ob, &CD_MASK_MESH, true);
BKE_mesh_calc_normals(new_ob->data);
- BKE_mesh_copy_settings(new_ob->data, mesh);
+ BKE_mesh_copy_parameters_for_eval(new_ob->data, mesh);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index b7f671a4157..593545ddcef 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -270,7 +270,12 @@ static void mouse_mesh_shortest_path_vert(Scene *UNUSED(scene),
}
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
/** \} */
@@ -474,7 +479,12 @@ static void mouse_mesh_shortest_path_edge(Scene *scene,
}
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
if (op_params->edge_mode == EDGE_MODE_TAG_SEAM) {
ED_uvedit_live_unwrap(scene, &obedit, 1);
@@ -591,7 +601,12 @@ static void mouse_mesh_shortest_path_face(Scene *UNUSED(scene),
BM_mesh_active_face_set(bm, f_dst_last);
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 4d37b78c9b7..303cf41df0d 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -154,8 +154,12 @@ static int edbm_polybuild_transform_at_cursor_invoke(bContext *C,
BM_face_select_set(bm, (BMFace *)ele_act, true);
}
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(vc.obedit->data, true, true);
+ EDBM_update(vc.obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
@@ -237,8 +241,12 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
}
if (changed) {
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(vc.obedit->data, true, true);
+ EDBM_update(vc.obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
@@ -400,8 +408,12 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con
}
if (changed) {
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(vc.obedit->data, true, true);
+ EDBM_update(vc.obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
@@ -488,8 +500,12 @@ static int edbm_polybuild_split_at_cursor_invoke(bContext *C,
}
if (changed) {
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(vc.obedit->data, true, true);
+ EDBM_update(vc.obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
WM_event_add_mousemove(vc.win);
@@ -559,7 +575,7 @@ static int edbm_polybuild_dissolve_at_cursor_invoke(bContext *C,
else {
/* too involved to do inline */
- /* Avoid using selection so failure wont leave modified state. */
+ /* Avoid using selection so failure won't leave modified state. */
EDBM_flag_disable_all(em, BM_ELEM_TAG);
BM_elem_flag_enable(v_act, BM_ELEM_TAG);
@@ -578,8 +594,12 @@ static int edbm_polybuild_dissolve_at_cursor_invoke(bContext *C,
if (changed) {
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(vc.obedit->data, true, true);
+ EDBM_update(vc.obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 222d44f85d8..615590c51c6 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -170,15 +170,15 @@ static float edbm_rip_edge_side_measure(
*
* The method used for checking the side of selection is as follows...
* - First tag all rip-able edges.
- * - Build a contiguous edge list by looping over tagged edges and following each ones tagged
+ * - Build a contiguous edge list by looping over tagged edges and following each one's tagged
* siblings in both directions.
- * - The loops are not stored in an array, Instead both loops on either side of each edge has
- * its index values set to count down from the last edge, this way, once we have the 'last'
- * edge its very easy to walk down the connected edge loops.
- * The reason for using loops like this is because when the edges are split we don't which
- * face user gets the newly created edge
- * (its as good as random so we cant assume new edges will be on once side).
- * After splitting, its very simple to walk along boundary loops since each only has one edge
+ * - The loops are not stored in an array. Instead both loops on either side of each edge has
+ * its index values set to count down from the last edge. This way once we have the 'last'
+ * edge it's very easy to walk down the connected edge loops.
+ * The reason for using loops like this is because when the edges are split we don't know
+ * which face user gets the newly created edge
+ * (it's as good as random so we can't assume new edges will be on one side).
+ * After splitting, it's very simple to walk along boundary loops since each only has one edge
* from a single side.
* - The end loop pairs are stored in an array however to support multiple edge-selection-islands,
* so you can rip multiple selections at once.
@@ -189,7 +189,7 @@ static float edbm_rip_edge_side_measure(
*
* Limitation!
* This currently works very poorly with intersecting edge islands
- * (verts with more than 2 tagged edges). This is nice to but for now not essential.
+ * (verts with more than 2 tagged edges). This is nice to do but for now not essential.
*
* - campbell.
*/
@@ -639,7 +639,7 @@ static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obed
/* should we go ahead with edge rip or do we need to do special case, split off vertex?:
* split off vertex if...
- * - we cant find an edge - this means we are ripping a faces vert that is connected to other
+ * - we can't find an edge - this means we are ripping a faces vert that is connected to other
* geometry only at the vertex.
* - the boundary edge total is greater than 2,
* in this case edge split _can_ work but we get far nicer results if we use this special case.
@@ -1082,7 +1082,12 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
error_rip_failed = false;
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index 6775cb85ef9..f7e88284d93 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -223,7 +223,12 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
BM_mesh_select_mode_flush(bm);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 6cb103460f6..46abf71c4e2 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -547,8 +547,10 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenEdge(
- vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenEdge(vc,
+ find_nearest_edge_center__doZBuf,
+ &data,
+ V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
*r_dist_center_px_manhattan = data.dist;
}
@@ -601,7 +603,8 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc,
*dist_px_manhattan_p;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag);
+ mesh_foreachScreenEdge(
+ vc, find_nearest_edge__doClosest, &data, clip_flag | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
@@ -2568,7 +2571,7 @@ bool EDBM_selectmode_disable(Scene *scene,
const short selectmode_fallback)
{
/* note essential, but switch out of vertex mode since the
- * selected regions wont be nicely isolated after flushing */
+ * selected regions won't be nicely isolated after flushing */
if (em->selectmode & selectmode_disable) {
if (em->selectmode == selectmode_disable) {
em->selectmode = selectmode_fallback;
@@ -3639,8 +3642,9 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- const int object_index = RNA_int_get(op->ptr, "object_index");
- const int index = RNA_int_get(op->ptr, "index");
+ /* Intentionally wrap negative values so the lookup fails. */
+ const uint object_index = (uint)RNA_int_get(op->ptr, "object_index");
+ const uint index = (uint)RNA_int_get(op->ptr, "index");
ele = EDBM_elem_from_index_any_multi(view_layer, object_index, index, &obedit);
}
@@ -4270,7 +4274,12 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
if (edbm_deselect_nth(em, &op_params) == true) {
found_active_elt = true;
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index f3c0da67ecc..2ffeaa06751 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -497,7 +497,12 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
if (changed) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(ob->data, false, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
@@ -519,7 +524,12 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
}
}
EDBM_selectmode_flush(em);
- EDBM_update_generic(ob->data, false, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
@@ -917,7 +927,12 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
if (changed) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(ob->data, false, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
@@ -939,7 +954,12 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
}
}
EDBM_selectmode_flush(em);
- EDBM_update_generic(ob->data, false, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
@@ -1213,7 +1233,12 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
if (changed) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(ob->data, false, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index bb332a4094c..c09ce126b7f 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -132,7 +132,12 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
false,
seed);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -324,7 +329,12 @@ static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -384,7 +394,12 @@ static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
}
EDBM_selectmode_flush(em);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -499,7 +514,12 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -628,7 +648,12 @@ static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
int totelem_new[3];
@@ -686,7 +711,12 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -954,7 +984,7 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
* copying face data from surrounding, may have copied hidden face flag too.
*
* Important that faces use flushing since 'edges.out'
- * wont include hidden edges that already existed.
+ * won't include hidden edges that already existed.
*/
BMO_slot_buffer_hflag_disable(
em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
@@ -971,7 +1001,12 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
changed_multi = true;
}
MEM_freeN(objects);
@@ -1047,7 +1082,12 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -1117,7 +1157,12 @@ static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear);
}
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -1239,7 +1284,12 @@ static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *
BM_custom_loop_normals_from_vector_layer(bm, false);
- EDBM_update_generic(me, true, true);
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
MEM_freeN(verts);
@@ -1538,7 +1588,12 @@ static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
else {
failed_selection_order_len++;
@@ -1603,7 +1658,12 @@ static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
em, op, "faces.out", true, "connect_verts_concave faces=%hf", BM_ELEM_SELECT)) {
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -1657,7 +1717,12 @@ static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -1726,7 +1791,12 @@ static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -1775,7 +1845,12 @@ static bool edbm_edge_split_selected_edges(wmOperator *op, Object *obedit, BMEdi
BM_custom_loop_normals_from_vector_layer(em->bm, false);
EDBM_select_flush(em);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
return true;
}
@@ -1845,7 +1920,12 @@ static bool edbm_edge_split_selected_verts(wmOperator *op, Object *obedit, BMEdi
BM_custom_loop_normals_from_vector_layer(em->bm, false);
EDBM_select_flush(em);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
return true;
}
@@ -1958,7 +2038,12 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
if (!EDBM_op_finish(em, &bmop, op, true)) {
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -2114,7 +2199,12 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
lnor_ed->clnors_data);
}
BM_loop_normal_editdata_array_free(lnors_ed_arr);
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
continue;
}
@@ -2133,7 +2223,12 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
}
if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) {
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
if (lnors_ed_arr != NULL) {
@@ -2255,7 +2350,12 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -2341,7 +2441,12 @@ static int edbm_hide_exec(bContext *C, wmOperator *op)
}
if (EDBM_mesh_hide(em, unselected)) {
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
changed = true;
}
}
@@ -2392,7 +2497,12 @@ static int edbm_reveal_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (EDBM_mesh_reveal(em, select)) {
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
}
MEM_freeN(objects);
@@ -2458,7 +2568,12 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
}
}
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2570,7 +2685,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
EDBM_verts_mirror_cache_end(em);
}
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2694,7 +2814,12 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
EDBM_verts_mirror_cache_end(em);
}
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2787,7 +2912,12 @@ static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
}
mesh_set_smooth_faces(em, 1);
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2830,7 +2960,12 @@ static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
}
mesh_set_smooth_faces(em, 0);
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2887,7 +3022,12 @@ static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2920,7 +3060,12 @@ static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
if (!EDBM_op_finish(em, &bmop, op, true)) {
continue;
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2958,7 +3103,12 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
}
/* dependencies graph and notification stuff */
- EDBM_update_generic(ob->data, false, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -2994,7 +3144,12 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -3243,7 +3398,12 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
/* once collapsed, we can't have edge/face selection */
if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
@@ -3422,7 +3582,12 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
if (count) {
count_multi += count;
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
MEM_freeN(objects);
@@ -3522,7 +3687,12 @@ static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
tot_shapekeys++;
}
- EDBM_update_generic(me, false, false);
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -3644,7 +3814,12 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
interp_v3_v3v3(eve->co, eve->co, co, blend);
}
}
- EDBM_update_generic(me, true, false);
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = false,
+ });
}
}
MEM_freeN(objects);
@@ -3781,7 +3956,12 @@ static int edbm_solidify_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -4072,7 +4252,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)];
const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)];
- /* check for error value (vert cant be projected) */
+ /* check for error value (vert can't be projected) */
if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) {
isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected);
@@ -4113,7 +4293,12 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
return OPERATOR_FINISHED;
}
@@ -4516,7 +4701,12 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
if (retval) {
- EDBM_update_generic(base->object->data, true, true);
+ EDBM_update(base->object->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
}
MEM_freeN(bases);
@@ -4664,7 +4854,12 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -4958,7 +5153,12 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5030,7 +5230,12 @@ static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5113,7 +5318,12 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5197,9 +5407,12 @@ static int edbm_poke_face_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5301,7 +5514,12 @@ static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5413,7 +5631,12 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5597,7 +5820,12 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op)
}
EDBM_selectmode_flush_ex(em, selectmode);
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5736,7 +5964,12 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5797,7 +6030,12 @@ static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -5858,7 +6096,12 @@ static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -6003,7 +6246,12 @@ static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
BM_custom_loop_normals_from_vector_layer(em->bm, false);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -6090,7 +6338,12 @@ static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
/* tricky to maintain correct selection here, so just flush up from verts */
EDBM_select_flush(em);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
totelem_new[0] += bm->totvert;
totelem_new[1] += bm->totedge;
@@ -6181,7 +6434,12 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -6242,10 +6500,13 @@ static int edbm_split_exec(bContext *C, wmOperator *op)
continue;
}
- /* Geometry has changed, need to recalc normals and looptris */
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(obedit->data, true, true);
+ /* Geometry has changed, need to recalculate normals and tessellation. */
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -7085,7 +7346,12 @@ static int edbm_bridge_edge_loops_for_single_editmesh(wmOperator *op,
}
if (EDBM_op_finish(em, &bmop, op, true)) {
- EDBM_update_generic(me, true, true);
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
/* Always return finished so the user can select different options. */
@@ -7220,7 +7486,12 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
}
MEM_freeN(objects);
@@ -7311,7 +7582,12 @@ static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
if (EDBM_op_finish(em, &bmop, op, true)) {
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
changed_multi = true;
}
}
@@ -7441,7 +7717,12 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
EDBM_selectmode_flush(em);
}
@@ -7529,7 +7810,12 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
if (!EDBM_op_finish(em, &bmop, op, true)) {
continue;
}
- EDBM_update_generic(obedit->data, true, true);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = true,
+ });
EDBM_selectmode_flush(em);
}
MEM_freeN(objects);
@@ -7671,7 +7957,12 @@ static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
}
}
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
/* No need to end cache, just free the array. */
MEM_freeN(index);
@@ -8347,7 +8638,12 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *
if (point_normals_ensure(C, op)) {
point_normals_apply(C, op, target, do_reset);
- EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ }); /* Recheck bools. */
point_normals_update_header(C, op);
}
else {
@@ -8404,7 +8700,12 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op)
point_normals_apply(C, op, target, false);
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
point_normals_cancel(C, op);
return OPERATOR_FINISHED;
@@ -8663,7 +8964,12 @@ static int normals_split_merge(bContext *C, const bool do_merge)
BM_loop_normal_editdata_array_free(lnors_ed_arr);
}
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -8875,7 +9181,12 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
} while ((l_curr = l_curr->next) != l_first);
}
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
BLI_heapsimple_free(loop_weight, NULL);
@@ -9126,7 +9437,12 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
BM_loop_normal_editdata_array_free(lnors_ed_arr);
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -9280,7 +9596,12 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
MEM_freeN(loop_set);
MEM_freeN(vnors);
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -9388,7 +9709,12 @@ static int edbm_smooth_normals_exec(bContext *C, wmOperator *op)
BM_loop_normal_editdata_array_free(lnors_ed_arr);
MEM_freeN(smooth_normal);
- EDBM_update_generic(obedit->data, true, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
@@ -9477,7 +9803,12 @@ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op)
}
}
- EDBM_update_generic(obedit->data, false, false);
+ EDBM_update(obedit->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = false,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 274f4cdbb6c..112de68b52c 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -626,7 +626,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key, Undo
# ifdef USE_ARRAY_STORE_THREAD
if (um_arraystore.task_pool == NULL) {
- um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW, true);
+ um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW);
}
struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 19c9909039c..9c97bdd6fde 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -438,7 +438,7 @@ void EDBM_selectmode_to_scene(bContext *C)
void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
{
- BM_mesh_select_mode_flush_ex(em->bm, selectmode);
+ BM_mesh_select_mode_flush_ex(em->bm, selectmode, BM_SELECT_LEN_FLUSH_RECALC_ALL);
}
void EDBM_selectmode_flush(BMEditMesh *em)
@@ -1222,12 +1222,12 @@ BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
{
- BMVert *v1_mirr = EDBM_verts_mirror_get(em, e->v1);
- if (v1_mirr) {
- BMVert *v2_mirr = EDBM_verts_mirror_get(em, e->v2);
- if (v2_mirr) {
- return BM_edge_exists(v1_mirr, v2_mirr);
- }
+ BMVert *v1_mirr, *v2_mirr;
+ if ((v1_mirr = EDBM_verts_mirror_get(em, e->v1)) &&
+ (v2_mirr = EDBM_verts_mirror_get(em, e->v2)) &&
+ /* While highly unlikely, a zero length central edges vertices can match, see T89342. */
+ LIKELY(v1_mirr != v2_mirr)) {
+ return BM_edge_exists(v1_mirr, v2_mirr);
}
return NULL;
@@ -1405,9 +1405,17 @@ bool EDBM_mesh_reveal(BMEditMesh *em, bool select)
/** \name Update API
* \{ */
+void EDBM_mesh_normals_update_ex(BMEditMesh *em, const struct BMeshNormalsUpdate_Params *params)
+{
+ BM_mesh_normals_update_ex(em->bm, params);
+}
+
void EDBM_mesh_normals_update(BMEditMesh *em)
{
- BM_mesh_normals_update(em->bm);
+ EDBM_mesh_normals_update_ex(em,
+ &(const struct BMeshNormalsUpdate_Params){
+ .face_normals = true,
+ });
}
void EDBM_stats_update(BMEditMesh *em)
@@ -1439,20 +1447,31 @@ void EDBM_stats_update(BMEditMesh *em)
}
}
-/* so many tools call these that we better make it a generic function.
+/**
+ * So many tools call these that we better make it a generic function.
*/
-void EDBM_update_generic(Mesh *mesh, const bool do_tessellation, const bool is_destructive)
+void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
{
BMEditMesh *em = mesh->edit_mesh;
/* Order of calling isn't important. */
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
- if (do_tessellation) {
- BKE_editmesh_looptri_calc(em);
+ if (params->calc_normals && params->calc_looptri) {
+ /* Calculating both has some performance gains. */
+ BKE_editmesh_looptri_and_normals_calc(em);
}
+ else {
+ if (params->calc_normals) {
+ EDBM_mesh_normals_update(em);
+ }
- if (is_destructive) {
+ if (params->calc_looptri) {
+ BKE_editmesh_looptri_calc(em);
+ }
+ }
+
+ if (params->is_destructive) {
/* TODO. we may be able to remove this now! - Campbell */
// BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP);
}
@@ -1477,6 +1496,17 @@ void EDBM_update_generic(Mesh *mesh, const bool do_tessellation, const bool is_d
#endif
}
+/* Bad level call from Python API. */
+void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
+{
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = do_tessellation,
+ .calc_normals = false,
+ .is_destructive = is_destructive,
+ });
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1544,7 +1574,7 @@ int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
return index;
}
-BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index)
+BMElem *EDBM_elem_from_index_any(BMEditMesh *em, uint index)
{
BMesh *bm = em->bm;
@@ -1585,14 +1615,14 @@ int EDBM_elem_to_index_any_multi(ViewLayer *view_layer,
}
BMElem *EDBM_elem_from_index_any_multi(ViewLayer *view_layer,
- int object_index,
- int elem_index,
+ uint object_index,
+ uint elem_index,
Object **r_obedit)
{
uint bases_len;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, NULL, &bases_len);
*r_obedit = NULL;
- Object *obedit = ((uint)object_index < bases_len) ? bases[object_index]->object : NULL;
+ Object *obedit = (object_index < bases_len) ? bases[object_index]->object : NULL;
MEM_freeN(bases);
if (obedit != NULL) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 763bdf04d83..9e2e2786347 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -77,15 +77,15 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
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);
+struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, uint index);
int EDBM_elem_to_index_any_multi(struct ViewLayer *view_layer,
struct BMEditMesh *em,
struct BMElem *ele,
int *r_object_index);
struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer,
- int object_index,
- int elem_index,
+ uint object_index,
+ uint elem_index,
struct Object **r_obedit);
bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
index 0f746dfd3a0..25d3eaf11d4 100644
--- a/source/blender/editors/mesh/mesh_mirror.c
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -309,7 +309,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
last = 0;
/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
- * but you cant ever access the last 'a' index of MirrTopoPairs */
+ * but you can't ever access the last 'a' index of MirrTopoPairs */
if (em) {
BMVert **vtable = em->bm->vtable;
for (a = 1; a <= totvert; a++) {
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 3450d61337c..f306612f295 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -149,7 +149,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
mul_m4_m4m4(cmat, imat, ob_src->obmat);
/* transform vertex coordinates into new space */
- for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, mvert++) {
+ for (a = 0; a < me->totvert; a++, mvert++) {
mul_m4_v3(cmat, mvert->co);
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 12aaa9c2d9f..b677a2f96c3 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -456,49 +456,53 @@ void ED_object_add_mesh_props(wmOperatorType *ot)
bool ED_object_add_generic_get_opts(bContext *C,
wmOperator *op,
const char view_align_axis,
- float loc[3],
- float rot[3],
- float scale[3],
- bool *enter_editmode,
- ushort *local_view_bits,
- bool *is_view_aligned)
-{
- PropertyRNA *prop;
-
- /* Switch to Edit mode? optional prop */
- if ((prop = RNA_struct_find_property(op->ptr, "enter_editmode"))) {
+ float r_loc[3],
+ float r_rot[3],
+ float r_scale[3],
+ bool *r_enter_editmode,
+ ushort *r_local_view_bits,
+ bool *r_is_view_aligned)
+{
+ /* Edit Mode! (optional) */
+ {
bool _enter_editmode;
- if (!enter_editmode) {
- enter_editmode = &_enter_editmode;
+ if (!r_enter_editmode) {
+ r_enter_editmode = &_enter_editmode;
}
+ /* Only to ensure the value is _always_ set.
+ * Typically the property will exist when the argument is non-NULL. */
+ *r_enter_editmode = false;
- if (RNA_property_is_set(op->ptr, prop) && enter_editmode) {
- *enter_editmode = RNA_property_boolean_get(op->ptr, prop);
- }
- else {
- *enter_editmode = (U.flag & USER_ADD_EDITMODE) != 0;
- RNA_property_boolean_set(op->ptr, prop, *enter_editmode);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "enter_editmode");
+ if (prop != NULL) {
+ if (RNA_property_is_set(op->ptr, prop) && r_enter_editmode) {
+ *r_enter_editmode = RNA_property_boolean_get(op->ptr, prop);
+ }
+ else {
+ *r_enter_editmode = (U.flag & USER_ADD_EDITMODE) != 0;
+ RNA_property_boolean_set(op->ptr, prop, *r_enter_editmode);
+ }
}
}
- if (local_view_bits) {
+ if (r_local_view_bits) {
View3D *v3d = CTX_wm_view3d(C);
- *local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
+ *r_local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
}
/* Location! */
{
float _loc[3];
- if (!loc) {
- loc = _loc;
+ if (!r_loc) {
+ r_loc = _loc;
}
if (RNA_struct_property_is_set(op->ptr, "location")) {
- RNA_float_get_array(op->ptr, "location", loc);
+ RNA_float_get_array(op->ptr, "location", r_loc);
}
else {
- ED_object_location_from_view(C, loc);
- RNA_float_set_array(op->ptr, "location", loc);
+ ED_object_location_from_view(C, r_loc);
+ RNA_float_set_array(op->ptr, "location", r_loc);
}
}
@@ -506,33 +510,33 @@ bool ED_object_add_generic_get_opts(bContext *C,
{
bool _is_view_aligned;
float _rot[3];
- if (!is_view_aligned) {
- is_view_aligned = &_is_view_aligned;
+ if (!r_is_view_aligned) {
+ r_is_view_aligned = &_is_view_aligned;
}
- if (!rot) {
- rot = _rot;
+ if (!r_rot) {
+ r_rot = _rot;
}
if (RNA_struct_property_is_set(op->ptr, "rotation")) {
/* If rotation is set, always use it. Alignment (and corresponding user preference)
* can be ignored since this is in world space anyways.
* To not confuse (e.g. on redo), don't set it to #ALIGN_WORLD in the op UI though. */
- *is_view_aligned = false;
- RNA_float_get_array(op->ptr, "rotation", rot);
+ *r_is_view_aligned = false;
+ RNA_float_get_array(op->ptr, "rotation", r_rot);
}
else {
int alignment = ALIGN_WORLD;
- prop = RNA_struct_find_property(op->ptr, "align");
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "align");
if (RNA_property_is_set(op->ptr, prop)) {
/* If alignment is set, always use it. */
- *is_view_aligned = alignment == ALIGN_VIEW;
+ *r_is_view_aligned = alignment == ALIGN_VIEW;
alignment = RNA_property_enum_get(op->ptr, prop);
}
else {
/* If alignment is not set, use User Preferences. */
- *is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0;
- if (*is_view_aligned) {
+ *r_is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0;
+ if (*r_is_view_aligned) {
RNA_property_enum_set(op->ptr, prop, ALIGN_VIEW);
alignment = ALIGN_VIEW;
}
@@ -547,18 +551,18 @@ bool ED_object_add_generic_get_opts(bContext *C,
}
switch (alignment) {
case ALIGN_WORLD:
- RNA_float_get_array(op->ptr, "rotation", rot);
+ RNA_float_get_array(op->ptr, "rotation", r_rot);
break;
case ALIGN_VIEW:
- ED_object_rotation_from_view(C, rot, view_align_axis);
- RNA_float_set_array(op->ptr, "rotation", rot);
+ ED_object_rotation_from_view(C, r_rot, view_align_axis);
+ RNA_float_set_array(op->ptr, "rotation", r_rot);
break;
case ALIGN_CURSOR: {
const Scene *scene = CTX_data_scene(C);
float tmat[3][3];
BKE_scene_cursor_rot_to_mat3(&scene->cursor, tmat);
- mat3_normalized_to_eul(rot, tmat);
- RNA_float_set_array(op->ptr, "rotation", rot);
+ mat3_normalized_to_eul(r_rot, tmat);
+ RNA_float_set_array(op->ptr, "rotation", r_rot);
break;
}
}
@@ -568,19 +572,21 @@ bool ED_object_add_generic_get_opts(bContext *C,
/* Scale! */
{
float _scale[3];
- if (!scale) {
- scale = _scale;
+ if (!r_scale) {
+ r_scale = _scale;
}
/* For now this is optional, we can make it always use. */
- copy_v3_fl(scale, 1.0f);
- if ((prop = RNA_struct_find_property(op->ptr, "scale"))) {
+ copy_v3_fl(r_scale, 1.0f);
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "scale");
+ if (prop != NULL) {
if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_get_array(op->ptr, prop, scale);
+ RNA_property_float_get_array(op->ptr, prop, r_scale);
}
else {
- copy_v3_fl(scale, 1.0f);
- RNA_property_float_set_array(op->ptr, prop, scale);
+ copy_v3_fl(r_scale, 1.0f);
+ RNA_property_float_set_array(op->ptr, prop, r_scale);
}
}
}
@@ -2642,10 +2648,10 @@ static Base *duplibase_for_convert(
ED_object_base_select(basen, BA_SELECT);
ED_object_base_select(base, BA_DESELECT);
- /* XXX An ugly hack needed because if we re-run depsgraph with some new MBall objects
- * having same 'family name' as orig ones, they will affect end result of MBall computation...
+ /* XXX: An ugly hack needed because if we re-run depsgraph with some new meta-ball objects
+ * having same 'family name' as orig ones, they will affect end result of meta-ball computation.
* For until we get rid of that name-based thingy in MBalls, that should do the trick
- * (this is weak, but other solution (to change name of obn) is even worse imho).
+ * (this is weak, but other solution (to change name of `obn`) is even worse imho).
* See T65996. */
const bool is_meta_ball = (obn->type == OB_MBALL);
void *obdata = obn->data;
@@ -3462,6 +3468,19 @@ void OBJECT_OT_duplicate(wmOperatorType *ot)
* Use for drag & drop.
* \{ */
+static Base *object_add_ensure_in_view_layer(Main *bmain, ViewLayer *view_layer, Object *ob)
+{
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (!base) {
+ LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ }
+
+ return base;
+}
+
static int object_add_named_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -3469,7 +3488,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Base *basen;
Object *ob;
- const bool linked = RNA_boolean_get(op->ptr, "linked");
+ const bool duplicate = RNA_boolean_get(op->ptr, "duplicate");
+ const bool linked = duplicate && RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag;
char name[MAX_ID_NAME - 2];
@@ -3483,20 +3503,30 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
/* prepare dupli */
- basen = object_add_duplicate_internal(
- bmain,
- scene,
- view_layer,
- ob,
- dupflag,
- /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
- * function will only work if the object is already linked in the view layer, which is not
- * the case here. So we have to do the new-ID relinking ourselves (#copy_object_set_idnew()).
- */
- LIB_ID_DUPLICATE_IS_SUBPROCESS);
+ if (duplicate) {
+ basen = object_add_duplicate_internal(
+ bmain,
+ scene,
+ view_layer,
+ ob,
+ dupflag,
+ /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
+ * function will only work if the object is already linked in the view layer, which is not
+ * the case here. So we have to do the new-ID relinking ourselves
+ * (#copy_object_set_idnew()).
+ */
+ LIB_ID_DUPLICATE_IS_SUBPROCESS);
+ }
+ else {
+ /* basen is actually not a new base in this case. */
+ basen = object_add_ensure_in_view_layer(bmain, view_layer, ob);
+ }
if (basen == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
+ BKE_report(op->reports,
+ RPT_ERROR,
+ duplicate ? "Object could not be duplicated" :
+ "Object could not be linked to the view layer");
return OPERATOR_CANCELLED;
}
@@ -3543,11 +3573,24 @@ void OBJECT_OT_add_named(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "duplicate",
+ true,
+ "Duplicate",
+ "Create a duplicate of the object. If not set, only ensures the object is linked into the "
+ "active view layer, positions and selects/activates it (deselecting others)");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
RNA_def_boolean(ot->srna,
"linked",
- 0,
+ false,
"Linked",
- "Duplicate object but not object data, linking to the original data");
+ "Duplicate object but not object data, linking to the original data (ignored if "
+ "'duplicate' is false)");
+
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add");
object_add_drop_xy_props(ot);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 3370476d466..7f26d44a4ed 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -158,7 +158,7 @@ static int bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
/**
* for exec() when there is no render job
- * note: this wont check for the escape key being pressed, but doing so isn't thread-safe.
+ * note: this won't check for the escape key being pressed, but doing so isn't thread-safe.
*/
static int bake_break(void *UNUSED(rjv))
{
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 244124a6e0a..06d6f2b94f3 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -696,12 +696,11 @@ static bool edit_constraint_poll_generic(bContext *C,
Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
bConstraint *con = ptr.data;
- if (!ob) {
- CTX_wm_operator_poll_msg_set(C, "Context missing active object");
+ if (!ED_operator_object_active_editable_ex(C, ob)) {
return false;
}
- if (ID_IS_LINKED(ob) || (ptr.owner_id && ID_IS_LINKED(ptr.owner_id))) {
+ if (ptr.owner_id != NULL && ID_IS_LINKED(ptr.owner_id)) {
CTX_wm_operator_poll_msg_set(C, "Cannot edit library data");
return false;
}
@@ -1746,8 +1745,8 @@ void POSE_OT_constraints_clear(wmOperatorType *ot)
/* callbacks */
ot->exec = pose_constraints_clear_exec;
- ot->poll = ED_operator_posemode_exclusive; /* XXX - do we want to ensure there are selected
- * bones too? */
+ /* XXX - do we want to ensure there are selected bones too? */
+ ot->poll = ED_operator_object_active_local_editable_posemode_exclusive;
}
static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2480,7 +2479,7 @@ void POSE_OT_ik_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = pose_ik_clear_exec;
- ot->poll = ED_operator_posemode_exclusive;
+ ot->poll = ED_operator_object_active_local_editable_posemode_exclusive;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
index 6e3a5e715f6..4a4ace309e1 100644
--- a/source/blender/editors/object/object_data_transform.c
+++ b/source/blender/editors/object/object_data_transform.c
@@ -745,8 +745,12 @@ void ED_object_data_xform_tag_update(struct XFormObjectData *xod_base)
case ID_ME: {
Mesh *me = (Mesh *)xod_base->id;
if (xod_base->is_edit_mode) {
- EDBM_update_generic(me, true, false);
- EDBM_mesh_normals_update(me->edit_mesh);
+ EDBM_update(me,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = true,
+ .is_destructive = false,
+ });
}
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
break;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 5be572baec5..c8923bb55c1 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -794,9 +794,7 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
BMEditMesh *em = BKE_editmesh_from_object(ob);
if (LIKELY(em)) {
- /* order doesn't matter */
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
+ BKE_editmesh_looptri_and_normals_calc(em);
}
WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL);
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index d56ee17a73f..7122fd09892 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -350,8 +350,7 @@ static bool object_hook_index_array(Main *bmain,
em = me->edit_mesh;
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
+ BKE_editmesh_looptri_and_normals_calc(em);
/* check selected vertices first */
if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) {
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 3d1a5ac2d62..ed06cd2a217 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -484,7 +484,9 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
ob_dst_orig = DEG_get_original_object(ob_dst);
ED_object_mode_set_ex(C, last_mode, true, op->reports);
- object_overlay_mode_transfer_animation_start(C, ob_dst);
+ if (RNA_boolean_get(op->ptr, "use_flash_on_transfer")) {
+ object_overlay_mode_transfer_animation_start(C, ob_dst);
+ }
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_toolsystem_update_from_context_view3d(C);
@@ -578,6 +580,12 @@ void OBJECT_OT_transfer_mode(wmOperatorType *ot)
false,
"Use Eyedropper",
"Pick the object to switch to using an eyedropper");
+
+ RNA_def_boolean(ot->srna,
+ "use_flash_on_transfer",
+ true,
+ "Flash On Transfer",
+ "Flash the target object when transfering the mode");
}
/** \} */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index f3433833b5f..cdf12bcb5df 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -153,8 +153,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
em = me->edit_mesh;
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
+ BKE_editmesh_looptri_and_normals_calc(em);
/* Make sure the evaluated mesh is updated.
*
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 1ff576504ce..c04c91d21b5 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -139,6 +139,13 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (mesh->totpoly == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Output mesh will be all smooth or all flat shading. */
+ const bool smooth_normals = mesh->mpoly[0].flag & ME_SMOOTH;
+
float isovalue = 0.0f;
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
isovalue = mesh->remesh_voxel_size * 0.3f;
@@ -185,7 +192,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
- if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
+ if (smooth_normals) {
BKE_mesh_smooth_flag_set(ob->data, true);
}
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index 585a1e22a84..2723d7ad1e3 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -64,7 +64,9 @@
#include "object_intern.h"
-/******************************** API ****************************/
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
ShaderFxData *ED_object_shaderfx_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
@@ -261,7 +263,59 @@ void ED_object_shaderfx_copy(Object *dst, ShaderFxData *fx)
WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, dst);
}
-/************************ add effect operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Poll Callback Helpers
+ * \{ */
+
+static bool edit_shaderfx_poll_generic(bContext *C,
+ StructRNA *rna_type,
+ int obtype_flag,
+ const bool is_liboverride_allowed)
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type);
+ Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
+ ShaderFxData *fx = ptr.data; /* May be NULL. */
+
+ if (!ED_operator_object_active_editable_ex(C, ob)) {
+ return false;
+ }
+
+ /* NOTE: Temporary 'forbid all' for overrides, until we implement support to add shaderfx to
+ * overrides. */
+ if (ID_IS_OVERRIDE_LIBRARY(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs in a library override");
+ return false;
+ }
+
+ if (obtype_flag != 0 && ((1 << ob->type) & obtype_flag) == 0) {
+ CTX_wm_operator_poll_msg_set(C, "Object type is not supported");
+ return false;
+ }
+ if (ptr.owner_id != NULL && ID_IS_LINKED(ptr.owner_id)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit library data");
+ return false;
+ }
+ if (!is_liboverride_allowed && BKE_shaderfx_is_nonlocal_in_liboverride(ob, fx)) {
+ CTX_wm_operator_poll_msg_set(
+ C, "Cannot edit shaderfxs coming from linked data in a library override");
+ return false;
+ }
+
+ return true;
+}
+
+static bool edit_shaderfx_poll(bContext *C)
+{
+ return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0, false);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Effect Operator
+ * \{ */
static int shaderfx_add_exec(bContext *C, wmOperator *op)
{
@@ -334,7 +388,7 @@ void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = shaderfx_add_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = edit_shaderfx_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -352,37 +406,6 @@ void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
/** \name Generic Functions for Operators Using Names and Data Context
* \{ */
-static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type);
- Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
- ShaderFxData *fx = ptr.data; /* May be NULL. */
-
- if (!ob || ID_IS_LINKED(ob)) {
- return false;
- }
- if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) {
- return false;
- }
- if (ptr.owner_id && ID_IS_LINKED(ptr.owner_id)) {
- return false;
- }
-
- if (ID_IS_OVERRIDE_LIBRARY(ob)) {
- if ((fx == NULL) || (fx->flag & eShaderFxFlag_OverrideLibrary_Local) == 0) {
- CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from library override");
- return false;
- }
- }
-
- return true;
-}
-
-static bool edit_shaderfx_poll(bContext *C)
-{
- return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0);
-}
-
static void edit_shaderfx_properties(wmOperatorType *ot)
{
PropertyRNA *prop = RNA_def_string(
@@ -461,7 +484,9 @@ static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int
/** \} */
-/************************ remove shaderfx operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Remove ShaderFX Operator
+ * \{ */
static int shaderfx_remove_exec(bContext *C, wmOperator *op)
{
@@ -511,7 +536,11 @@ void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
edit_shaderfx_report_property(ot);
}
-/************************ move up shaderfx operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Move up ShaderFX Operator
+ * \{ */
static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
{
@@ -552,7 +581,11 @@ void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
edit_shaderfx_properties(ot);
}
-/************************ move down shaderfx operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Move Down ShaderFX Operator
+ * \{ */
static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
{
@@ -593,12 +626,11 @@ void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
edit_shaderfx_properties(ot);
}
-/************************ move shaderfx to index operator *********************/
+/** \} */
-static bool shaderfx_move_to_index_poll(bContext *C)
-{
- return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0);
-}
+/* -------------------------------------------------------------------- */
+/** \name Move ShaderFX to Index Operator
+ * \{ */
static int shaderfx_move_to_index_exec(bContext *C, wmOperator *op)
{
@@ -632,7 +664,7 @@ void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot)
ot->invoke = shaderfx_move_to_index_invoke;
ot->exec = shaderfx_move_to_index_exec;
- ot->poll = shaderfx_move_to_index_poll;
+ ot->poll = edit_shaderfx_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -641,7 +673,11 @@ void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot)
ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the effect to", 0, INT_MAX);
}
-/************************ copy shader operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy Shader Operator
+ * \{ */
static int shaderfx_copy_exec(bContext *C, wmOperator *op)
{
@@ -675,11 +711,6 @@ static int shaderfx_copy_invoke(bContext *C, wmOperator *op, const wmEvent *even
return retval;
}
-static bool shaderfx_copy_poll(bContext *C)
-{
- return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0);
-}
-
void OBJECT_OT_shaderfx_copy(wmOperatorType *ot)
{
ot->name = "Copy Effect";
@@ -688,9 +719,11 @@ void OBJECT_OT_shaderfx_copy(wmOperatorType *ot)
ot->invoke = shaderfx_copy_invoke;
ot->exec = shaderfx_copy_exec;
- ot->poll = shaderfx_copy_poll;
+ ot->poll = edit_shaderfx_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_shaderfx_properties(ot);
}
+
+/** \} */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index b9a3bc87e19..94b2f3fd566 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1615,6 +1615,7 @@ struct XFormAxisItem {
struct XFormAxisData {
ViewContext vc;
+ ViewDepths *depths;
struct {
float depth;
float normal[3];
@@ -1684,8 +1685,8 @@ static void object_transform_axis_target_free_data(wmOperator *op)
struct XFormAxisItem *item = xfd->object_data;
#ifdef USE_RENDER_OVERRIDE
- if (xfd->vc.rv3d->depths) {
- xfd->vc.rv3d->depths->damaged = true;
+ if (xfd->depths) {
+ ED_view3d_depths_free(xfd->depths);
}
#endif
@@ -1782,13 +1783,14 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
vc.v3d->flag2 |= V3D_HIDE_OVERLAYS;
#endif
- ED_view3d_depth_override(vc.depsgraph, vc.region, vc.v3d, NULL, V3D_DEPTH_NO_GPENCIL, true);
+ ViewDepths *depths = NULL;
+ ED_view3d_depth_override(vc.depsgraph, vc.region, vc.v3d, NULL, V3D_DEPTH_NO_GPENCIL, &depths);
#ifdef USE_RENDER_OVERRIDE
vc.v3d->flag2 = flag2_prev;
#endif
- if (vc.rv3d->depths == NULL) {
+ if (depths == NULL) {
BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
return OPERATOR_CANCELLED;
}
@@ -1800,6 +1802,7 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
/* Don't change this at runtime. */
xfd->vc = vc;
+ xfd->depths = depths;
xfd->vc.mval[0] = event->mval[0];
xfd->vc.mval[1] = event->mval[1];
@@ -1863,7 +1866,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
const bool is_translate_init = is_translate && (xfd->is_translate != is_translate);
if (event->type == MOUSEMOVE || is_translate_init) {
- const ViewDepths *depths = xfd->vc.rv3d->depths;
+ const ViewDepths *depths = xfd->depths;
if (depths && ((uint)event->mval[0] < depths->w) && ((uint)event->mval[1] < depths->h)) {
float depth_fl = 1.0f;
ED_view3d_depth_read_cached(depths, event->mval, 0, &depth_fl);
@@ -1895,7 +1898,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
float normal[3];
bool normal_found = false;
- if (ED_view3d_depth_read_cached_normal(&xfd->vc, event->mval, normal)) {
+ if (ED_view3d_depth_read_cached_normal(region, depths, event->mval, normal)) {
normal_found = true;
/* cheap attempt to smooth normals out a bit! */
@@ -1905,7 +1908,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
if (x != 0 && y != 0) {
const int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y};
float n[3];
- if (ED_view3d_depth_read_cached_normal(&xfd->vc, mval_ofs, n)) {
+ if (ED_view3d_depth_read_cached_normal(region, depths, mval_ofs, n)) {
add_v3_v3(normal, n);
}
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 97994b65f40..2bf0f842623 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -466,6 +466,7 @@ static int pe_x_mirror(Object *ob)
typedef struct PEData {
ViewContext vc;
+ ViewDepths *depths;
const bContext *context;
Main *bmain;
@@ -524,14 +525,12 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
ED_view3d_viewcontext_init(C, &data->vc, data->depsgraph);
if (!XRAY_ENABLED(data->vc.v3d)) {
- if (!(data->vc.v3d->runtime.flag & V3D_RUNTIME_DEPTHBUF_OVERRIDDEN)) {
- ED_view3d_depth_override(data->depsgraph,
- data->vc.region,
- data->vc.v3d,
- data->vc.obact,
- V3D_DEPTH_OBJECT_ONLY,
- true);
- }
+ ED_view3d_depth_override(data->depsgraph,
+ data->vc.region,
+ data->vc.v3d,
+ data->vc.obact,
+ V3D_DEPTH_OBJECT_ONLY,
+ &data->depths);
}
}
@@ -570,6 +569,16 @@ static void PE_free_random_generator(PEData *data)
}
}
+static void PE_data_free(PEData *data)
+{
+ PE_free_random_generator(data);
+ PE_free_shape_tree(data);
+ if (data->depths) {
+ ED_view3d_depths_free(data->depths);
+ data->depths = NULL;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -579,7 +588,7 @@ static void PE_free_random_generator(PEData *data)
static bool key_test_depth(const PEData *data, const float co[3], const int screen_co[2])
{
View3D *v3d = data->vc.v3d;
- ViewDepths *vd = data->vc.rv3d->depths;
+ ViewDepths *vd = data->depths;
float depth;
/* nothing to do */
@@ -1871,15 +1880,13 @@ void PARTICLE_OT_select_all(wmOperatorType *ot)
bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- PEData data;
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
POINT_P;
KEY_K;
- PE_set_view3d_data(C, &data);
-
- PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!PE_start_edit(edit)) {
return false;
@@ -1894,6 +1901,8 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
}
}
+ PEData data;
+ PE_set_view3d_data(C, &data);
data.mval = mval;
data.rad = ED_view3d_select_dist_px();
@@ -1913,6 +1922,8 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
}
+ PE_data_free(&data);
+
return true;
}
@@ -2204,6 +2215,7 @@ static int select_linked_pick_exec(bContext *C, wmOperator *op)
for_mouse_hit_keys(&data, select_keys, PSEL_NEAREST);
PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ PE_data_free(&data);
return OPERATOR_FINISHED;
}
@@ -2298,11 +2310,14 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
for_mouse_hit_keys(&data, select_key_op, PSEL_ALL_KEYS);
}
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
+ bool is_changed = data.is_changed;
+ PE_data_free(&data);
+
+ if (is_changed) {
+ PE_update_selection(depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
}
- return data.is_changed;
+ return is_changed;
}
/** \} */
@@ -2311,35 +2326,53 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
/** \name Circle Select Operator
* \{ */
-bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
+static void pe_select_cache_free_generic_userdata(void *data)
+{
+ PE_data_free(data);
+ MEM_freeN(data);
+}
+
+static void pe_select_cache_init_with_generic_userdata(bContext *C, wmGenericUserData *wm_userdata)
+{
+ struct PEData *data = MEM_callocN(sizeof(*data), __func__);
+ wm_userdata->data = data;
+ wm_userdata->free_fn = pe_select_cache_free_generic_userdata;
+ wm_userdata->use_free = true;
+ PE_set_view3d_data(C, data);
+}
+
+bool PE_circle_select(
+ bContext *C, wmGenericUserData *wm_userdata, const int sel_op, const int mval[2], float rad)
{
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
- PEData data;
if (!PE_start_edit(edit)) {
return false;
}
- const bool select = (sel_op != SEL_OP_SUB);
+ if (wm_userdata->data == NULL) {
+ pe_select_cache_init_with_generic_userdata(C, wm_userdata);
+ }
- PE_set_view3d_data(C, &data);
- data.mval = mval;
- data.rad = rad;
- data.select = select;
+ PEData *data = wm_userdata->data;
+ data->mval = mval;
+ data->rad = rad;
+ data->select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- data.is_changed = PE_deselect_all_visible_ex(edit);
+ data->is_changed = PE_deselect_all_visible_ex(edit);
}
- for_mouse_hit_keys(&data, select_key, 0);
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
+ for_mouse_hit_keys(data, select_key, 0);
+
+ if (data->is_changed) {
+ PE_update_selection(depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
}
- return data.is_changed;
+ return data->is_changed;
}
/** \} */
@@ -2425,8 +2458,11 @@ int PE_lasso_select(bContext *C, const int mcoords[][2], const int mcoords_len,
}
}
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
+ bool is_changed = data.is_changed;
+ PE_data_free(&data);
+
+ if (is_changed) {
+ PE_update_selection(depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
}
@@ -4921,7 +4957,7 @@ static void brush_edit_exit(wmOperator *op)
{
BrushEdit *bedit = op->customdata;
- PE_free_random_generator(&bedit->data);
+ PE_data_free(&bedit->data);
MEM_freeN(bedit);
}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index a94a2b9b764..cbab4fbd3d1 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -403,8 +403,10 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
BLI_path_join(
temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
BLI_path_abs(temp_dir, relbase);
- BLI_dir_create_recursive(
- temp_dir); /* Create 'particles' subdir if it does not exist already */
+
+ /* Create 'particles' subdir if it does not exist already */
+ BLI_dir_create_recursive(temp_dir);
+
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES);
fds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES;
job->pause_frame = &fds->cache_frame_pause_particles;
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 0bec509cd7e..d39570857ab 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -285,7 +285,7 @@ static void screen_render_single_layer_set(
scn = (Scene *)BLI_findstring(&mainp->scenes, scene_name, offsetof(ID, name) + 2);
if (scn) {
- /* camera switch wont have updated */
+ /* camera switch won't have updated */
scn->r.cfra = (*scene)->r.cfra;
BKE_scene_camera_switch_update(scn);
@@ -773,7 +773,7 @@ static void render_endjob(void *rjv)
* was locked before running the job.
*/
WM_set_locked_interface(G_MAIN->wm.first, false);
- DEG_on_visible_update(G_MAIN, false);
+ DEG_tag_on_visible_update(G_MAIN, false);
}
}
@@ -793,7 +793,7 @@ static int render_breakjob(void *rjv)
/**
* For exec() when there is no render job
- * note: this wont check for the escape key being pressed, but doing so isn't thread-safe.
+ * note: this won't check for the escape key being pressed, but doing so isn't thread-safe.
*/
static int render_break(void *UNUSED(rjv))
{
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index cfc07de3f6c..48f937fb4ec 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -859,7 +859,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->task_pool = BLI_task_pool_create_background_serial(oglrender, TASK_PRIORITY_LOW);
}
else {
- oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW);
}
oglrender->pool_ok = true;
BLI_spin_init(&oglrender->reports_lock);
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 465438f814a..eb4a040e891 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -164,6 +164,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
sizex,
sizey,
SPACE_IMAGE,
+ true,
false,
true,
WIN_ALIGN_LOCATION_CENTER) == NULL) {
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 2b2a0d10e29..5195bc8303a 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -120,7 +120,7 @@ void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
BKE_scene_set_background(bmain, scene);
DEG_graph_relations_update(depsgraph);
- DEG_on_visible_update(bmain, false);
+ DEG_tag_on_visible_update(bmain, false);
ED_render_engine_changed(bmain, false);
ED_update_for_newframe(bmain, depsgraph);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 2814a4c9351..377cc60f9db 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1385,7 +1385,7 @@ static void region_rect_recursive(
region->flag |= RGN_FLAG_SIZE_CLAMP_Y;
}
- /* We need to use a test that wont have been previously clamped. */
+ /* We need to use a test that won't have been previously clamped. */
rcti winrct_test = {
.xmin = region->winrct.xmin,
.ymin = region->winrct.ymin,
@@ -2387,7 +2387,7 @@ void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_regi
* However, add-on install for example, forces the header to the top which shouldn't
* be applied back to the previous space type when closing - see: T57724
*
- * Newly created windows wont have any space data, use the alignment
+ * Newly-created windows won't have any space data, use the alignment
* the space type defaults to in this case instead
* (needed for preferences to have space-type on bottom).
*/
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 6fb5f33d836..21800536503 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -68,7 +68,7 @@ static ScrArea *screen_addarea_ex(ScrAreaMap *area_map,
ScrVert *top_left,
ScrVert *top_right,
ScrVert *bottom_right,
- short spacetype)
+ const eSpace_Type space_type)
{
ScrArea *area = MEM_callocN(sizeof(ScrArea), "addscrarea");
@@ -76,7 +76,7 @@ static ScrArea *screen_addarea_ex(ScrAreaMap *area_map,
area->v2 = top_left;
area->v3 = top_right;
area->v4 = bottom_right;
- area->spacetype = spacetype;
+ area->spacetype = space_type;
BLI_addtail(&area_map->areabase, area);
@@ -87,10 +87,10 @@ static ScrArea *screen_addarea(bScreen *screen,
ScrVert *left_top,
ScrVert *right_top,
ScrVert *right_bottom,
- short spacetype)
+ const eSpace_Type space_type)
{
return screen_addarea_ex(
- AREAMAP_FROM_SCREEN(screen), left_bottom, left_top, right_top, right_bottom, spacetype);
+ AREAMAP_FROM_SCREEN(screen), left_bottom, left_top, right_top, right_bottom, space_type);
}
static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
@@ -972,7 +972,7 @@ int ED_screen_area_active(const bContext *C)
*/
static ScrArea *screen_area_create_with_geometry(ScrAreaMap *area_map,
const rcti *rect,
- short spacetype)
+ eSpace_Type space_type)
{
ScrVert *bottom_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin);
ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax);
@@ -984,7 +984,7 @@ static ScrArea *screen_area_create_with_geometry(ScrAreaMap *area_map,
screen_geom_edge_add_ex(area_map, top_right, bottom_right);
screen_geom_edge_add_ex(area_map, bottom_right, bottom_left);
- return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
+ return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, space_type);
}
static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
@@ -1001,7 +1001,7 @@ static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
static void screen_global_area_refresh(wmWindow *win,
bScreen *screen,
- eSpace_Type space_type,
+ const eSpace_Type space_type,
GlobalAreaAlign align,
const rcti *rect,
const short height_cur,
@@ -1275,11 +1275,14 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
{
+ bScreen *newscreen = NULL;
ScrArea *newsa = NULL;
SpaceLink *newsl;
if (!area || area->full == NULL) {
- newsa = ED_screen_state_maximized_create(C);
+ newscreen = ED_screen_state_maximized_create(C);
+ newsa = newscreen->areabase.first;
+ BLI_assert(newsa->spacetype == SPACE_EMPTY);
}
if (!newsa) {
@@ -1296,6 +1299,10 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY));
+ if (newscreen) {
+ ED_screen_change(C, newscreen);
+ }
+
return newsa;
}
@@ -1361,6 +1368,10 @@ void ED_screen_full_restore(bContext *C, ScrArea *area)
* \param toggle_area: If this is set, its space data will be swapped with the one of the new empty
* area, when toggling back it can be swapped back again.
* \return The newly created screen with the non-normal area.
+ *
+ * \note The caller must run #ED_screen_change this is not done in this function
+ * as it would attempt to initialize areas that don't yet have a space-type assigned
+ * (converting them to 3D view without creating the space-data).
*/
static bScreen *screen_state_to_nonnormal(bContext *C,
wmWindow *win,
@@ -1429,7 +1440,6 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
}
newa->full = oldscreen;
- ED_screen_change(C, screen);
ED_area_tag_refresh(newa);
return screen;
@@ -1442,10 +1452,9 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
* Use this to just create a new maximized screen/area, rather than maximizing an existing one.
* Otherwise, maximize with #ED_screen_state_toggle().
*/
-ScrArea *ED_screen_state_maximized_create(bContext *C)
+bScreen *ED_screen_state_maximized_create(bContext *C)
{
- bScreen *screen = screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED);
- return screen->areabase.first;
+ return screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED);
}
/**
@@ -1548,6 +1557,8 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
}
screen = screen_state_to_nonnormal(C, win, toggle_area, state);
+
+ ED_screen_change(C, screen);
}
BLI_assert(CTX_wm_screen(C) == screen);
@@ -1585,6 +1596,7 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
sizex,
sizey,
(int)space_type,
+ false,
dialog,
true,
WIN_ALIGN_LOCATION_CENTER)) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 6b8d4e73f12..f0e12ca60e9 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -279,6 +279,11 @@ bool ED_operator_file_active(bContext *C)
return ed_spacetype_test(C, SPACE_FILE);
}
+bool ED_operator_spreadsheet_active(bContext *C)
+{
+ return ed_spacetype_test(C, SPACE_SPREADSHEET);
+}
+
bool ED_operator_action_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_ACTION);
@@ -358,9 +363,24 @@ bool ED_operator_object_active(bContext *C)
return ((ob != NULL) && !ed_object_hidden(ob));
}
-bool ED_operator_object_active_editable_ex(bContext *UNUSED(C), const Object *ob)
+bool ED_operator_object_active_editable_ex(bContext *C, const Object *ob)
{
- return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+ if (ob == NULL) {
+ CTX_wm_operator_poll_msg_set(C, "Context missing active object");
+ return false;
+ }
+
+ if (ID_IS_LINKED(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit library linked object");
+ return false;
+ }
+
+ if (ed_object_hidden(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit hidden obect");
+ return false;
+ }
+
+ return true;
}
bool ED_operator_object_active_editable(bContext *C)
@@ -444,28 +464,48 @@ bool ED_operator_editarmature(bContext *C)
}
/**
- * \brief check for pose mode (no mixed modes)
+ * Check for pose mode (no mixed modes).
*
- * We want to enable most pose operations in weight paint mode,
- * when it comes to transforming bones, but managing bones layers/groups
- * can be left for pose mode only. (not weight paint mode)
+ * We want to enable most pose operations in weight paint mode, when it comes to transforming
+ * bones, but managing bones layers/groups and their constraints can be left for pose mode only
+ * (not weight paint mode).
*/
-bool ED_operator_posemode_exclusive(bContext *C)
+static bool ed_operator_posemode_exclusive_ex(bContext *C, Object *obact)
{
- Object *obact = CTX_data_active_object(C);
-
- if (obact && !(obact->mode & OB_MODE_EDIT)) {
- Object *obpose = BKE_object_pose_armature_get(obact);
- if (obpose != NULL) {
- if (obact == obpose) {
- return true;
- }
+ if (obact != NULL && !(obact->mode & OB_MODE_EDIT)) {
+ if (obact == BKE_object_pose_armature_get(obact)) {
+ return true;
}
}
+ CTX_wm_operator_poll_msg_set(C, "No object, or not exclusively in pose mode");
return false;
}
+bool ED_operator_posemode_exclusive(bContext *C)
+{
+ Object *obact = ED_object_active_context(C);
+
+ return ed_operator_posemode_exclusive_ex(C, obact);
+}
+
+/** Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode. */
+bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
+{
+ Object *obact = ED_object_active_context(C);
+
+ if (!ed_operator_posemode_exclusive_ex(C, obact)) {
+ return false;
+ }
+
+ if (ID_IS_OVERRIDE_LIBRARY(obact)) {
+ CTX_wm_operator_poll_msg_set(C, "Object is a local library override");
+ return false;
+ }
+
+ return true;
+}
+
/* allows for pinned pose objects to be used in the object buttons
* and the non-active pose object to be used in the 3D view */
bool ED_operator_posemode_context(bContext *C)
@@ -1362,6 +1402,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
area->winx,
area->winy,
SPACE_EMPTY,
+ false,
true,
false,
WIN_ALIGN_ABSOLUTE);
@@ -4446,9 +4487,17 @@ static void screen_animation_region_tag_redraw(ScrArea *area,
/* No need to do a full redraw as the current frame indicator is only updated.
* We do need to redraw when this area is in full screen as no other areas
* will be tagged for redrawing. */
- if ((region->regiontype == RGN_TYPE_WINDOW) &&
- (ELEM(area->spacetype, SPACE_GRAPH, SPACE_NLA, SPACE_ACTION)) && !area->full) {
- return;
+ if (region->regiontype == RGN_TYPE_WINDOW && !area->full) {
+ if (ELEM(area->spacetype, SPACE_GRAPH, SPACE_NLA, SPACE_ACTION)) {
+ return;
+ }
+
+ if (area->spacetype == SPACE_SEQ) {
+ const SpaceSeq *sseq = area->spacedata.first;
+ if (!ED_space_sequencer_has_playback_animation(sseq, scene)) {
+ return;
+ }
+ }
}
ED_region_tag_redraw(region);
}
@@ -4948,6 +4997,7 @@ static int userpref_show_exec(bContext *C, wmOperator *op)
sizey,
SPACE_USERPREF,
false,
+ false,
true,
WIN_ALIGN_LOCATION_CENTER) != NULL) {
/* The header only contains the editor switcher and looks empty.
@@ -5014,6 +5064,7 @@ static int drivers_editor_show_exec(bContext *C, wmOperator *op)
sizey,
SPACE_GRAPH,
false,
+ false,
true,
WIN_ALIGN_LOCATION_CENTER) != NULL) {
ED_drivers_editor_init(C, CTX_wm_area(C));
@@ -5082,6 +5133,7 @@ static int info_log_show_exec(bContext *C, wmOperator *op)
sizey,
SPACE_INFO,
false,
+ false,
true,
WIN_ALIGN_LOCATION_CENTER) != NULL) {
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 41db79bc134..c83e4de281a 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -122,7 +122,7 @@ BLI_INLINE uchar f_to_char(const float val)
*
* When 3 - a brush should have ~9 buckets under it at once
* ...this helps for threading while painting as well as
- * avoiding initializing pixels that wont touch the brush */
+ * avoiding initializing pixels that won't touch the brush */
#define PROJ_BUCKET_BRUSH_DIV 4
#define PROJ_BUCKET_RECT_MIN 4
@@ -957,7 +957,7 @@ static int line_isect_y(const float p1[2], const float p2[2], const float y_leve
return ISECT_TRUE_P2;
}
- /** yuck, horizontal line, we cant do much here. */
+ /** yuck, horizontal line, we can't do much here. */
y_diff = fabsf(p1[1] - p2[1]);
if (y_diff < 0.000001f) {
@@ -991,10 +991,10 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
return ISECT_TRUE_P2;
}
- /* yuck, horizontal line, we cant do much here */
+ /* yuck, horizontal line, we can't do much here */
x_diff = fabsf(p1[0] - p2[0]);
- /* yuck, vertical line, we cant do much here */
+ /* yuck, vertical line, we can't do much here */
if (x_diff < 0.000001f) {
*y_isect = (p1[0] + p2[0]) * 0.5f;
return ISECT_TRUE;
@@ -3152,7 +3152,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
}
//#if 0
else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ /* assuming the face is not a bow-tie - we know we can't intersect again on the X */
break;
}
//#endif
@@ -3239,7 +3239,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
uv_image_outset(ps, lt_uv_pxoffset, lt_puv, tri_index, ibuf->x, ibuf->y);
}
- /* ps->loopSeamUVs cant be modified when threading, now this is done we can unlock. */
+ /* ps->loopSeamUVs can't be modified when threading, now this is done we can unlock. */
if (threaded) {
/* Other threads could be modifying these vars */
BLI_thread_unlock(LOCK_CUSTOM1);
@@ -3292,7 +3292,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
interp_v2_v2v2(seam_subsection[3], seam_uvs[0], seam_uvs[1], fac1);
/* if the bucket_clip_edges values Z values was kept we could avoid this
- * Inset needs to be added so occlusion tests wont hit adjacent faces */
+ * Inset needs to be added so occlusion tests won't hit adjacent faces */
interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
@@ -3648,7 +3648,7 @@ static void project_paint_delayed_face_init(ProjPaintState *ps,
has_x_isect = has_isect = 1;
}
else if (has_x_isect) {
- /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ /* assuming the face is not a bow-tie - we know we can't intersect again on the X */
break;
}
}
@@ -5514,7 +5514,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
if (tool == PAINT_TOOL_SMEAR) {
- for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */
+ for (node = smearPixels; node; node = node->next) { /* this won't run for a float image */
projPixel = node->link;
*projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
if (lock_alpha) {
@@ -5534,7 +5534,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
}
else if (tool == PAINT_TOOL_SOFTEN) {
- for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */
+ for (node = softenPixels; node; node = node->next) { /* this won't run for a float image */
projPixel = node->link;
*projPixel->pixel.uint_pt = projPixel->newColor.uint;
if (lock_alpha) {
@@ -5571,7 +5571,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
if (ps->thread_tot > 1) {
- task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH);
}
image_pool = BKE_image_pool_new();
@@ -6468,6 +6468,8 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
alpha = RNA_boolean_get(op->ptr, "alpha");
RNA_string_get(op->ptr, "name", imagename);
}
+
+ /* TODO(lukas): Add option for tiled image. */
ima = BKE_image_add_generated(bmain,
width,
height,
@@ -6478,7 +6480,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
color,
false,
is_data,
- false); /* TODO(lukas): Add option */
+ false);
return ima;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index daccc6f228a..0a5f1975361 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -725,7 +725,7 @@ typedef struct WeightPaintInfo {
* length of defbase_tot */
const bool *lock_flags;
/* boolean array for selected bones,
- * length of defbase_tot, cant be const because of how its passed */
+ * length of defbase_tot, can't be const because of how it's passed */
const bool *defbase_sel;
/* same as WeightPaintData.vgroup_validmap,
* only added here for convenience */
@@ -917,7 +917,7 @@ static void do_weight_paint_vertex_single(
* 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active.
*
* However this gave a problem since applying mirror, then normalize both verts
- * the resulting weight wont match on both sides.
+ * the resulting weight won't match on both sides.
*
* If this 'resisting', slower normalize is nicer, we could call
* do_weight_paint_normalize_all() and only use...
@@ -941,13 +941,13 @@ static void do_weight_paint_vertex_single(
* - Auto normalize is enabled.
* - The group you are painting onto has a L / R version.
*
- * We want L/R vgroups to have the same weight but this cant be if both are over 0.5,
+ * We want L/R vgroups to have the same weight but this can't be if both are over 0.5,
* We _could_ have special check for that, but this would need its own
* normalize function which holds 2 groups from changing at once.
*
* So! just balance out the 2 weights, it keeps them equal and everything normalized.
*
- * While it wont hit the desired weight immediately as the user waggles their mouse,
+ * While it won't hit the desired weight immediately as the user waggles their mouse,
* constant painting and re-normalizing will get there. this is also just simpler logic.
* - campbell */
dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index d6d54a1985d..ab5c46f4bc5 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1146,10 +1146,9 @@ void SCULPT_floodfill_add_active(
v = SCULPT_active_vertex_get(ss);
}
else if (radius > 0.0f) {
- float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
float location[3];
flip_v3_v3(location, SCULPT_active_vertex_co_get(ss), i);
- v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ v = SCULPT_nearest_vertex_get(sd, ob, location, radius, false);
}
if (v != -1) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index b6205db6f45..71166b7c20c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1189,9 +1189,7 @@ static SculptUndoNode *sculpt_undo_geometry_push(Object *object, SculptUndoType
static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptUndoNode *unode = usculpt->nodes.first;
-
- unode = MEM_callocN(sizeof(*unode), __func__);
+ SculptUndoNode *unode = MEM_callocN(sizeof(*unode), __func__);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
unode->type = type;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 98e39520e99..fea01ab5330 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1872,12 +1872,13 @@ void ACTION_OT_clickselect(wmOperatorType *ot)
/* properties */
WM_operator_properties_generic_select(ot);
+ /* Key-map: Enable with `Shift`. */
prop = RNA_def_boolean(
ot->srna,
"extend",
0,
"Extend Select",
- "Toggle keyframe selection instead of leaving newly selected keyframes only"); /* SHIFTKEY */
+ "Toggle keyframe selection instead of leaving newly selected keyframes only");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
@@ -1887,20 +1888,21 @@ void ACTION_OT_clickselect(wmOperatorType *ot)
"Deselect all when nothing under the cursor");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* Key-map: Enable with `Alt`. */
prop = RNA_def_boolean(
ot->srna,
"column",
0,
"Column Select",
- "Select all keyframes that occur on the same frame as the one under the mouse"); /* ALTKEY */
+ "Select all keyframes that occur on the same frame as the one under the mouse");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(
- ot->srna,
- "channel",
- 0,
- "Only Channel",
- "Select all the keyframes in the channel under the mouse"); /* CTRLKEY + ALTKEY */
+ /* Key-map: Enable with `Ctrl-Alt`. */
+ prop = RNA_def_boolean(ot->srna,
+ "channel",
+ 0,
+ "Only Channel",
+ "Select all the keyframes in the channel under the mouse");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index f6af2f79890..26b087168f9 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -153,6 +153,8 @@ static SpaceLink *action_duplicate(SpaceLink *sl)
{
SpaceAction *sactionn = MEM_dupallocN(sl);
+ memset(&sactionn->runtime, 0x0, sizeof(sactionn->runtime));
+
/* clear or remove stuff from old */
return (SpaceLink *)sactionn;
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 9aa6a993c13..2da13646a8b 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -904,7 +904,7 @@ static void start_prefetch_threads(MovieClip *clip,
queue.do_update = do_update;
queue.progress = progress;
- TaskPool *task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ TaskPool *task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
for (int i = 0; i < tot_thread; i++) {
BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, NULL);
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index cd60ebf3031..f5e4c4d55d9 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1235,10 +1235,8 @@ static void do_movie_proxy(void *pjv,
float *progress)
{
ProxyJob *pj = pjv;
- Scene *scene = pj->scene;
MovieClip *clip = pj->clip;
struct MovieDistortion *distortion = NULL;
- int cfra, sfra = SFRA, efra = EFRA;
if (pj->index_context) {
IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
@@ -1252,8 +1250,8 @@ static void do_movie_proxy(void *pjv,
return;
}
- sfra = 1;
- efra = clip->len;
+ const int sfra = 1;
+ const int efra = clip->len;
if (build_undistort_count) {
int threads = BLI_system_thread_count();
@@ -1265,7 +1263,7 @@ static void do_movie_proxy(void *pjv,
BKE_tracking_distortion_set_threads(distortion, threads);
}
- for (cfra = sfra; cfra <= efra; cfra++) {
+ for (int cfra = sfra; cfra <= efra; cfra++) {
BKE_movieclip_build_proxy_frame(
clip, pj->clip_flag, distortion, cfra, build_undistort_sizes, build_undistort_count, 1);
@@ -1431,7 +1429,7 @@ static void do_sequence_proxy(void *pjv,
queue.do_update = do_update;
queue.progress = progress;
- TaskPool *task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ TaskPool *task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
for (int i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index bcac4d94bf0..ff62bcf0cfa 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -52,7 +52,9 @@
#include "clip_intern.h"
#include "tracking_ops_intern.h"
-/********************** add marker operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Add Marker Operator
+ * \{ */
static bool add_marker(const bContext *C, float x, float y)
{
@@ -147,7 +149,11 @@ void CLIP_OT_add_marker(wmOperatorType *ot)
1.0f);
}
-/********************** add marker operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Marker Operator
+ * \{ */
static int add_marker_at_click_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
@@ -212,7 +218,11 @@ void CLIP_OT_add_marker_at_click(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
}
-/********************** delete track operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Track Operator
+ * \{ */
static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -265,7 +275,11 @@ void CLIP_OT_delete_track(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** delete marker operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Marker Operator
+ * \{ */
static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -334,7 +348,11 @@ void CLIP_OT_delete_marker(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** slide marker operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Slide Marker Operator
+ * \{ */
enum {
SLIDE_ACTION_POS = 0,
@@ -1000,7 +1018,11 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
FLT_MAX);
}
-/********************** clear track operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Track Operator
+ * \{ */
static int clear_track_path_exec(bContext *C, wmOperator *op)
{
@@ -1071,7 +1093,11 @@ void CLIP_OT_clear_track_path(wmOperatorType *ot)
"Clear active track only instead of all selected tracks");
}
-/********************** disable markers operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Disable Markers Operator
+ * \{ */
enum {
MARKER_OP_DISABLE = 0,
@@ -1137,7 +1163,11 @@ void CLIP_OT_disable_markers(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
}
-/********************** set principal center operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Principal Center Operator
+ * \{ */
static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1174,7 +1204,11 @@ void CLIP_OT_set_center_principal(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** hide tracks operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Tracks Operator
+ * \{ */
static int hide_tracks_exec(bContext *C, wmOperator *op)
{
@@ -1241,7 +1275,11 @@ void CLIP_OT_hide_tracks(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
}
-/********************** hide tracks clear operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Tracks Clear Operator
+ * \{ */
static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1284,7 +1322,11 @@ void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** frame jump operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Frame Jump Operator
+ * \{ */
static bool frame_jump_poll(bContext *C)
{
@@ -1379,7 +1421,11 @@ void CLIP_OT_frame_jump(wmOperatorType *ot)
RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jump to");
}
-/********************** join tracks operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Join Tracks Operator
+ * \{ */
static int join_tracks_exec(bContext *C, wmOperator *op)
{
@@ -1475,7 +1521,11 @@ void CLIP_OT_join_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Average tracks operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Average Tracks Operator
+ * \{ */
static int average_tracks_exec(bContext *C, wmOperator *op)
{
@@ -1566,7 +1616,11 @@ void CLIP_OT_average_tracks(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************** lock tracks operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lock Tracks Operator
+ * \{ */
enum {
TRACK_ACTION_LOCK = 0,
@@ -1628,7 +1682,11 @@ void CLIP_OT_lock_tracks(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
}
-/********************** set keyframe operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Keyframe Operator
+ * \{ */
enum {
SOLVER_KEYFRAME_A = 0,
@@ -1680,7 +1738,11 @@ void CLIP_OT_set_solver_keyframe(wmOperatorType *ot)
RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe", "Keyframe to set");
}
-/********************** track copy color operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Track Copy Color Operator
+ * \{ */
static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1725,7 +1787,11 @@ void CLIP_OT_track_copy_color(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** clean tracks operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clean Tracks Operator
+ * \{ */
static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
{
@@ -1963,7 +2029,11 @@ void CLIP_OT_clean_tracks(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
}
-/********************** add tracking object *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Tracking Object
+ * \{ */
static int tracking_object_new_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1994,7 +2064,11 @@ void CLIP_OT_tracking_object_new(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** remove tracking object *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Tracking Object
+ * \{ */
static int tracking_object_remove_exec(bContext *C, wmOperator *op)
{
@@ -2033,7 +2107,11 @@ void CLIP_OT_tracking_object_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** copy tracks to clipboard operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy Tracks to Clipboard Operator
+ * \{ */
static int copy_tracks_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2064,7 +2142,11 @@ void CLIP_OT_copy_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* paste tracks from clipboard operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paste Tracks From Clipboard Operator
+ * \{ */
static bool paste_tracks_poll(bContext *C)
{
@@ -2106,7 +2188,11 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Insert track keyframe operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Insert Track Keyframe Operator
+ * \{ */
static void keyframe_set_flag(bContext *C, bool set)
{
@@ -2181,7 +2267,11 @@ void CLIP_OT_keyframe_insert(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Delete track keyframe operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Track Keyframe Operator
+ * \{ */
static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2203,3 +2293,5 @@ void CLIP_OT_keyframe_delete(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 189b9b4c874..5e09692b041 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -142,7 +142,8 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh
color);
}
-static void file_draw_icon(uiBlock *block,
+static void file_draw_icon(const SpaceFile *sfile,
+ uiBlock *block,
const FileDirEntry *file,
const char *path,
int sx,
@@ -173,14 +174,19 @@ static void file_draw_icon(uiBlock *block,
if ((id = filelist_file_get_id(file))) {
UI_but_drag_set_id(but, id);
}
- else if (file->typeflag & FILE_TYPE_ASSET) {
+ else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS &&
+ (file->typeflag & FILE_TYPE_ASSET) != 0) {
ImBuf *preview_image = filelist_file_getimage(file);
char blend_path[FILE_MAX_LIBEXTRA];
if (BLO_library_path_explode(path, blend_path, NULL, NULL)) {
+ const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
+ BLI_assert(asset_params != NULL);
+
UI_but_drag_set_asset(but,
file->name,
BLI_strdup(blend_path),
file->blentype,
+ asset_params->import_type,
icon,
preview_image,
UI_DPI_FAC);
@@ -299,7 +305,8 @@ void file_calc_previews(const bContext *C, ARegion *region)
UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
}
-static void file_draw_preview(uiBlock *block,
+static void file_draw_preview(const SpaceFile *sfile,
+ uiBlock *block,
const FileDirEntry *file,
const char *path,
int sx,
@@ -484,9 +491,19 @@ static void file_draw_preview(uiBlock *block,
/* path is no more static, cannot give it directly to but... */
else if (file->typeflag & FILE_TYPE_ASSET) {
char blend_path[FILE_MAX_LIBEXTRA];
+
if (BLO_library_path_explode(path, blend_path, NULL, NULL)) {
- UI_but_drag_set_asset(
- but, file->name, BLI_strdup(blend_path), file->blentype, icon, imb, scale);
+ const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
+ BLI_assert(asset_params != NULL);
+
+ UI_but_drag_set_asset(but,
+ file->name,
+ BLI_strdup(blend_path),
+ file->blentype,
+ asset_params->import_type,
+ icon,
+ imb,
+ scale);
}
}
else {
@@ -925,7 +942,8 @@ void file_draw_list(const bContext *C, ARegion *region)
is_icon = 1;
}
- file_draw_preview(block,
+ file_draw_preview(sfile,
+ block,
file,
path,
sx,
@@ -940,7 +958,8 @@ void file_draw_list(const bContext *C, ARegion *region)
is_link);
}
else {
- file_draw_icon(block,
+ file_draw_icon(sfile,
+ block,
file,
path,
sx,
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index f1d0197b9ae..a7c57459729 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -62,6 +62,7 @@ void FILE_OT_bookmark_cleanup(struct wmOperatorType *ot);
void FILE_OT_bookmark_move(struct wmOperatorType *ot);
void FILE_OT_reset_recent(wmOperatorType *ot);
void FILE_OT_hidedot(struct wmOperatorType *ot);
+void FILE_OT_associate_blend(struct wmOperatorType *ot);
void FILE_OT_execute(struct wmOperatorType *ot);
void FILE_OT_mouse_execute(struct wmOperatorType *ot);
void FILE_OT_cancel(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 7c14f4659eb..0ac03c4c307 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1677,7 +1677,7 @@ void file_draw_check_ex(bContext *C, ScrArea *area)
if (op->type->check(C, op)) {
file_operator_to_sfile(bmain, sfile, op);
- /* redraw, else the changed settings wont get updated */
+ /* redraw, else the changed settings won't get updated */
ED_area_tag_redraw(area);
}
}
@@ -2633,6 +2633,43 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Associate File Type Operator (Windows only)
+ * \{ */
+
+static int associate_blend_exec(bContext *UNUSED(C), wmOperator *op)
+{
+#ifdef WIN32
+ WM_cursor_wait(true);
+ if (BLI_windows_register_blend_extension(true)) {
+ BKE_report(op->reports, RPT_INFO, "File association registered");
+ WM_cursor_wait(false);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Unable to register file association");
+ WM_cursor_wait(false);
+ return OPERATOR_CANCELLED;
+ }
+#else
+ BKE_report(op->reports, RPT_WARNING, "Operator Not supported");
+ return OPERATOR_CANCELLED;
+#endif
+}
+
+void FILE_OT_associate_blend(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Register File Association";
+ ot->description = "Use this installation for .blend files and to display thumbnails";
+ ot->idname = "FILE_OT_associate_blend";
+
+ /* api callbacks */
+ ot->exec = associate_blend_exec;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Increment Filename Operator
* \{ */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 8ea44e5c3ee..e43000d3f64 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1553,8 +1553,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
{
if (!cache->previews_pool) {
- cache->previews_pool = BLI_task_pool_create_background(
- cache, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW);
cache->previews_done = BLI_thread_queue_init();
IMB_thumb_locks_acquire();
@@ -2895,7 +2894,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
}
/* there we go */
- libfiledata = BLO_blendhandle_from_file(dir, NULL);
+ libfiledata = BLO_blendhandle_from_file(dir, &(BlendFileReadReport){.reports = NULL});
if (libfiledata == NULL) {
return nbr_entries;
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 038b9c11bca..8e3fc36aa71 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -120,6 +120,7 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
asset_params->base_params.details_flags = U_default.file_space_data.details_flags;
asset_params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL;
asset_params->asset_library.custom_library_index = -1;
+ asset_params->import_type = FILE_ASSET_IMPORT_APPEND;
}
FileSelectParams *base_params = &asset_params->base_params;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 12bc0a68ca6..0418bb87768 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -675,6 +675,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_bookmark_move);
WM_operatortype_append(FILE_OT_reset_recent);
WM_operatortype_append(FILE_OT_hidedot);
+ WM_operatortype_append(FILE_OT_associate_blend);
WM_operatortype_append(FILE_OT_filenum);
WM_operatortype_append(FILE_OT_directory_new);
WM_operatortype_append(FILE_OT_delete);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index d88bf8750c2..ec5f443e2dc 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -1337,8 +1337,8 @@ static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int
{
switch (event) {
case B_FMODIFIER_REDRAW: /* XXX this should send depsgraph updates too */
- WM_event_add_notifier(
- C, NC_ANIMATION, NULL); /* XXX need a notifier specially for F-Modifiers */
+ /* XXX: need a notifier specially for F-Modifiers */
+ WM_event_add_notifier(C, NC_ANIMATION, NULL);
break;
}
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 0e22a2fffe1..50d14d18be9 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -675,6 +675,16 @@ static short ok_bezier_always_ok(KeyframeEditData *UNUSED(ked), BezTriple *UNUSE
return KEYFRAME_OK_KEY | KEYFRAME_OK_H1 | KEYFRAME_OK_H2;
}
+#define ABOVE 1
+#define INSIDE 0
+#define BELOW -1
+static int rectf_curve_zone_y(
+ FCurve *fcu, const rctf *rectf, const float offset, const float unit_scale, const float eval_x)
+{
+ const float fcurve_y = (evaluate_fcurve(fcu, eval_x) + offset) * unit_scale;
+ return fcurve_y < rectf->ymin ? BELOW : fcurve_y <= rectf->ymax ? INSIDE : ABOVE;
+}
+
/* Checks whether the given rectangle intersects the given fcurve's calculated curve (i.e. not
* only keyframes, but also all the interpolated values). This is done by sampling the curve at
* different points between the xmin and the xmax of the rectangle.
@@ -683,8 +693,7 @@ static bool rectf_curve_intersection(
const float offset, const float unit_scale, const rctf *rectf, AnimData *adt, FCurve *fcu)
{
/* 30 sampling points. This worked well in tests. */
- const float num_steps = 30.0f;
- const float step = (rectf->xmax - rectf->xmin) / num_steps;
+ int num_steps = 30;
/* Remap the range at which to evaluate the fcurves. This enables us to avoid remapping
* the keys themselves. */
@@ -692,27 +701,36 @@ static bool rectf_curve_intersection(
const float mapped_min = BKE_nla_tweakedit_remap(adt, rectf->xmin, NLATIME_CONVERT_UNMAP);
const float eval_step = (mapped_max - mapped_min) / num_steps;
- float x = rectf->xmin;
- float eval_x = mapped_min;
/* Sample points on the given fcurve in the interval defined by the
* mapped_min and mapped_max of the selected rectangle.
* For each point, check if it is inside of the selection box. If it is, then select
* all the keyframes of the curve, the curve, and stop the loop.
*/
- while (x < rectf->xmax) {
- const float fcurve_y = (evaluate_fcurve(fcu, eval_x) + offset) * unit_scale;
- /* Since rectf->xmin <= x < rectf->xmax is always true, there is no need to keep comparing the
- * X-coordinate to the rectangle in every iteration. Therefore we do the comparisons manually
- * instead of using BLI_rctf_isect_pt_v(rectf, current_point).
- */
- if (rectf->ymin <= fcurve_y && fcurve_y <= rectf->ymax) {
+ struct {
+ float eval_x;
+ int zone;
+ } cur, prev;
+
+ prev.eval_x = mapped_min;
+ prev.zone = rectf_curve_zone_y(fcu, rectf, offset, unit_scale, prev.eval_x);
+ if (prev.zone == INSIDE) {
+ return true;
+ }
+
+ while (num_steps--) {
+ cur.eval_x = prev.eval_x + eval_step;
+ cur.zone = rectf_curve_zone_y(fcu, rectf, offset, unit_scale, cur.eval_x);
+ if (cur.zone != prev.zone) {
return true;
}
- x += step;
- eval_x += eval_step;
+
+ prev = cur;
}
return false;
}
+#undef ABOVE
+#undef INSIDE
+#undef BELOW
/* Perform a box selection of the curves themselves. This means this function tries
* to select a curve by sampling it at various points instead of trying to select the
@@ -1805,7 +1823,6 @@ static int graphkeys_mselect_column(bAnimContext *ac,
KeyframeEditFunc select_cb, ok_cb;
KeyframeEditData ked;
tNearestVertInfo *nvi;
- float selx = (float)ac->scene->r.cfra;
/* find the beztriple that we're selecting, and the handle that was clicked on */
nvi = find_nearest_fcurve_vert(ac, mval);
@@ -1817,7 +1834,7 @@ static int graphkeys_mselect_column(bAnimContext *ac,
/* get frame number on which elements should be selected */
/* TODO: should we restrict to integer frames only? */
- selx = nvi->frame;
+ const float selx = nvi->frame;
if (select_mode != SELECT_REPLACE) {
/* Doesn't need to deselect anything -> Pass. */
@@ -1941,12 +1958,14 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
/* properties */
WM_operator_properties_generic_select(ot);
+
+ /* Key-map: Enable with `Shift`. */
prop = RNA_def_boolean(ot->srna,
"extend",
0,
"Extend Select",
"Toggle keyframe selection instead of leaving newly selected "
- "keyframes only"); /* SHIFTKEY */
+ "keyframes only");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
@@ -1956,19 +1975,18 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
"Deselect all when nothing under the cursor");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* Key-map: Enable with `Alt`. */
prop = RNA_def_boolean(ot->srna,
"column",
0,
"Column Select",
"Select all keyframes that occur on the same frame as the one under "
- "the mouse"); /* ALTKEY */
+ "the mouse");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna,
- "curves",
- 0,
- "Only Curves",
- "Select all the keyframes in the curve"); /* CTRLKEY + ALTKEY */
+ /* Key-map: Enable with `Ctrl-Atl`. */
+ prop = RNA_def_boolean(
+ ot->srna, "curves", 0, "Only Curves", "Select all the keyframes in the curve");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 9f01773eadf..0c6d904de01 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -172,6 +172,8 @@ static SpaceLink *graph_duplicate(SpaceLink *sl)
{
SpaceGraph *sipon = MEM_dupallocN(sl);
+ memset(&sipon->runtime, 0x0, sizeof(sipon->runtime));
+
/* clear or remove stuff from old */
BLI_duplicatelist(&sipon->runtime.ghost_curves, &((SpaceGraph *)sl)->runtime.ghost_curves);
sipon->ads = MEM_dupallocN(sipon->ads);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 6053253790a..9e2bd1448b2 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1311,7 +1311,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
- ImageOpenData *iod = op->customdata;
Image *ima = NULL;
int frame_seq_len = 0;
int frame_ofs = 1;
@@ -1345,7 +1344,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
}
/* hook into UI */
- iod = op->customdata;
+ ImageOpenData *iod = op->customdata;
if (iod->pprop.prop) {
/* when creating new ID blocks, use is already 1, but RNA
@@ -1608,7 +1607,7 @@ static int image_replace_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", str);
- /* we cant do much if the str is longer than FILE_MAX :/ */
+ /* we can't do much if the str is longer than FILE_MAX :/ */
BLI_strncpy(sima->image->filepath, str, sizeof(sima->image->filepath));
if (sima->image->source == IMA_SRC_GENERATED) {
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index feee268c6d3..09e30298e79 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -293,8 +293,9 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
}
- BKE_image_free_gputextures(
- image); /* force OpenGL reload (maybe partial update will operate better?) */
+ /* Force OpenGL reload (maybe partial update will operate better?) */
+ BKE_image_free_gputextures(image);
+
if (ibuf->rect_float) {
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
}
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index be3b60d581b..9524c2a1d8a 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -134,14 +134,12 @@ static void report_textview_end(TextViewContext *UNUSED(tvc))
static int report_textview_step(TextViewContext *tvc)
{
/* simple case, but no newline support */
- const Report *report = tvc->iter;
-
if (tvc->iter_char_begin <= 0) {
tvc->iter = (void *)((Link *)tvc->iter)->prev;
if (tvc->iter && report_textview_skip__internal(tvc)) {
tvc->iter_tmp++;
- report = tvc->iter;
+ const Report *report = tvc->iter;
tvc->iter_char_end = report->len; /* reset start */
report_textview_init__internal(tvc);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index ebdf32a1cdb..50eb96824d7 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -31,6 +31,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "BLF_api.h"
@@ -63,6 +64,8 @@
#include "ED_info.h"
+#include "WM_api.h"
+
#include "UI_resources.h"
#include "GPU_capabilities.h"
@@ -123,12 +126,19 @@ static bool stats_mesheval(Mesh *me_eval, bool is_selected, SceneStats *stats)
return true;
}
-static void stats_object(Object *ob, SceneStats *stats, GSet *objects_gset)
+static void stats_object(Object *ob,
+ const View3D *v3d_local,
+ SceneStats *stats,
+ GSet *objects_gset)
{
if ((ob->base_flag & BASE_VISIBLE_VIEWLAYER) == 0) {
return;
}
+ if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob)) {
+ return;
+ }
+
const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
stats->totobj++;
@@ -334,7 +344,7 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
}
}
-static void stats_object_pose(Object *ob, SceneStats *stats)
+static void stats_object_pose(const Object *ob, SceneStats *stats)
{
if (ob->pose) {
bArmature *arm = ob->data;
@@ -351,16 +361,13 @@ static void stats_object_pose(Object *ob, SceneStats *stats)
}
}
-static bool stats_is_object_dynamic_topology_sculpt(Object *ob)
+static bool stats_is_object_dynamic_topology_sculpt(const Object *ob)
{
- if (ob == NULL) {
- return false;
- }
- const eObjectMode object_mode = ob->mode;
- return ((object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm);
+ BLI_assert(ob->mode & OB_MODE_SCULPT);
+ return (ob->sculpt && ob->sculpt->bm);
}
-static void stats_object_sculpt(Object *ob, SceneStats *stats)
+static void stats_object_sculpt(const Object *ob, SceneStats *stats)
{
SculptSession *ss = ob->sculpt;
@@ -386,81 +393,118 @@ static void stats_object_sculpt(Object *ob, SceneStats *stats)
}
/* Statistics displayed in info header. Called regularly on scene changes. */
-static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
+static void stats_update(Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ View3D *v3d_local,
+ SceneStats *stats)
{
- SceneStats stats = {0};
- Object *ob = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ const Object *ob = OBACT(view_layer);
+ const Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+
+ memset(stats, 0x0, sizeof(*stats));
if (obedit) {
- /* Edit Mode */
+ /* Edit Mode. */
FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) {
- if (ob_iter->mode == OB_MODE_EDIT) {
- stats_object_edit(ob_iter, &stats);
- stats.totobjsel++;
+ if (ob_iter->mode & OB_MODE_EDIT) {
+ stats_object_edit(ob_iter, stats);
+ stats->totobjsel++;
}
- stats.totobj++;
+ else {
+ /* Skip hidden objects in local view that are not in edit-mode,
+ * an exception for edit-mode, in most other modes these would be considered hidden. */
+ if ((v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob_iter))) {
+ continue;
+ }
+ }
+ stats->totobj++;
}
}
FOREACH_OBJECT_END;
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- /* Pose Mode */
- stats_object_pose(ob, &stats);
+ /* Pose Mode. */
+ FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
+ if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) {
+ if (ob_iter->mode & OB_MODE_POSE) {
+ stats_object_pose(ob_iter, stats);
+ stats->totobjsel++;
+ }
+ else {
+ /* See comment for edit-mode. */
+ if ((v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob_iter))) {
+ continue;
+ }
+ }
+ stats->totobj++;
+ }
+ }
+ FOREACH_OBJECT_END;
}
- else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- /* Dynamic topology. Do not count all vertices, dynamic topology stats are initialized later as
- * part of sculpt stats. */
+ else if (ob && (ob->mode & OB_MODE_SCULPT)) {
+ /* Sculpt Mode. */
+ if (stats_is_object_dynamic_topology_sculpt(ob)) {
+ /* Dynamic topology. Do not count all vertices,
+ * dynamic topology stats are initialized later as part of sculpt stats. */
+ }
+ else {
+ /* When dynamic topology is not enabled both sculpt stats and scene stats are collected. */
+ stats_object_sculpt(ob, stats);
+ }
}
else {
- /* Objects */
+ /* Objects. */
GSet *objects_gset = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob_iter) {
- stats_object(ob_iter, &stats, objects_gset);
+ stats_object(ob_iter, v3d_local, stats, objects_gset);
}
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
BLI_gset_free(objects_gset, NULL);
}
-
- if (ob && (ob->mode & OB_MODE_SCULPT)) {
- /* Sculpt Mode. When dynamic topology is not enabled both sculpt stats and scene stats are
- * collected. */
- stats_object_sculpt(ob, &stats);
- }
-
- if (!view_layer->stats) {
- view_layer->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
- }
-
- *(view_layer->stats) = stats;
}
-void ED_info_stats_clear(ViewLayer *view_layer)
+void ED_info_stats_clear(wmWindowManager *wm, ViewLayer *view_layer)
{
if (view_layer->stats) {
MEM_freeN(view_layer->stats);
view_layer->stats = NULL;
}
+
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ ViewLayer *view_layer_test = WM_window_get_active_view_layer(win);
+ if (view_layer != view_layer_test) {
+ continue;
+ }
+ const bScreen *screen = WM_window_get_active_screen(win);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
+ if (v3d->localvd) {
+ MEM_SAFE_FREE(v3d->runtime.local_stats);
+ }
+ }
+ }
+ }
}
-static bool format_stats(Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- SceneStatsFmt *stats_fmt)
+static bool format_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, SceneStatsFmt *stats_fmt)
{
/* Create stats if they don't already exist. */
- if (!view_layer->stats) {
+ SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats;
+ if (*stats_p == NULL) {
/* Do not not access dependency graph if interface is marked as locked. */
wmWindowManager *wm = bmain->wm.first;
if (wm->is_interface_locked) {
return false;
}
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
- stats_update(depsgraph, view_layer);
+ *stats_p = MEM_mallocN(sizeof(SceneStats), __func__);
+ stats_update(depsgraph, view_layer, v3d_local, *stats_p);
}
- SceneStats *stats = view_layer->stats;
+ SceneStats *stats = *stats_p;
/* Generate formatted numbers. */
#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt->_id, stats->_id)
@@ -605,7 +649,7 @@ static const char *info_statusbar_string(Main *bmain,
/* Scene statistics. */
if (statusbar_flag & STATUSBAR_SHOW_STATS) {
SceneStatsFmt stats_fmt;
- if (format_stats(bmain, scene, view_layer, &stats_fmt)) {
+ if (format_stats(bmain, scene, view_layer, NULL, &stats_fmt)) {
get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt);
}
}
@@ -682,11 +726,17 @@ static void stats_row(int col1,
BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
}
+/**
+ * \param v3d_local: Pass this argument to calculate view-port local statistics.
+ * Note that this must only be used for local-view, otherwise report specific statistics
+ * will be written into the global scene statistics giving incorrect results.
+ */
void ED_info_draw_stats(
- Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
+ Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
{
+ BLI_assert(v3d_local == NULL || v3d_local->localvd != NULL);
SceneStatsFmt stats_fmt;
- if (!format_stats(bmain, scene, view_layer, &stats_fmt)) {
+ if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) {
return;
}
@@ -747,8 +797,8 @@ void ED_info_draw_stats(
}
if (obedit) {
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
if (obedit->type == OB_MESH) {
- stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
@@ -763,6 +813,7 @@ void ED_info_draw_stats(
}
}
else if (ob && (object_mode & OB_MODE_POSE)) {
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else if ((ob) && (ob->type == OB_GPENCIL)) {
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 7276688e986..6143af8ed70 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -591,6 +591,7 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
snode_notify(C, snode);
snode_dag_update(C, snode);
+ DEG_relations_tag_update(bmain);
ED_node_tag_update_nodetree(bmain, ntree, texture_node);
@@ -696,6 +697,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
snode_notify(C, snode);
snode_dag_update(C, snode);
+ DEG_relations_tag_update(bmain);
ED_node_tag_update_nodetree(bmain, ntree, collection_node);
@@ -807,6 +809,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
snode_notify(C, snode);
snode_dag_update(C, snode);
+ DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
}
@@ -902,6 +905,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
snode_notify(C, snode);
snode_dag_update(C, snode);
+ DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index fd9c0f42f2d..1dc8e1412af 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -82,6 +82,7 @@
# include "COM_compositor.h"
#endif
+using blender::Map;
using blender::Set;
using blender::Span;
using blender::Vector;
@@ -1767,26 +1768,27 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
{
+ Map<bNodeSocket *, int> counts;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tosock->flag & SOCK_MULTI_INPUT) {
+ int &count = counts.lookup_or_add(link->tosock, 0);
+ count++;
+ }
+ }
+ /* Count temporary links going into this socket. */
+ LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
+ LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
+ bNodeLink *link = (bNodeLink *)linkdata->data;
+ if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) {
+ int &count = counts.lookup_or_add(link->tosock, 0);
+ count++;
+ }
+ }
+ }
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (struct bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_MULTI_INPUT) {
- Set<bNodeSocket *> visited_from_sockets;
- socket->total_inputs = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->tosock == socket) {
- visited_from_sockets.add(link->fromsock);
- }
- }
- /* Count temporary links going into this socket. */
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
- if (link->tosock == socket) {
- visited_from_sockets.add(link->fromsock);
- }
- }
- }
- socket->total_inputs = visited_from_sockets.size();
+ socket->total_inputs = counts.lookup_default(socket, 0);
}
}
}
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index d86b069aac3..b5ef250f5a9 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -177,7 +177,7 @@ static int compo_breakjob(void *cjv)
{
CompoJob *cj = (CompoJob *)cjv;
- /* without G.is_break 'ESC' wont quit - which annoys users */
+ /* without G.is_break 'ESC' won't quit - which annoys users */
return (*(cj->stop)
#ifdef USE_ESC_COMPO
|| G.is_break
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 2fcc59cde0b..8dfc43333e3 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -25,6 +25,7 @@
#include "BKE_node.h"
#include "UI_interface.h"
+#include "UI_view2d.h"
#include <stddef.h> /* for size_t */
/* internal exports only */
@@ -64,6 +65,9 @@ typedef struct bNodeLinkDrag {
/** Temporarily stores the last hovered socket for multi-input socket operator.
* Store it to recalculate sorting after it is no longer hovered. */
struct bNode *last_node_hovered_while_dragging_a_link;
+
+ /* Data for edge panning */
+ View2DEdgePanData pan_data;
} bNodeLinkDrag;
typedef struct SpaceNode_Runtime {
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 57dc0b6fef2..a1b8e4e3395 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -973,6 +973,8 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
float cursor[2];
+ UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
+
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
switch (event->type) {
@@ -1130,6 +1132,8 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
if (nldrag) {
+ UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
+
op->customdata = nldrag;
BLI_addtail(&snode->runtime->linkdrag, nldrag);
@@ -1193,6 +1197,13 @@ void NODE_OT_link(wmOperatorType *ot)
UI_PRECISION_FLOAT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ UI_view2d_edge_pan_operator_properties_ex(ot,
+ NODE_EDGE_PAN_INSIDE_PAD,
+ NODE_EDGE_PAN_OUTSIDE_PAD,
+ NODE_EDGE_PAN_SPEED_RAMP,
+ NODE_EDGE_PAN_MAX_SPEED,
+ NODE_EDGE_PAN_DELAY);
}
/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 7d889eed612..8021b45ac77 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -1365,7 +1365,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true);
PointerRNA op_ptr;
WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "outside_padding", OUTLINER_DRAG_SCOLL_OUTSIDE_PAD);
+ RNA_float_set(&op_ptr, "outside_padding", OUTLINER_DRAG_SCOLL_OUTSIDE_PAD);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
WM_operator_properties_free(&op_ptr);
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index f809bb13b42..d59d04b6ac2 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -86,6 +86,8 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "../../blender/blenloader/BLO_readfile.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -930,8 +932,14 @@ static void id_override_library_resync_fn(bContext *C,
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_resync(
- bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce, true, reports);
+ BKE_lib_override_library_resync(bmain,
+ scene,
+ CTX_data_view_layer(C),
+ id_root,
+ NULL,
+ do_hierarchy_enforce,
+ true,
+ &(struct BlendFileReadReport){.reports = reports});
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 90389fc1be2..ae455d957cf 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -312,12 +312,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
}
- outliner_add_element(space_outliner,
- &te->subtree,
- ob->poselib,
- te,
- TSE_SOME_ID,
- 0); /* XXX FIXME.. add a special type for this. */
+ /* FIXME: add a special type for this. */
+ outliner_add_element(space_outliner, &te->subtree, ob->poselib, te, TSE_SOME_ID, 0);
if (ob->proxy && !ID_IS_LINKED(ob)) {
outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 7f500597906..b6929f12cc0 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -367,8 +367,6 @@ static void draw_seq_waveform_overlay(View2D *v2d,
static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2)
{
- /* Don't use SEQ_ALL_BEGIN/SEQ_ALL_END here,
- * because it changes seq->depth, which is needed for transform. */
Sequence *seq;
uchar col[4];
@@ -2365,6 +2363,31 @@ static void draw_cache_view(const bContext *C)
}
/* Draw sequencer timeline. */
+static void draw_overlap_frame_indicator(const struct Scene *scene, const View2D *v2d)
+{
+ int overlap_frame = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ?
+ scene->ed->over_cfra :
+ scene->r.cfra + scene->ed->over_ofs;
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ /* Shader may have color set from past usage - reset it. */
+ immUniform1i("colors_len", 0);
+ immUniform1f("dash_width", 20.0f * U.pixelsize);
+ immUniform1f("dash_factor", 0.5f);
+ immUniformThemeColor(TH_CFRAME);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, overlap_frame, v2d->cur.ymin);
+ immVertex2f(pos, overlap_frame, v2d->cur.ymax);
+ immEnd();
+
+ immUnbindProgram();
+}
+
void draw_timeline_seq(const bContext *C, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -2424,31 +2447,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
cfra_flag |= DRAWCFRA_UNIT_SECONDS;
}
- /* Draw overlap frame frame indicator. */
- if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
- int overlap_frame = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ?
- scene->ed->over_cfra :
- scene->r.cfra + scene->ed->over_ofs;
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- /* Shader may have color set from past usage - reset it. */
- immUniform1i("colors_len", 0);
- immUniform1f("dash_width", 20.0f * U.pixelsize);
- immUniform1f("dash_factor", 0.5f);
- immUniformThemeColor(TH_CFRAME);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, overlap_frame, v2d->cur.ymin);
- immVertex2f(pos, overlap_frame, v2d->cur.ymax);
- immEnd();
-
- immUnbindProgram();
- }
-
UI_view2d_view_orthoSpecial(region, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
if (sseq->flag & SEQ_SHOW_MARKERS) {
@@ -2456,11 +2454,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
-
- if (ed) {
- draw_cache_view(C);
- }
-
ANIM_draw_previewrange(C, v2d, 1);
/* Draw registered callbacks. */
@@ -2486,6 +2479,13 @@ void draw_timeline_seq_display(const bContext *C, ARegion *region)
const SpaceSeq *sseq = CTX_wm_space_seq(C);
View2D *v2d = &region->v2d;
+ if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
+ UI_view2d_view_ortho(v2d);
+ draw_cache_view(C);
+ draw_overlap_frame_indicator(scene, v2d);
+ UI_view2d_view_restore(C);
+ }
+
ED_time_scrub_draw_current_frame(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
UI_view2d_scrollers_draw(v2d, NULL);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 11451091680..e17beb228de 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -34,6 +34,7 @@
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_sound_types.h"
@@ -138,6 +139,48 @@ bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq)
ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF));
}
+static bool sequencer_fcurves_targets_color_strip(const FCurve *fcurve)
+{
+ if (!BLI_str_startswith(fcurve->rna_path, "sequence_editor.sequences_all[\"")) {
+ return false;
+ }
+
+ if (!BLI_str_endswith(fcurve->rna_path, "\"].color")) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Check if there is animation shown during playback.
+ *
+ * - Colors of color strips are displayed on the strip itself.
+ * - Backdrop is drawn.
+ */
+bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
+ const struct Scene *scene)
+{
+ if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ return true;
+ }
+
+ if (!scene->adt) {
+ return false;
+ }
+ if (!scene->adt->action) {
+ return false;
+ }
+
+ LISTBASE_FOREACH (FCurve *, fcurve, &scene->adt->action->curves) {
+ if (sequencer_fcurves_targets_color_strip(fcurve)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -292,7 +335,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
/* Check meta-strips. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) &&
+ if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK) &&
SEQ_transform_sequence_can_be_translated(seq)) {
if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
SEQ_transform_translate_sequence(
@@ -314,7 +357,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
/* Test for effects and overlap. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) {
+ if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) {
seq->flag &= ~SEQ_OVERLAP;
if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
@@ -1940,7 +1983,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
seqm->machine = active_seq ? active_seq->machine : channel_max;
strcpy(seqm->name + 2, "MetaStrip");
- SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seqm);
+ SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm);
seqm->start = meta_start_frame;
seqm->len = meta_end_frame - meta_start_frame;
SEQ_time_update_sequence(scene, seqm);
@@ -2144,7 +2187,7 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
seq = ed->seqbasep->first;
while (seq) {
- if ((seq != test) && (test->machine == seq->machine) && (test->depth == seq->depth) &&
+ if ((seq != test) && (test->machine == seq->machine) &&
((sel == -1) || (sel == (seq->flag & SELECT)))) {
dist = MAXFRAME * 2;
@@ -2443,7 +2486,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
min_seq_startdisp = seq->startdisp;
}
}
- /* Paste strips after playhead. */
+ /* Paste strips relative to the current-frame. */
ofs = scene->r.cfra - min_seq_startdisp;
}
@@ -2496,7 +2539,11 @@ void SEQUENCER_OT_paste(wmOperatorType *ot)
/* Properties. */
PropertyRNA *prop = RNA_def_boolean(
- ot->srna, "keep_offset", false, "Keep Offset", "Keep strip offset to playhead when pasting");
+ ot->srna,
+ "keep_offset",
+ false,
+ "Keep Offset",
+ "Keep strip offset relative to the current frame when pasting");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -2782,7 +2829,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
RNA_END;
}
- /* Reset these else we wont see all the images. */
+ /* Reset these else we won't see all the images. */
seq->anim_startofs = seq->anim_endofs = 0;
/* Correct start/end frames so we don't move.
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index b2a0905d4a2..7e3f3db9bc8 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -20,6 +20,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../depsgraph
../../functions
@@ -40,6 +41,8 @@ set(SRC
spreadsheet_draw.cc
spreadsheet_layout.cc
spreadsheet_ops.cc
+ spreadsheet_row_filter.cc
+ spreadsheet_row_filter_ui.cc
spreadsheet_context.hh
spreadsheet_cell_value.hh
@@ -50,6 +53,8 @@ set(SRC
spreadsheet_draw.hh
spreadsheet_intern.hh
spreadsheet_layout.hh
+ spreadsheet_row_filter.hh
+ spreadsheet_row_filter_ui.hh
)
set(LIB
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 1f0b5d5d13e..8c42f28b5f4 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -49,6 +49,8 @@
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
+#include "spreadsheet_row_filter.hh"
+#include "spreadsheet_row_filter_ui.hh"
using namespace blender;
using namespace blender::ed::spreadsheet;
@@ -59,6 +61,8 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
"spreadsheet space");
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
+ spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
+
{
/* Header. */
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
@@ -76,6 +80,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
}
{
+ /* Properties region. */
+ ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region");
+ BLI_addtail(&spreadsheet_space->regionbase, region);
+ region->regiontype = RGN_TYPE_UI;
+ region->alignment = RGN_ALIGN_RIGHT;
+ region->flag = RGN_FLAG_HIDDEN;
+ }
+
+ {
/* Main window. */
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
BLI_addtail(&spreadsheet_space->regionbase, region);
@@ -88,8 +101,12 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+
MEM_SAFE_FREE(sspreadsheet->runtime);
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
+ spreadsheet_row_filter_free(row_filter);
+ }
LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
spreadsheet_column_free(column);
}
@@ -113,6 +130,11 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
sspreadsheet_new->runtime = (SpaceSpreadsheet_Runtime *)MEM_dupallocN(sspreadsheet_old->runtime);
+ BLI_listbase_clear(&sspreadsheet_new->row_filters);
+ LISTBASE_FOREACH (const SpreadsheetRowFilter *, src_filter, &sspreadsheet_old->row_filters) {
+ SpreadsheetRowFilter *new_filter = spreadsheet_row_filter_copy(src_filter);
+ BLI_addtail(&sspreadsheet_new->row_filters, new_filter);
+ }
BLI_listbase_clear(&sspreadsheet_new->columns);
LISTBASE_FOREACH (SpreadsheetColumn *, src_column, &sspreadsheet_old->columns) {
SpreadsheetColumn *new_column = spreadsheet_column_copy(src_column);
@@ -128,8 +150,10 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
return (SpaceLink *)sspreadsheet_new;
}
-static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
+static void spreadsheet_keymap(wmKeyConfig *keyconf)
{
+ /* Entire editor only. */
+ WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
}
static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
@@ -160,8 +184,15 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
- wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
- WM_event_add_keymap_handler(&region->handlers, keymap);
+ {
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
+ WM_event_add_keymap_handler(&region->handlers, keymap);
+ }
+ {
+ wmKeyMap *keymap = WM_keymap_ensure(
+ wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
+ WM_event_add_keymap_handler(&region->handlers, keymap);
+ }
}
ID *ED_spreadsheet_get_current_id(struct SpaceSpreadsheet *sspreadsheet)
@@ -346,24 +377,14 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
const ColumnValues *values = scope.add(std::move(values_ptr), __func__);
const int width = get_column_width_in_pixels(*values);
spreadsheet_layout.columns.append({values, width});
+
+ spreadsheet_column_assign_runtime_data(column, values->type(), values->name());
}
const int tot_rows = data_source->tot_rows();
spreadsheet_layout.index_column_width = get_index_column_width(tot_rows);
- spreadsheet_layout.row_indices = IndexRange(tot_rows).as_span();
-
- if (const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
- data_source.get())) {
- Object *object_eval = geometry_data_source->object_eval();
- Object *object_orig = DEG_get_original_object(object_eval);
- if (object_orig->type == OB_MESH) {
- if (object_orig->mode == OB_MODE_EDIT) {
- if (sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY) {
- spreadsheet_layout.row_indices = geometry_data_source->get_selected_element_indices();
- }
- }
- }
- }
+ spreadsheet_layout.row_indices = spreadsheet_filter_rows(
+ *sspreadsheet, spreadsheet_layout, *data_source, scope);
sspreadsheet->runtime->tot_columns = spreadsheet_layout.columns.size();
sspreadsheet->runtime->tot_rows = tot_rows;
@@ -372,9 +393,11 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_layout(spreadsheet_layout);
draw_spreadsheet_in_region(C, region, *drawer);
- /* Tag footer for redraw, because the main region updates data for the footer. */
+ /* Tag other regions for redraw, because the main region updates data for them. */
ARegion *footer = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_FOOTER);
ED_region_tag_redraw(footer);
+ ARegion *sidebar = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_UI);
+ ED_region_tag_redraw(sidebar);
}
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
@@ -511,6 +534,24 @@ static void spreadsheet_footer_region_listener(const wmRegionListenerParams *UNU
{
}
+static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
+{
+ UI_panel_category_active_set_default(region, "Filters");
+ ED_region_panels_init(wm, region);
+
+ wmKeyMap *keymap = WM_keymap_ensure(
+ wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
+ WM_event_add_keymap_handler(&region->handlers, keymap);
+}
+
+static void spreadsheet_right_region_free(ARegion *UNUSED(region))
+{
+}
+
+static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUSED(params))
+{
+}
+
void ED_spacetype_spreadsheet(void)
{
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
@@ -563,5 +604,20 @@ void ED_spacetype_spreadsheet(void)
art->listener = spreadsheet_footer_region_listener;
BLI_addhead(&st->regiontypes, art);
+ /* regions: right panel buttons */
+ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region");
+ art->regionid = RGN_TYPE_UI;
+ art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+
+ art->init = spreadsheet_sidebar_init;
+ art->layout = ED_region_panels_layout;
+ art->draw = ED_region_panels_draw;
+ art->free = spreadsheet_right_region_free;
+ art->listener = spreadsheet_right_region_listener;
+ BLI_addhead(&st->regiontypes, art);
+
+ register_row_filter_panels(*art);
+
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index de40545fdae..ee08c86b29f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -56,16 +56,29 @@ SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
return column;
}
+void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
+ const eSpreadsheetColumnValueType data_type,
+ const StringRefNull display_name)
+{
+ column->data_type = data_type;
+ MEM_SAFE_FREE(column->display_name);
+ column->display_name = BLI_strdup(display_name.c_str());
+}
+
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column)
{
SpreadsheetColumnID *new_column_id = spreadsheet_column_id_copy(src_column->id);
SpreadsheetColumn *new_column = spreadsheet_column_new(new_column_id);
+ if (src_column->display_name != nullptr) {
+ new_column->display_name = BLI_strdup(src_column->display_name);
+ }
return new_column;
}
void spreadsheet_column_free(SpreadsheetColumn *column)
{
spreadsheet_column_id_free(column->id);
+ MEM_SAFE_FREE(column->display_name);
MEM_freeN(column);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
index bb245851d55..1a03278acad 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
@@ -43,6 +43,9 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column);
+void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
+ const eSpreadsheetColumnValueType data_type,
+ const StringRefNull display_name);
void spreadsheet_column_free(SpreadsheetColumn *column);
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 373c988a41c..68370cf6a44 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -16,6 +16,8 @@
#pragma once
+#include "DNA_space_types.h"
+
#include "BLI_string_ref.hh"
#include "spreadsheet_cell_value.hh"
@@ -28,11 +30,13 @@ namespace blender::ed::spreadsheet {
*/
class ColumnValues {
protected:
+ eSpreadsheetColumnValueType type_;
std::string name_;
int size_;
public:
- ColumnValues(std::string name, const int size) : name_(std::move(name)), size_(size)
+ ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size)
+ : type_(type), name_(std::move(name)), size_(size)
{
}
@@ -40,6 +44,11 @@ class ColumnValues {
virtual void get_value(int index, CellValue &r_cell_value) const = 0;
+ eSpreadsheetColumnValueType type() const
+ {
+ return type_;
+ }
+
StringRefNull name() const
{
return name_;
@@ -60,8 +69,11 @@ template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
GetValueF get_value_;
public:
- LambdaColumnValues(std::string name, int size, GetValueF get_value)
- : ColumnValues(std::move(name), size), get_value_(std::move(get_value))
+ LambdaColumnValues(const eSpreadsheetColumnValueType type,
+ std::string name,
+ int size,
+ GetValueF get_value)
+ : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value))
{
}
@@ -73,13 +85,14 @@ template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
template<typename GetValueF>
-std::unique_ptr<ColumnValues> column_values_from_function(std::string name,
+std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColumnValueType type,
+ std::string name,
const int size,
GetValueF get_value,
const float default_width = 0.0f)
{
std::unique_ptr<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>(
- std::move(name), size, std::move(get_value));
+ type, std::move(name), size, std::move(get_value));
column_values->default_width = default_width;
return column_values;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
index de47109a144..2ea7fb5809f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
@@ -54,6 +54,15 @@ class DataSource {
}
/**
+ * Returns true if the data source has the ability to limit visible rows
+ * by user interface selection status.
+ */
+ virtual bool has_selection_filter() const
+ {
+ return false;
+ }
+
+ /**
* Returns the number of rows in columns returned by #get_column_values.
*/
virtual int tot_rows() const
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 452885959f6..0c76c8b7a15 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -69,28 +69,35 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type());
switch (type) {
case CD_PROP_FLOAT:
- return column_values_from_function(
- column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
- float value;
- varray->get(index, &value);
- r_cell_value.value_float = value;
- });
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ float value;
+ varray->get(index, &value);
+ r_cell_value.value_float = value;
+ });
case CD_PROP_INT32:
- return column_values_from_function(
- column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
- int value;
- varray->get(index, &value);
- r_cell_value.value_int = value;
- });
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_INT32,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ int value;
+ varray->get(index, &value);
+ r_cell_value.value_int = value;
+ });
case CD_PROP_BOOL:
- return column_values_from_function(
- column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
- bool value;
- varray->get(index, &value);
- r_cell_value.value_bool = value;
- });
+ return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL,
+ column_id.name,
+ domain_size,
+ [varray](int index, CellValue &r_cell_value) {
+ bool value;
+ varray->get(index, &value);
+ r_cell_value.value_bool = value;
+ });
case CD_PROP_FLOAT2: {
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_FLOAT2,
column_id.name,
domain_size,
[varray](int index, CellValue &r_cell_value) {
@@ -102,6 +109,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
case CD_PROP_FLOAT3: {
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
domain_size,
[varray](int index, CellValue &r_cell_value) {
@@ -113,6 +121,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
case CD_PROP_COLOR: {
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_COLOR,
column_id.name,
domain_size,
[varray](int index, CellValue &r_cell_value) {
@@ -137,55 +146,63 @@ using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
static void get_selected_vertex_indices(const Mesh &mesh,
const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_vertex_indices)
+ MutableSpan<bool> selection)
{
for (const int i : IndexRange(mesh.totvert)) {
- if (is_vertex_selected_fn(i)) {
- r_vertex_indices.append(i);
+ if (!selection[i]) {
+ continue;
+ }
+ if (!is_vertex_selected_fn(i)) {
+ selection[i] = false;
}
}
}
static void get_selected_corner_indices(const Mesh &mesh,
const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_corner_indices)
+ MutableSpan<bool> selection)
{
for (const int i : IndexRange(mesh.totloop)) {
const MLoop &loop = mesh.mloop[i];
- if (is_vertex_selected_fn(loop.v)) {
- r_corner_indices.append(i);
+ if (!selection[i]) {
+ continue;
+ }
+ if (!is_vertex_selected_fn(loop.v)) {
+ selection[i] = false;
}
}
}
static void get_selected_face_indices(const Mesh &mesh,
const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_face_indices)
+ MutableSpan<bool> selection)
{
for (const int poly_index : IndexRange(mesh.totpoly)) {
+ if (!selection[poly_index]) {
+ continue;
+ }
const MPoly &poly = mesh.mpoly[poly_index];
- bool is_selected = true;
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
const MLoop &loop = mesh.mloop[loop_index];
if (!is_vertex_selected_fn(loop.v)) {
- is_selected = false;
+ selection[poly_index] = false;
break;
}
}
- if (is_selected) {
- r_face_indices.append(poly_index);
- }
}
}
static void get_selected_edge_indices(const Mesh &mesh,
const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_edge_indices)
+ MutableSpan<bool> selection)
{
for (const int i : IndexRange(mesh.totedge)) {
+ if (!selection[i]) {
+ continue;
+ }
const MEdge &edge = mesh.medge[i];
- if (is_vertex_selected_fn(edge.v1) && is_vertex_selected_fn(edge.v2)) {
- r_edge_indices.append(i);
+ if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) {
+ selection[i] = false;
}
}
}
@@ -193,30 +210,48 @@ static void get_selected_edge_indices(const Mesh &mesh,
static void get_selected_indices_on_domain(const Mesh &mesh,
const AttributeDomain domain,
const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_indices)
+ MutableSpan<bool> selection)
{
switch (domain) {
case ATTR_DOMAIN_POINT:
- return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices);
+ return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection);
case ATTR_DOMAIN_FACE:
- return get_selected_face_indices(mesh, is_vertex_selected_fn, r_indices);
+ return get_selected_face_indices(mesh, is_vertex_selected_fn, selection);
case ATTR_DOMAIN_CORNER:
- return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices);
+ return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection);
case ATTR_DOMAIN_EDGE:
- return get_selected_edge_indices(mesh, is_vertex_selected_fn, r_indices);
+ return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection);
default:
return;
}
}
-Span<int64_t> GeometryDataSource::get_selected_element_indices() const
+/**
+ * Only data sets corresponding to mesh objects in edit mode currently support selection filtering.
+ */
+bool GeometryDataSource::has_selection_filter() const
+{
+ Object *object_orig = DEG_get_original_object(object_eval_);
+ if (object_orig->type != OB_MESH) {
+ return false;
+ }
+ if (object_orig->mode != OB_MODE_EDIT) {
+ return false;
+ }
+ if (component_->type() != GEO_COMPONENT_TYPE_MESH) {
+ return false;
+ }
+
+ return true;
+}
+
+void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const
{
std::lock_guard lock{mutex_};
BLI_assert(object_eval_->mode == OB_MODE_EDIT);
BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
Object *object_orig = DEG_get_original_object(object_eval_);
- Vector<int64_t> &indices = scope_.construct<Vector<int64_t>>(__func__);
const MeshComponent *mesh_component = static_cast<const MeshComponent *>(component_);
const Mesh *mesh_eval = mesh_component->get_for_read();
Mesh *mesh_orig = (Mesh *)object_orig->data;
@@ -237,7 +272,7 @@ Span<int64_t> GeometryDataSource::get_selected_element_indices() const
BMVert *vert = bm->vtable[i_orig];
return BM_elem_flag_test(vert, BM_ELEM_SELECT);
};
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, indices);
+ get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
}
else if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
@@ -245,10 +280,8 @@ Span<int64_t> GeometryDataSource::get_selected_element_indices() const
BMVert *vert = bm->vtable[vertex_index];
return BM_elem_flag_test(vert, BM_ELEM_SELECT);
};
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, indices);
+ get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
}
-
- return indices;
}
void InstancesDataSource::foreach_default_column_ids(
@@ -279,7 +312,10 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
Span<int> reference_handles = component_->instance_reference_handles();
Span<InstanceReference> references = component_->references();
std::unique_ptr<ColumnValues> values = column_values_from_function(
- "Name", size, [reference_handles, references](int index, CellValue &r_cell_value) {
+ SPREADSHEET_VALUE_TYPE_INSTANCES,
+ "Name",
+ size,
+ [reference_handles, references](int index, CellValue &r_cell_value) {
const InstanceReference &reference = references[reference_handles[index]];
switch (reference.type()) {
case InstanceReference::Type::Object: {
@@ -303,6 +339,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
Span<float4x4> transforms = component_->instance_transforms();
if (STREQ(column_id.name, "Position")) {
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
@@ -312,6 +349,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
}
if (STREQ(column_id.name, "Rotation")) {
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
@@ -321,6 +359,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
}
if (STREQ(column_id.name, "Scale")) {
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
@@ -332,6 +371,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
if (STREQ(column_id.name, "ID")) {
/* Make the column a bit wider by default, since the IDs tend to be large numbers. */
return column_values_from_function(
+ SPREADSHEET_VALUE_TYPE_INT32,
column_id.name,
size,
[ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index 273d39f27bf..d1b5dc6845e 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -58,7 +58,8 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
- Span<int64_t> get_selected_element_indices() const;
+ bool has_selection_filter() const override;
+ void apply_selection_filter(MutableSpan<bool> rows_included) const;
void foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
index 770bd207e8d..fcbc37346e6 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
@@ -14,8 +14,83 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_listbase.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "spreadsheet_intern.hh"
+#include "spreadsheet_row_filter.hh"
+
+using namespace blender::ed::spreadsheet;
+
+static int row_filter_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+
+ SpreadsheetRowFilter *row_filter = spreadsheet_row_filter_new();
+ BLI_addtail(&sspreadsheet->row_filters, row_filter);
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SPREADSHEET, sspreadsheet);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SPREADSHEET_OT_add_row_filter_rule(wmOperatorType *ot)
+{
+ ot->name = "Add Row Filter";
+ ot->description = "Add a filter to remove rows from the displayed data";
+ ot->idname = "SPREADSHEET_OT_add_row_filter_rule";
+
+ ot->exec = row_filter_add_exec;
+ ot->poll = ED_operator_spreadsheet_active;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int row_filter_remove_exec(bContext *C, wmOperator *op)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+
+ SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)BLI_findlink(
+ &sspreadsheet->row_filters, RNA_int_get(op->ptr, "index"));
+ if (row_filter == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_remlink(&sspreadsheet->row_filters, row_filter);
+ spreadsheet_row_filter_free(row_filter);
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SPREADSHEET, sspreadsheet);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SPREADSHEET_OT_remove_row_filter_rule(wmOperatorType *ot)
+{
+ ot->name = "Remove Row Filter";
+ ot->description = "Remove a row filter from the rules";
+ ot->idname = "SPREADSHEET_OT_remove_row_filter_rule";
+
+ ot->exec = row_filter_remove_exec;
+ ot->poll = ED_operator_spreadsheet_active;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
+}
void spreadsheet_operatortypes()
{
+ WM_operatortype_append(SPREADSHEET_OT_add_row_filter_rule);
+ WM_operatortype_append(SPREADSHEET_OT_remove_row_filter_rule);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
new file mode 100644
index 00000000000..ae336edfead
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -0,0 +1,366 @@
+/*
+ * 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 <cstring>
+
+#include "BLI_listbase.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "spreadsheet_intern.hh"
+
+#include "spreadsheet_data_source_geometry.hh"
+#include "spreadsheet_intern.hh"
+#include "spreadsheet_layout.hh"
+#include "spreadsheet_row_filter.hh"
+
+namespace blender::ed::spreadsheet {
+
+template<typename OperationFn>
+static void apply_filter_operation(const ColumnValues &values,
+ OperationFn check_fn,
+ MutableSpan<bool> rows_included)
+{
+ for (const int i : rows_included.index_range()) {
+ if (!rows_included[i]) {
+ continue;
+ }
+ CellValue cell_value;
+ values.get_value(i, cell_value);
+ if (!check_fn(cell_value)) {
+ rows_included[i] = false;
+ }
+ }
+}
+
+static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout,
+ const SpreadsheetRowFilter &row_filter,
+ MutableSpan<bool> rows_included)
+{
+ for (const ColumnLayout &column : spreadsheet_layout.columns) {
+ const ColumnValues &values = *column.values;
+ if (values.name() != row_filter.column_name) {
+ continue;
+ }
+
+ switch (values.type()) {
+ case SPREADSHEET_VALUE_TYPE_INT32: {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return *cell_value.value_int == value;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return *cell_value.value_int > value;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return *cell_value.value_int < value;
+ },
+ rows_included);
+ break;
+ }
+ }
+ break;
+ }
+ case SPREADSHEET_VALUE_TYPE_FLOAT: {
+ const float value = row_filter.value_float;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold = row_filter.threshold;
+ apply_filter_operation(
+ values,
+ [value, threshold](const CellValue &cell_value) -> bool {
+ return std::abs(*cell_value.value_float - value) < threshold;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return *cell_value.value_float > value;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return *cell_value.value_float < value;
+ },
+ rows_included);
+ break;
+ }
+ }
+ break;
+ }
+ case SPREADSHEET_VALUE_TYPE_FLOAT2: {
+ const float2 value = row_filter.value_float2;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_squared = row_filter.threshold * row_filter.threshold;
+ apply_filter_operation(
+ values,
+ [value, threshold_squared](const CellValue &cell_value) -> bool {
+ return float2::distance_squared(*cell_value.value_float2, value) <
+ threshold_squared;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return cell_value.value_float2->x > value.x &&
+ cell_value.value_float2->y > value.y;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return cell_value.value_float2->x < value.x &&
+ cell_value.value_float2->y < value.y;
+ },
+ rows_included);
+ break;
+ }
+ }
+ break;
+ }
+ case SPREADSHEET_VALUE_TYPE_FLOAT3: {
+ const float3 value = row_filter.value_float3;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_squared = row_filter.threshold * row_filter.threshold;
+ apply_filter_operation(
+ values,
+ [value, threshold_squared](const CellValue &cell_value) -> bool {
+ return float3::distance_squared(*cell_value.value_float3, value) <
+ threshold_squared;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return cell_value.value_float3->x > value.x &&
+ cell_value.value_float3->y > value.y &&
+ cell_value.value_float3->z > value.z;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return cell_value.value_float3->x < value.x &&
+ cell_value.value_float3->y < value.y &&
+ cell_value.value_float3->z < value.z;
+ },
+ rows_included);
+ break;
+ }
+ }
+ break;
+ }
+ case SPREADSHEET_VALUE_TYPE_COLOR: {
+ const ColorGeometry4f value = row_filter.value_color;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_squared = row_filter.threshold * row_filter.threshold;
+ apply_filter_operation(
+ values,
+ [value, threshold_squared](const CellValue &cell_value) -> bool {
+ return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared;
+ },
+ rows_included);
+ break;
+ }
+ }
+ break;
+ }
+ case SPREADSHEET_VALUE_TYPE_BOOL: {
+ const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ return *cell_value.value_bool == value;
+ },
+ rows_included);
+ break;
+ }
+ case SPREADSHEET_VALUE_TYPE_INSTANCES: {
+ const StringRef value = row_filter.value_string;
+ apply_filter_operation(
+ values,
+ [value](const CellValue &cell_value) -> bool {
+ const ID *id = nullptr;
+ if (cell_value.value_object) {
+ id = &cell_value.value_object->object->id;
+ }
+ else if (cell_value.value_collection) {
+ id = &cell_value.value_collection->collection->id;
+ }
+ if (id == nullptr) {
+ return false;
+ }
+
+ return value == id->name + 2;
+ },
+ rows_included);
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Only one column should have this name. */
+ break;
+ }
+}
+
+static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices)
+{
+ for (const int i : selection.index_range()) {
+ if (selection[i]) {
+ indices.append(i);
+ }
+ }
+}
+
+static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
+{
+ if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_ENABLE)) {
+ return false;
+ }
+ if (BLI_listbase_is_empty(&sspreadsheet.row_filters)) {
+ return false;
+ }
+ return true;
+}
+
+static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
+ const DataSource &data_source)
+{
+ if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY)) {
+ return false;
+ }
+ if (!data_source.has_selection_filter()) {
+ return false;
+ }
+ return true;
+}
+
+Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope)
+{
+ const int tot_rows = data_source.tot_rows();
+
+ const bool use_selection = use_selection_filter(sspreadsheet, data_source);
+ const bool use_filters = use_row_filters(sspreadsheet);
+
+ /* Avoid allocating an array if no row filtering is necessary. */
+ if (!(use_filters || use_selection)) {
+ return IndexRange(tot_rows).as_span();
+ }
+
+ Array<bool> rows_included(tot_rows, true);
+
+ if (use_filters) {
+ LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
+ if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
+ apply_row_filter(spreadsheet_layout, *row_filter, rows_included);
+ }
+ }
+ }
+
+ if (use_selection) {
+ const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
+ &data_source);
+ geometry_data_source->apply_selection_filter(rows_included);
+ }
+
+ Vector<int64_t> &indices = scope.construct<Vector<int64_t>>(__func__);
+ index_vector_from_bools(rows_included, indices);
+
+ return indices;
+}
+
+SpreadsheetRowFilter *spreadsheet_row_filter_new()
+{
+ SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN(
+ sizeof(SpreadsheetRowFilter), __func__);
+ row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED);
+ row_filter->operation = SPREADSHEET_ROW_FILTER_LESS;
+ row_filter->threshold = 0.01f;
+ row_filter->column_name[0] = '\0';
+
+ return row_filter;
+}
+
+SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter)
+{
+ SpreadsheetRowFilter *new_filter = spreadsheet_row_filter_new();
+
+ memcpy(new_filter, src_row_filter, sizeof(SpreadsheetRowFilter));
+ new_filter->next = nullptr;
+ new_filter->prev = nullptr;
+
+ return new_filter;
+}
+
+void spreadsheet_row_filter_free(SpreadsheetRowFilter *row_filter)
+{
+ MEM_SAFE_FREE(row_filter->value_string);
+ MEM_freeN(row_filter);
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
new file mode 100644
index 00000000000..0a5783e318d
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BLI_resource_scope.hh"
+
+#include "spreadsheet_data_source.hh"
+#include "spreadsheet_layout.hh"
+
+namespace blender::ed::spreadsheet {
+
+Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope);
+
+SpreadsheetRowFilter *spreadsheet_row_filter_new();
+SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter);
+void spreadsheet_row_filter_free(SpreadsheetRowFilter *row_filter);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
new file mode 100644
index 00000000000..dbd2ef157af
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -0,0 +1,347 @@
+/*
+ * 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 <cstring>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_ref.hh"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "spreadsheet_column.hh"
+#include "spreadsheet_intern.hh"
+#include "spreadsheet_row_filter.hh"
+#include "spreadsheet_row_filter_ui.hh"
+
+using namespace blender;
+using namespace blender::ed::spreadsheet;
+
+static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name)
+{
+ /* All row filters use the same panel ID. */
+ BLI_snprintf(r_name, BKE_ST_MAXNAME, "SPREADSHEET_PT_filter");
+}
+
+static std::string operation_string(const eSpreadsheetColumnValueType data_type,
+ const eSpreadsheetFilterOperation operation)
+{
+ if (ELEM(data_type,
+ SPREADSHEET_VALUE_TYPE_BOOL,
+ SPREADSHEET_VALUE_TYPE_INSTANCES,
+ SPREADSHEET_VALUE_TYPE_COLOR)) {
+ return "=";
+ }
+
+ switch (operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL:
+ return "=";
+ case SPREADSHEET_ROW_FILTER_GREATER:
+ return ">";
+ case SPREADSHEET_ROW_FILTER_LESS:
+ return "<";
+ }
+ BLI_assert_unreachable();
+ return "";
+}
+
+static std::string value_string(const SpreadsheetRowFilter &row_filter,
+ const eSpreadsheetColumnValueType data_type)
+{
+ switch (data_type) {
+ case SPREADSHEET_VALUE_TYPE_INT32:
+ return std::to_string(row_filter.value_int);
+ case SPREADSHEET_VALUE_TYPE_FLOAT: {
+ std::ostringstream result;
+ result.precision(3);
+ result << std::fixed << row_filter.value_float;
+ return result.str();
+ }
+ case SPREADSHEET_VALUE_TYPE_FLOAT2: {
+ std::ostringstream result;
+ result.precision(3);
+ result << std::fixed << "(" << row_filter.value_float2[0] << ", "
+ << row_filter.value_float2[1] << ")";
+ return result.str();
+ }
+ case SPREADSHEET_VALUE_TYPE_FLOAT3: {
+ std::ostringstream result;
+ result.precision(3);
+ result << std::fixed << "(" << row_filter.value_float3[0] << ", "
+ << row_filter.value_float3[1] << ", " << row_filter.value_float3[2] << ")";
+ return result.str();
+ }
+ case SPREADSHEET_VALUE_TYPE_BOOL:
+ return (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) ? IFACE_("True") :
+ IFACE_("False");
+ case SPREADSHEET_VALUE_TYPE_INSTANCES:
+ if (row_filter.value_string != nullptr) {
+ return row_filter.value_string;
+ }
+ return "";
+ case SPREADSHEET_VALUE_TYPE_COLOR:
+ std::ostringstream result;
+ result.precision(3);
+ result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1]
+ << ", " << row_filter.value_color[2] << ", " << row_filter.value_color[3] << ")";
+ return result.str();
+ }
+ BLI_assert_unreachable();
+ return "";
+}
+
+static SpreadsheetColumn *lookup_visible_column_for_filter(const SpaceSpreadsheet &sspreadsheet,
+ const StringRef column_name)
+{
+ LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet.columns) {
+ if (column->display_name == column_name) {
+ return column;
+ }
+ }
+ return nullptr;
+}
+
+static void spreadsheet_filter_panel_draw_header(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
+ const SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
+ const StringRef column_name = filter->column_name;
+ const eSpreadsheetFilterOperation operation = (eSpreadsheetFilterOperation)filter->operation;
+
+ const SpreadsheetColumn *column = lookup_visible_column_for_filter(*sspreadsheet, column_name);
+ if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE) ||
+ (column == nullptr && !column_name.is_empty())) {
+ uiLayoutSetActive(layout, false);
+ }
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
+ uiItemR(row, filter_ptr, "enabled", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+
+ if (column_name.is_empty()) {
+ uiItemL(row, IFACE_("Filter"), ICON_NONE);
+ }
+ else if (column == nullptr) {
+ uiItemL(row, column_name.data(), ICON_NONE);
+ }
+ else {
+ const eSpreadsheetColumnValueType data_type = (eSpreadsheetColumnValueType)column->data_type;
+ std::stringstream ss;
+ ss << column_name;
+ ss << " ";
+ ss << operation_string(data_type, operation);
+ ss << " ";
+ ss << value_string(*filter, data_type);
+ uiItemL(row, ss.str().c_str(), ICON_NONE);
+ }
+
+ row = uiLayoutRow(layout, true);
+ uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
+ const int current_index = BLI_findindex(&sspreadsheet->row_filters, filter);
+ uiItemIntO(row, "", ICON_X, "SPREADSHEET_OT_remove_row_filter_rule", "index", current_index);
+
+ /* Some padding so the X isn't too close to the drag icon. */
+ uiItemS_ex(layout, 0.25f);
+}
+
+static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
+ SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
+ const StringRef column_name = filter->column_name;
+ const eSpreadsheetFilterOperation operation = (eSpreadsheetFilterOperation)filter->operation;
+
+ const SpreadsheetColumn *column = lookup_visible_column_for_filter(*sspreadsheet, column_name);
+ if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE) ||
+ !(filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) ||
+ (column == nullptr && !column_name.is_empty())) {
+ uiLayoutSetActive(layout, false);
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ uiItemR(layout, filter_ptr, "column_name", 0, IFACE_("Column"), ICON_NONE);
+
+ /* Don't draw settings for filters with no corresponding visible column. */
+ if (column == nullptr || column_name.is_empty()) {
+ return;
+ }
+
+ switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) {
+ case SPREADSHEET_VALUE_TYPE_INT32:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_FLOAT:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_float", 0, IFACE_("Value"), ICON_NONE);
+ if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
+ uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ }
+ break;
+ case SPREADSHEET_VALUE_TYPE_FLOAT2:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_float2", 0, IFACE_("Value"), ICON_NONE);
+ if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
+ uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ }
+ break;
+ case SPREADSHEET_VALUE_TYPE_FLOAT3:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_float3", 0, IFACE_("Value"), ICON_NONE);
+ if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
+ uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ }
+ break;
+ case SPREADSHEET_VALUE_TYPE_BOOL:
+ uiItemR(layout, filter_ptr, "value_boolean", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_INSTANCES:
+ uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_COLOR:
+ uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE);
+ uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ break;
+ }
+}
+
+static void spreadsheet_row_filters_layout(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ ARegion *region = CTX_wm_region(C);
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ ListBase *row_filters = &sspreadsheet->row_filters;
+
+ if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE)) {
+ uiLayoutSetActive(layout, false);
+ }
+
+ uiItemO(layout, nullptr, ICON_ADD, "SPREADSHEET_OT_add_row_filter_rule");
+
+ const bool panels_match = UI_panel_list_matches_data(region, row_filters, filter_panel_id_fn);
+
+ if (!panels_match) {
+ UI_panels_free_instanced(C, region);
+ LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, row_filters) {
+ char panel_idname[MAX_NAME];
+ filter_panel_id_fn(row_filter, panel_idname);
+
+ PointerRNA *filter_ptr = (PointerRNA *)MEM_mallocN(sizeof(PointerRNA), "panel customdata");
+ RNA_pointer_create(&screen->id, &RNA_SpreadsheetRowFilter, row_filter, filter_ptr);
+
+ UI_panel_add_instanced(C, region, &region->panels, panel_idname, filter_ptr);
+ }
+ }
+ else {
+ /* Assuming there's only one group of instanced panels, update the custom data pointers. */
+ Panel *panel = (Panel *)region->panels.first;
+ LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, row_filters) {
+
+ /* Move to the next instanced panel corresponding to the next filter. */
+ while ((panel->type == nullptr) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
+ panel = panel->next;
+ BLI_assert(panel != nullptr); /* There shouldn't be fewer panels than filters. */
+ }
+
+ PointerRNA *filter_ptr = (PointerRNA *)MEM_mallocN(sizeof(PointerRNA), "panel customdata");
+ RNA_pointer_create(&screen->id, &RNA_SpreadsheetRowFilter, row_filter, filter_ptr);
+ UI_panel_custom_data_set(panel, filter_ptr);
+
+ panel = panel->next;
+ }
+ }
+}
+
+static void filter_reorder(bContext *C, Panel *panel, int new_index)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ ListBase *row_filters = &sspreadsheet->row_filters;
+ PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
+ SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
+
+ int current_index = BLI_findindex(row_filters, filter);
+ BLI_assert(current_index >= 0);
+ BLI_assert(new_index >= 0);
+
+ BLI_listbase_link_move(row_filters, filter, new_index - current_index);
+}
+
+static short get_filter_expand_flag(const bContext *UNUSED(C), Panel *panel)
+{
+ PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
+ SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
+
+ return (short)filter->flag & SPREADSHEET_ROW_FILTER_UI_EXPAND;
+}
+
+static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, short expand_flag)
+{
+ PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
+ SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
+
+ SET_FLAG_FROM_TEST(filter->flag,
+ expand_flag & SPREADSHEET_ROW_FILTER_UI_EXPAND,
+ SPREADSHEET_ROW_FILTER_UI_EXPAND);
+}
+
+void register_row_filter_panels(ARegionType &region_type)
+{
+ {
+ PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
+ strcpy(panel_type->label, N_("Filters"));
+ strcpy(panel_type->category, "Filters");
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ panel_type->flag = PANEL_TYPE_NO_HEADER;
+ panel_type->draw = spreadsheet_row_filters_layout;
+ BLI_addtail(&region_type.paneltypes, panel_type);
+ }
+
+ {
+ PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
+ strcpy(panel_type->label, "");
+ strcpy(panel_type->category, "Filters");
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ panel_type->flag = PANEL_TYPE_INSTANCED | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_HEADER_EXPAND;
+ panel_type->draw_header = spreadsheet_filter_panel_draw_header;
+ panel_type->draw = spreadsheet_filter_panel_draw;
+ panel_type->get_list_data_expand_flag = get_filter_expand_flag;
+ panel_type->set_list_data_expand_flag = set_filter_expand_flag;
+ panel_type->reorder = filter_reorder;
+ BLI_addtail(&region_type.paneltypes, panel_type);
+ }
+}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.hh
new file mode 100644
index 00000000000..e22178b63ea
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.hh
@@ -0,0 +1,21 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+struct ARegionType;
+
+void register_row_filter_panels(ARegionType &region_type);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index b5274c2357e..c9f345b3123 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -187,7 +187,7 @@ bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion
* view3d_project_short_clip and view3d_project_short_noclip in cases where
* these functions are not used during draw_object
*/
-void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
+void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
{
/* local viewmat and persmat, to calculate projections */
mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->obmat);
@@ -197,7 +197,7 @@ void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
ED_view3d_clipping_local(rv3d, ob->obmat);
}
-void ED_view3d_init_mats_rv3d_gl(struct Object *ob, struct RegionView3D *rv3d)
+void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d)
{
ED_view3d_init_mats_rv3d(ob, rv3d);
@@ -331,6 +331,8 @@ static void view3d_free(SpaceLink *sl)
MEM_freeN(vd->localvd);
}
+ MEM_SAFE_FREE(vd->runtime.local_stats);
+
if (vd->runtime.properties_storage) {
MEM_freeN(vd->runtime.properties_storage);
}
@@ -346,19 +348,25 @@ static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
+static void view3d_exit(wmWindowManager *UNUSED(wm), ScrArea *area)
+{
+ BLI_assert(area->spacetype == SPACE_VIEW3D);
+ View3D *v3d = area->spacedata.first;
+ MEM_SAFE_FREE(v3d->runtime.local_stats);
+}
+
static SpaceLink *view3d_duplicate(SpaceLink *sl)
{
View3D *v3do = (View3D *)sl;
View3D *v3dn = MEM_dupallocN(sl);
+ memset(&v3dn->runtime, 0x0, sizeof(v3dn->runtime));
+
/* clear or remove stuff from old */
if (v3dn->localvd) {
v3dn->localvd = NULL;
- v3dn->runtime.properties_storage = NULL;
}
- /* Only one View3D is allowed to have this flag! */
- v3dn->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
v3dn->local_collections_uuid = 0;
v3dn->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_XR_SESSION_MIRROR);
@@ -373,8 +381,6 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
/* copy or clear inside new stuff */
- v3dn->runtime.properties_storage = NULL;
-
return (SpaceLink *)v3dn;
}
@@ -625,6 +631,7 @@ static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_OB);
RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_boolean_set(drop->ptr, "duplicate", false);
}
static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -779,12 +786,6 @@ static void view3d_main_region_free(ARegion *region)
RE_engine_free(rv3d->render_engine);
}
- if (rv3d->depths) {
- if (rv3d->depths->depths) {
- MEM_freeN(rv3d->depths->depths);
- }
- MEM_freeN(rv3d->depths);
- }
if (rv3d->sms) {
MEM_freeN(rv3d->sms);
}
@@ -808,7 +809,6 @@ static void *view3d_main_region_duplicate(void *poin)
new->clipbb = MEM_dupallocN(rv3d->clipbb);
}
- new->depths = NULL;
new->render_engine = NULL;
new->sms = NULL;
new->smooth_timer = NULL;
@@ -1583,7 +1583,7 @@ static void space_view3d_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area))
+static void space_view3d_refresh(const bContext *C, ScrArea *area)
{
Scene *scene = CTX_data_scene(C);
LightCache *lcache = scene->eevee.light_cache_data;
@@ -1592,6 +1592,9 @@ static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area))
lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO;
view3d_lightcache_update((bContext *)C);
}
+
+ View3D *v3d = (View3D *)area->spacedata.first;
+ MEM_SAFE_FREE(v3d->runtime.local_stats);
}
const char *view3d_context_dir[] = {
@@ -1699,6 +1702,7 @@ void ED_spacetype_view3d(void)
st->create = view3d_create;
st->free = view3d_free;
st->init = view3d_init;
+ st->exit = view3d_exit;
st->listener = space_view3d_listener;
st->refresh = space_view3d_refresh;
st->duplicate = view3d_duplicate;
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index e42f6b5faac..60e1c780b9e 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -927,7 +927,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (apply_vcos) {
- EDBM_mesh_normals_update(em);
+ /* TODO: use the #BKE_editmesh_looptri_and_normals_calc_with_partial
+ * This requires begin/end states for UI interaction (which currently aren't supported). */
+ BKE_editmesh_looptri_and_normals_calc(em);
}
/* Edges */
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 0edd6aeb2ca..0b232d525fa 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -140,7 +140,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph
vctrl->persp_backup = rv3d->persp;
vctrl->dist_backup = rv3d->dist;
- /* check for flying ortho camera - which we cant support well
+ /* check for flying ortho camera - which we can't support well
* we _could_ also check for an ortho camera but this is easier */
if ((rv3d->persp == RV3D_CAMOB) && (rv3d->is_persp == false)) {
((Camera *)v3d->camera->data)->type = CAM_PERSP;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 4a595c716b6..2e46deea0e8 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1537,7 +1537,9 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) {
- ED_info_draw_stats(bmain, scene, view_layer, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
+ View3D *v3d_local = v3d->localvd ? v3d : NULL;
+ ED_info_draw_stats(
+ bmain, scene, view_layer, v3d_local, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
BLF_batch_draw_end();
@@ -2219,7 +2221,7 @@ int ED_view3d_backbuf_sample_size_clamp(ARegion *region, const float dist)
/** \name Z-Depth Utilities
* \{ */
-void view3d_update_depths_rect(ARegion *region, ViewDepths *d, rcti *rect)
+void view3d_depths_rect_create(ARegion *region, rcti *rect, ViewDepths *r_d)
{
/* clamp rect by region */
rcti r = {
@@ -2240,70 +2242,44 @@ void view3d_update_depths_rect(ARegion *region, ViewDepths *d, rcti *rect)
int h = BLI_rcti_size_y(rect);
if (w <= 0 || h <= 0) {
- if (d->depths) {
- MEM_freeN(d->depths);
- }
- d->depths = NULL;
-
- d->damaged = false;
+ r_d->depths = NULL;
+ return;
}
- else if (d->w != w || d->h != h || d->x != x || d->y != y || d->depths == NULL) {
- d->x = x;
- d->y = y;
- d->w = w;
- d->h = h;
- if (d->depths) {
- MEM_freeN(d->depths);
- }
+ r_d->x = x;
+ r_d->y = y;
+ r_d->w = w;
+ r_d->h = h;
- d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
+ r_d->depths = MEM_mallocN(sizeof(float) * w * h, "View depths Subset");
- d->damaged = true;
- }
-
- if (d->damaged) {
+ {
GPUViewport *viewport = WM_draw_region_get_viewport(region);
- view3d_opengl_read_Z_pixels(viewport, rect, d->depths);
+ view3d_opengl_read_Z_pixels(viewport, rect, r_d->depths);
/* Range is assumed to be this as they are never changed. */
- d->depth_range[0] = 0.0;
- d->depth_range[1] = 1.0;
- d->damaged = false;
+ r_d->depth_range[0] = 0.0;
+ r_d->depth_range[1] = 1.0;
}
}
/* Note, with nouveau drivers the glReadPixels() is very slow. T24339. */
-static void view3d_depth_cache_update(ARegion *region)
+static ViewDepths *view3d_depths_create(ARegion *region)
{
- RegionView3D *rv3d = region->regiondata;
-
- /* Create storage for, and, if necessary, copy depth buffer. */
- if (!rv3d->depths) {
- rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
- }
- if (rv3d->depths) {
- ViewDepths *d = rv3d->depths;
- if (d->w != region->winx || d->h != region->winy || !d->depths) {
- d->w = region->winx;
- d->h = region->winy;
- if (d->depths) {
- MEM_freeN(d->depths);
- }
- d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
- d->damaged = true;
- }
+ ViewDepths *d = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
+ d->w = region->winx;
+ d->h = region->winy;
+ d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
- if (d->damaged) {
- GPUViewport *viewport = WM_draw_region_get_viewport(region);
- DefaultFramebufferList *fbl = GPU_viewport_framebuffer_list_get(viewport);
- GPU_framebuffer_read_depth(fbl->depth_only_fb, 0, 0, d->w, d->h, GPU_DATA_FLOAT, d->depths);
+ {
+ GPUViewport *viewport = WM_draw_region_get_viewport(region);
+ DefaultFramebufferList *fbl = GPU_viewport_framebuffer_list_get(viewport);
+ GPU_framebuffer_read_depth(fbl->depth_only_fb, 0, 0, d->w, d->h, GPU_DATA_FLOAT, d->depths);
- /* Assumed to be this as they are never changed. */
- d->depth_range[0] = 0.0;
- d->depth_range[1] = 1.0;
- d->damaged = false;
- }
+ /* Assumed to be this as they are never changed. */
+ d->depth_range[0] = 0.0;
+ d->depth_range[1] = 1.0;
}
+ return d;
}
/* Utility function to find the closest Z value, use for auto-depth. */
@@ -2343,10 +2319,13 @@ void ED_view3d_depth_override(Depsgraph *depsgraph,
View3D *v3d,
Object *obact,
eV3DDepthOverrideMode mode,
- bool update_cache)
+ ViewDepths **r_depths)
{
if (v3d->runtime.flag & V3D_RUNTIME_DEPTHBUF_OVERRIDDEN) {
- return;
+ /* Force redraw if `r_depths` is required. */
+ if (!r_depths || *r_depths != NULL) {
+ return;
+ }
}
struct bThemeState theme_state;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
@@ -2388,12 +2367,11 @@ void ED_view3d_depth_override(Depsgraph *depsgraph,
break;
}
- if (rv3d->depths != NULL) {
- rv3d->depths->damaged = true;
- /* TODO: Clear cache? */
- }
- if (update_cache) {
- view3d_depth_cache_update(region);
+ if (r_depths) {
+ if (*r_depths) {
+ ED_view3d_depths_free(*r_depths);
+ }
+ *r_depths = view3d_depths_create(region);
}
}
@@ -2407,6 +2385,14 @@ void ED_view3d_depth_override(Depsgraph *depsgraph,
UI_Theme_Restore(&theme_state);
}
+void ED_view3d_depths_free(ViewDepths *depths)
+{
+ if (depths->depths) {
+ MEM_freeN(depths->depths);
+ }
+ MEM_freeN(depths);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 8b6d0e9ee04..53fc7eed43b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -509,7 +509,7 @@ 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 you'll
- * always be able to zoom into it and panning wont go bad when dist was zero. */
+ * always be able to zoom into it and panning won't go bad when dist was zero. */
/* remove dist value */
upvec[0] = upvec[1] = 0;
@@ -895,7 +895,7 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
copy_qt_qt(rv3d->viewquat, vod->curr.viewquat);
/* check for view snap,
- * note: don't apply snap to vod->viewquat so the view wont jam up */
+ * note: don't apply snap to vod->viewquat so the view won't jam up */
if (vod->axis_snap) {
viewrotate_apply_snap(vod);
}
@@ -953,7 +953,6 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_depth_tag_update(vod->rv3d);
use_autokey = true;
ret = OPERATOR_FINISHED;
}
@@ -1014,7 +1013,6 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
viewrotate_apply(vod, event_xy);
- ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -1799,7 +1797,6 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_depth_tag_update(vod->rv3d);
use_autokey = true;
ret = OPERATOR_FINISHED;
}
@@ -1840,7 +1837,6 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEPAN) {
/* invert it, trackpad scroll follows same principle as 2d windows this way */
viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
- ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -2254,7 +2250,6 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_depth_tag_update(vod->rv3d);
use_autokey = true;
ret = OPERATOR_FINISHED;
}
@@ -2341,8 +2336,6 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
view3d_boxview_sync(area, region);
}
- ED_view3d_depth_tag_update(rv3d);
-
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
@@ -2398,8 +2391,6 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
- ED_view3d_depth_tag_update(vod->rv3d);
-
viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -2579,7 +2570,6 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_depth_tag_update(vod->rv3d);
use_autokey = true;
ret = OPERATOR_FINISHED;
}
@@ -2636,8 +2626,6 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
view3d_boxview_sync(area, region);
}
- ED_view3d_depth_tag_update(rv3d);
-
ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d);
ED_region_tag_redraw(region);
@@ -2718,7 +2706,6 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->prevx;
}
viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0);
- ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
return OPERATOR_FINISHED;
@@ -3629,13 +3616,13 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
ED_view3d_dist_range_get(v3d, dist_range);
ED_view3d_depth_override(
- CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false);
+ CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
{
/* avoid allocating the whole depth buffer */
ViewDepths depth_temp = {0};
/* avoid view3d_update_depths() for speed. */
- view3d_update_depths_rect(region, &depth_temp, &rect);
+ view3d_depths_rect_create(region, &rect, &depth_temp);
/* find the closest Z pixel */
depth_close = view3d_depth_near(&depth_temp);
@@ -3660,7 +3647,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
if (rv3d->is_persp) {
float p_corner[3];
- /* no depths to use, we cant do anything! */
+ /* no depths to use, we can't do anything! */
if (depth_close == FLT_MAX) {
BKE_report(op->reports, RPT_ERROR, "Depth too large");
return OPERATOR_CANCELLED;
@@ -4433,7 +4420,6 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_depth_tag_update(vod->rv3d);
use_autokey = true;
ret = OPERATOR_FINISHED;
}
@@ -4541,7 +4527,6 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEROTATE) {
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
viewroll_apply(vod, event->prevx, event->prevy);
- ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
return OPERATOR_FINISHED;
@@ -4638,7 +4623,6 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y);
- ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 2d499cf85c7..d42746c168c 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -772,7 +772,7 @@ static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
float moffset[2]; /* mouse offset from the views center */
float tmp_quat[4]; /* used for rotating the view */
- /* x and y margin are define the safe area where the mouses movement wont rotate the view */
+ /* x and y margin defining the safe area where the mouse's movement won't rotate the view */
int xmargin, ymargin;
#ifdef NDOF_FLY_DEBUG
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 4d8102af6ff..16c83b45924 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -86,12 +86,12 @@ static void gizmo_bbone_offset_get(const wmGizmo *UNUSED(gz),
if (bh->index == 0) {
bh->co[1] = pchan->bone->ease1 / BBONE_SCALE_Y;
bh->co[0] = pchan->curve_in_x;
- bh->co[2] = pchan->curve_in_y;
+ bh->co[2] = pchan->curve_in_z;
}
else {
bh->co[1] = -pchan->bone->ease2 / BBONE_SCALE_Y;
bh->co[0] = pchan->curve_out_x;
- bh->co[2] = pchan->curve_out_y;
+ bh->co[2] = pchan->curve_out_z;
}
copy_v3_v3(value, bh->co);
}
@@ -111,12 +111,12 @@ static void gizmo_bbone_offset_set(const wmGizmo *UNUSED(gz),
if (bh->index == 0) {
pchan->bone->ease1 = max_ff(0.0f, bh->co[1] * BBONE_SCALE_Y);
pchan->curve_in_x = bh->co[0];
- pchan->curve_in_y = bh->co[2];
+ pchan->curve_in_z = bh->co[2];
}
else {
pchan->bone->ease2 = max_ff(0.0f, -bh->co[1] * BBONE_SCALE_Y);
pchan->curve_out_x = bh->co[0];
- pchan->curve_out_y = bh->co[2];
+ pchan->curve_out_z = bh->co[2];
}
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 6f07cb8b44d..0964c2dcbcc 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -137,7 +137,7 @@ void ED_view3d_draw_depth_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
View3D *v3d);
-void view3d_update_depths_rect(struct ARegion *region, struct ViewDepths *d, struct rcti *rect);
+void view3d_depths_rect_create(struct ARegion *region, struct rcti *rect, struct ViewDepths *r_d);
float view3d_depth_near(struct ViewDepths *d);
/* view3d_select.c */
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index bdb2c3874db..2a381bb96cb 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -50,15 +50,179 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Clipping Utilities
+ * \{ */
+
+/**
+ * Calculate clipping planes to use when #V3D_PROJ_TEST_CLIP_CONTENT is enabled.
+ *
+ * Planes are selected from the viewpoint using `clip_flag`
+ * to detect which planes should be applied (maximum 6).
+ *
+ * \return The number of planes written into `planes`.
+ */
+static int content_planes_from_clip_flag(const ARegion *region,
+ const Object *ob,
+ const eV3DProjTest clip_flag,
+ float planes[6][4])
+{
+ BLI_assert(clip_flag & V3D_PROJ_TEST_CLIP_CONTENT);
+
+ float *clip_xmin = NULL, *clip_xmax = NULL;
+ float *clip_ymin = NULL, *clip_ymax = NULL;
+ float *clip_zmin = NULL, *clip_zmax = NULL;
+
+ int planes_len = 0;
+
+ /* The order of `planes` has been selected based on the likelihood of points being fully
+ * outside the plane to increase the chance of an early exit in #clip_segment_v3_plane_n.
+ * With "near" being most likely and "far" being unlikely.
+ *
+ * Otherwise the order of axes in `planes` isn't significant. */
+
+ if (clip_flag & V3D_PROJ_TEST_CLIP_NEAR) {
+ clip_zmin = planes[planes_len++];
+ }
+ if (clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
+ clip_xmin = planes[planes_len++];
+ clip_xmax = planes[planes_len++];
+ clip_ymin = planes[planes_len++];
+ clip_ymax = planes[planes_len++];
+ }
+ if (clip_flag & V3D_PROJ_TEST_CLIP_FAR) {
+ clip_zmax = planes[planes_len++];
+ }
+
+ BLI_assert(planes_len <= 6);
+ if (planes_len != 0) {
+ RegionView3D *rv3d = region->regiondata;
+ float projmat[4][4];
+ ED_view3d_ob_project_mat_get(rv3d, ob, projmat);
+ planes_from_projmat(projmat, clip_xmin, clip_xmax, clip_ymin, clip_ymax, clip_zmin, clip_zmax);
+ }
+ return planes_len;
+}
+
+/**
+ * Edge projection is more involved since part of the edge may be behind the view
+ * or extend beyond the far limits. In the case of single points, these can be ignored.
+ * However it just may still be visible on screen, so constrained the edge to planes
+ * defined by the port to ensure both ends of the edge can be projected, see T32214.
+ *
+ * \note This is unrelated to #V3D_PROJ_TEST_CLIP_BB which must be checked separately.
+ */
+static bool view3d_project_segment_to_screen_with_content_clip_planes(
+ const ARegion *region,
+ const float v_a[3],
+ const float v_b[3],
+ const eV3DProjTest clip_flag,
+ const rctf *win_rect,
+ const float content_planes[][4],
+ const int content_planes_len,
+ /* Output. */
+ float r_screen_co_a[2],
+ float r_screen_co_b[2])
+{
+ /* Clipping already handled, no need to check in projection. */
+ eV3DProjTest clip_flag_nowin = clip_flag & ~V3D_PROJ_TEST_CLIP_WIN;
+
+ const eV3DProjStatus status_a = ED_view3d_project_float_object(
+ region, v_a, r_screen_co_a, clip_flag_nowin);
+ const eV3DProjStatus status_b = ED_view3d_project_float_object(
+ region, v_b, r_screen_co_b, clip_flag_nowin);
+
+ if ((status_a == V3D_PROJ_RET_OK) && (status_b == V3D_PROJ_RET_OK)) {
+ if (clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
+ if (!BLI_rctf_isect_segment(win_rect, r_screen_co_a, r_screen_co_b)) {
+ return false;
+ }
+ }
+ }
+ else {
+ if (content_planes_len == 0) {
+ return false;
+ }
+
+ /* Both too near, ignore. */
+ if ((status_a & V3D_PROJ_TEST_CLIP_NEAR) && (status_b & V3D_PROJ_TEST_CLIP_NEAR)) {
+ return false;
+ }
+
+ /* Both too far, ignore. */
+ if ((status_a & V3D_PROJ_TEST_CLIP_FAR) && (status_b & V3D_PROJ_TEST_CLIP_FAR)) {
+ return false;
+ }
+
+ /* Simple cases have been ruled out, clip by viewport planes, then re-project. */
+ float v_a_clip[3], v_b_clip[3];
+ if (!clip_segment_v3_plane_n(
+ v_a, v_b, content_planes, content_planes_len, v_a_clip, v_b_clip)) {
+ return false;
+ }
+
+ if ((ED_view3d_project_float_object(region, v_a_clip, r_screen_co_a, clip_flag_nowin) !=
+ V3D_PROJ_RET_OK) ||
+ (ED_view3d_project_float_object(region, v_b_clip, r_screen_co_b, clip_flag_nowin) !=
+ V3D_PROJ_RET_OK)) {
+ return false;
+ }
+
+ /* No need for #V3D_PROJ_TEST_CLIP_WIN check here,
+ * clipping the segment by planes handle this. */
+ }
+
+ return true;
+}
+
+/**
+ * Project an edge, points that fail to project are tagged with #IS_CLIPPED.
+ */
+static bool view3d_project_segment_to_screen_with_clip_tag(const ARegion *region,
+ const float v_a[3],
+ const float v_b[3],
+ const eV3DProjTest clip_flag,
+ /* Output. */
+ float r_screen_co_a[2],
+ float r_screen_co_b[2])
+{
+ int count = 0;
+
+ if (ED_view3d_project_float_object(region, v_a, r_screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
+ count++;
+ }
+ else {
+ r_screen_co_a[0] = IS_CLIPPED; /* weak */
+ /* screen_co_a[1]: intentionally don't set this so we get errors on misuse */
+ }
+
+ if (ED_view3d_project_float_object(region, v_b, r_screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
+ count++;
+ }
+ else {
+ r_screen_co_b[0] = IS_CLIPPED; /* weak */
+ /* screen_co_b[1]: intentionally don't set this so we get errors on misuse */
+ }
+
+ /* Caller may want to know this value, for now it's not needed. */
+ return count != 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Private User Data Structures
+ * \{ */
+
typedef struct foreachScreenObjectVert_userData {
- void (*func)(void *userData, MVert *mv, const float screen_co_b[2], int index);
+ void (*func)(void *userData, MVert *mv, const float screen_co[2], int index);
void *userData;
ViewContext vc;
eV3DProjTest clip_flag;
} foreachScreenObjectVert_userData;
typedef struct foreachScreenVert_userData {
- void (*func)(void *userData, BMVert *eve, const float screen_co_b[2], int index);
+ void (*func)(void *userData, BMVert *eve, const float screen_co[2], int index);
void *userData;
ViewContext vc;
eV3DProjTest clip_flag;
@@ -73,8 +237,16 @@ typedef struct foreachScreenEdge_userData {
int index);
void *userData;
ViewContext vc;
- rctf win_rect; /* copy of: vc.region->winx/winy, use for faster tests, minx/y will always be 0 */
eV3DProjTest clip_flag;
+
+ rctf win_rect; /* copy of: vc.region->winx/winy, use for faster tests, minx/y will always be 0 */
+
+ /**
+ * Clip plans defined by the the view bounds,
+ * use when #V3D_PROJ_TEST_CLIP_CONTENT is enabled.
+ */
+ float content_planes[6][4];
+ int content_planes_len;
} foreachScreenEdge_userData;
typedef struct foreachScreenFace_userData {
@@ -91,7 +263,11 @@ typedef struct foreachScreenFace_userData {
* use the object matrix in the usual way.
*/
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh: For Each Screen Vertex
+ * \{ */
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
@@ -120,6 +296,7 @@ void meshobject_foreachScreenVert(
void *userData,
eV3DProjTest clip_flag)
{
+ BLI_assert((clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) == 0);
foreachScreenObjectVert_userData data;
Mesh *me;
@@ -150,17 +327,17 @@ static void mesh_foreachScreenVert__mapFunc(void *userData,
{
foreachScreenVert_userData *data = userData;
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
+ if (UNLIKELY(BM_elem_flag_test(eve, BM_ELEM_HIDDEN))) {
+ return;
+ }
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- float screen_co[2];
-
- if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
- V3D_PROJ_RET_OK) {
- return;
- }
-
- data->func(data->userData, eve, screen_co, index);
+ float screen_co[2];
+ if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
+ V3D_PROJ_RET_OK) {
+ return;
}
+
+ data->func(data->userData, eve, screen_co, index);
}
void mesh_foreachScreenVert(
@@ -189,38 +366,37 @@ void mesh_foreachScreenVert(
BKE_mesh_foreach_mapped_vert(me, mesh_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh: For Each Screen Mesh Edge
+ * \{ */
static void mesh_foreachScreenEdge__mapFunc(void *userData,
int index,
- const float v0co[3],
- const float v1co[3])
+ const float v_a[3],
+ const float v_b[3])
{
foreachScreenEdge_userData *data = userData;
BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
+ if (UNLIKELY(BM_elem_flag_test(eed, BM_ELEM_HIDDEN))) {
+ return;
+ }
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float screen_co_a[2];
- float screen_co_b[2];
- eV3DProjTest clip_flag_nowin = data->clip_flag & ~V3D_PROJ_TEST_CLIP_WIN;
-
- if (ED_view3d_project_float_object(data->vc.region, v0co, screen_co_a, clip_flag_nowin) !=
- V3D_PROJ_RET_OK) {
- return;
- }
- if (ED_view3d_project_float_object(data->vc.region, v1co, screen_co_b, clip_flag_nowin) !=
- V3D_PROJ_RET_OK) {
- return;
- }
-
- if (data->clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
- if (!BLI_rctf_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) {
- return;
- }
- }
-
- data->func(data->userData, eed, screen_co_a, screen_co_b, index);
+ float screen_co_a[2], screen_co_b[2];
+ if (!view3d_project_segment_to_screen_with_content_clip_planes(data->vc.region,
+ v_a,
+ v_b,
+ data->clip_flag,
+ &data->win_rect,
+ data->content_planes,
+ data->content_planes_len,
+ screen_co_a,
+ screen_co_b)) {
+ return;
}
+
+ data->func(data->userData, eed, screen_co_a, screen_co_b, index);
}
void mesh_foreachScreenEdge(ViewContext *vc,
@@ -254,11 +430,23 @@ void mesh_foreachScreenEdge(ViewContext *vc,
ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
}
+ if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
+ data.content_planes_len = content_planes_from_clip_flag(
+ vc->region, vc->obedit, clip_flag, data.content_planes);
+ }
+ else {
+ data.content_planes_len = 0;
+ }
+
BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh: For Each Screen Edge (Bounding Box Clipped)
+ * \{ */
/**
* Only call for bound-box clipping.
@@ -266,46 +454,36 @@ void mesh_foreachScreenEdge(ViewContext *vc,
*/
static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData,
int index,
- const float v0co[3],
- const float v1co[3])
+ const float v_a[3],
+ const float v_b[3])
{
foreachScreenEdge_userData *data = userData;
BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index);
+ if (UNLIKELY(BM_elem_flag_test(eed, BM_ELEM_HIDDEN))) {
+ return;
+ }
BLI_assert(data->clip_flag & V3D_PROJ_TEST_CLIP_BB);
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float v0co_clip[3];
- float v1co_clip[3];
-
- if (!clip_segment_v3_plane_n(v0co, v1co, data->vc.rv3d->clip_local, 4, v0co_clip, v1co_clip)) {
- return;
- }
-
- float screen_co_a[2];
- float screen_co_b[2];
-
- /* Clipping already handled, no need to check in projection. */
- eV3DProjTest clip_flag_nowin = data->clip_flag &
- ~(V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_BB);
-
- if (ED_view3d_project_float_object(data->vc.region, v0co_clip, screen_co_a, clip_flag_nowin) !=
- V3D_PROJ_RET_OK) {
- return;
- }
- if (ED_view3d_project_float_object(data->vc.region, v1co_clip, screen_co_b, clip_flag_nowin) !=
- V3D_PROJ_RET_OK) {
- return;
- }
-
- if (data->clip_flag & V3D_PROJ_TEST_CLIP_WIN) {
- if (!BLI_rctf_isect_segment(&data->win_rect, screen_co_a, screen_co_b)) {
- return;
- }
- }
+ float v_a_clip[3], v_b_clip[3];
+ if (!clip_segment_v3_plane_n(v_a, v_b, data->vc.rv3d->clip_local, 4, v_a_clip, v_b_clip)) {
+ return;
+ }
- data->func(data->userData, eed, screen_co_a, screen_co_b, index);
+ float screen_co_a[2], screen_co_b[2];
+ if (!view3d_project_segment_to_screen_with_content_clip_planes(data->vc.region,
+ v_a_clip,
+ v_b_clip,
+ data->clip_flag,
+ &data->win_rect,
+ data->content_planes,
+ data->content_planes_len,
+ screen_co_a,
+ screen_co_b)) {
+ return;
}
+
+ data->func(data->userData, eed, screen_co_a, screen_co_b, index);
}
/**
@@ -339,6 +517,14 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
data.userData = userData;
data.clip_flag = clip_flag;
+ if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
+ data.content_planes_len = content_planes_from_clip_flag(
+ vc->region, vc->obedit, clip_flag, data.content_planes);
+ }
+ else {
+ data.content_planes_len = 0;
+ }
+
BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) {
@@ -350,7 +536,11 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
}
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh: For Each Screen Face Center
+ * \{ */
static void mesh_foreachScreenFace__mapFunc(void *userData,
int index,
@@ -359,14 +549,17 @@ static void mesh_foreachScreenFace__mapFunc(void *userData,
{
foreachScreenFace_userData *data = userData;
BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
+ if (UNLIKELY(BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
+ return;
+ }
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- float screen_co[2];
- if (ED_view3d_project_float_object(data->vc.region, cent, screen_co, data->clip_flag) ==
- V3D_PROJ_RET_OK) {
- data->func(data->userData, efa, screen_co, index);
- }
+ float screen_co[2];
+ if (ED_view3d_project_float_object(data->vc.region, cent, screen_co, data->clip_flag) !=
+ V3D_PROJ_RET_OK) {
+ return;
}
+
+ data->func(data->userData, efa, screen_co, index);
}
void mesh_foreachScreenFace(
@@ -375,6 +568,7 @@ void mesh_foreachScreenFace(
void *userData,
const eV3DProjTest clip_flag)
{
+ BLI_assert((clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) == 0);
foreachScreenFace_userData data;
Mesh *me = editbmesh_get_eval_cage_from_orig(
@@ -398,7 +592,11 @@ void mesh_foreachScreenFace(
}
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Nurbs: For Each Screen Vertex
+ * \{ */
void nurbs_foreachScreenVert(ViewContext *vc,
void (*func)(void *userData,
@@ -486,7 +684,11 @@ void nurbs_foreachScreenVert(ViewContext *vc,
}
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Meta: For Each Screen Meta-Element
+ * \{ */
/* ED_view3d_init_mats_rv3d must be called first */
void mball_foreachScreenElem(struct ViewContext *vc,
@@ -510,7 +712,11 @@ void mball_foreachScreenElem(struct ViewContext *vc,
}
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Lattice: For Each Screen Vertex
+ * \{ */
void lattice_foreachScreenVert(ViewContext *vc,
void (*func)(void *userData, BPoint *bp, const float screen_co[2]),
@@ -543,7 +749,11 @@ void lattice_foreachScreenVert(ViewContext *vc,
}
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Armature: For Each Screen Bone
+ * \{ */
/* ED_view3d_init_mats_rv3d must be called first */
void armature_foreachScreenBone(struct ViewContext *vc,
@@ -559,39 +769,59 @@ void armature_foreachScreenBone(struct ViewContext *vc,
ED_view3d_check_mats_rv3d(vc->rv3d);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- float screen_co_a[2], screen_co_b[2];
- int points_proj_tot = 0;
+ float content_planes[6][4];
+ int content_planes_len;
+ rctf win_rect;
+
+ if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
+ content_planes_len = content_planes_from_clip_flag(
+ vc->region, vc->obedit, clip_flag, content_planes);
+ win_rect.xmin = 0;
+ win_rect.ymin = 0;
+ win_rect.xmax = vc->region->winx;
+ win_rect.ymax = vc->region->winy;
+ }
+ else {
+ content_planes_len = 0;
+ }
- /* project head location to screenspace */
- if (ED_view3d_project_float_object(vc->region, ebone->head, screen_co_a, clip_flag) ==
- V3D_PROJ_RET_OK) {
- points_proj_tot++;
- }
- else {
- screen_co_a[0] = IS_CLIPPED; /* weak */
- /* screen_co_a[1]: intentionally don't set this so we get errors on misuse */
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (!EBONE_VISIBLE(arm, ebone)) {
+ continue;
+ }
- /* project tail location to screenspace */
- if (ED_view3d_project_float_object(vc->region, ebone->tail, screen_co_b, clip_flag) ==
- V3D_PROJ_RET_OK) {
- points_proj_tot++;
- }
- else {
- screen_co_b[0] = IS_CLIPPED; /* weak */
- /* screen_co_b[1]: intentionally don't set this so we get errors on misuse */
+ float screen_co_a[2], screen_co_b[2];
+ const float *v_a = ebone->head, *v_b = ebone->tail;
+
+ if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
+ if (!view3d_project_segment_to_screen_with_content_clip_planes(vc->region,
+ v_a,
+ v_b,
+ clip_flag,
+ &win_rect,
+ content_planes,
+ content_planes_len,
+ screen_co_a,
+ screen_co_b)) {
+ continue;
}
-
- if (points_proj_tot) { /* at least one point's projection worked */
- func(userData, ebone, screen_co_a, screen_co_b);
+ }
+ else {
+ if (!view3d_project_segment_to_screen_with_clip_tag(
+ vc->region, v_a, v_b, clip_flag, screen_co_a, screen_co_b)) {
+ continue;
}
}
+
+ func(userData, ebone, screen_co_a, screen_co_b);
}
}
-/* ------------------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose: For Each Screen Bone
+ * \{ */
/* ED_view3d_init_mats_rv3d must be called first */
/* almost _exact_ copy of #armature_foreachScreenBone */
@@ -610,35 +840,53 @@ void pose_foreachScreenBone(struct ViewContext *vc,
ED_view3d_check_mats_rv3d(vc->rv3d);
+ float content_planes[6][4];
+ int content_planes_len;
+ rctf win_rect;
+
+ if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
+ content_planes_len = content_planes_from_clip_flag(
+ vc->region, ob_eval, clip_flag, content_planes);
+ win_rect.xmin = 0;
+ win_rect.ymin = 0;
+ win_rect.xmax = vc->region->winx;
+ win_rect.ymax = vc->region->winy;
+ }
+ else {
+ content_planes_len = 0;
+ }
+
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_VISIBLE(arm_eval, pchan->bone)) {
- bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
- float screen_co_a[2], screen_co_b[2];
- int points_proj_tot = 0;
-
- /* project head location to screenspace */
- if (ED_view3d_project_float_object(
- vc->region, pchan_eval->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
- points_proj_tot++;
- }
- else {
- screen_co_a[0] = IS_CLIPPED; /* weak */
- /* screen_co_a[1]: intentionally don't set this so we get errors on misuse */
- }
+ if (!PBONE_VISIBLE(arm_eval, pchan->bone)) {
+ continue;
+ }
- /* project tail location to screenspace */
- if (ED_view3d_project_float_object(
- vc->region, pchan_eval->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
- points_proj_tot++;
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ float screen_co_a[2], screen_co_b[2];
+ const float *v_a = pchan_eval->pose_head, *v_b = pchan_eval->pose_tail;
+
+ if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) {
+ if (!view3d_project_segment_to_screen_with_content_clip_planes(vc->region,
+ v_a,
+ v_b,
+ clip_flag,
+ &win_rect,
+ content_planes,
+ content_planes_len,
+ screen_co_a,
+ screen_co_b)) {
+ continue;
}
- else {
- screen_co_b[0] = IS_CLIPPED; /* weak */
- /* screen_co_b[1]: intentionally don't set this so we get errors on misuse */
- }
-
- if (points_proj_tot) { /* at least one point's projection worked */
- func(userData, pchan, screen_co_a, screen_co_b);
+ }
+ else {
+ if (!view3d_project_segment_to_screen_with_clip_tag(
+ vc->region, v_a, v_b, clip_flag, screen_co_a, screen_co_b)) {
+ continue;
}
}
+
+ func(userData, pchan, screen_co_a, screen_co_b);
}
}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index e602521f6a2..04f382de56b 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -961,7 +961,7 @@ static void view3d_interactive_add_calc_plane(bContext *C,
const float view_axis_dot = fabsf(dot_v3v3(rv3d->viewinv[2], r_matrix_orient[plane_axis]));
if (view_axis_dot < eps_view_align) {
/* In this case, just project onto the view plane as it's important the location
- * is _always_ under the mouse cursor, even if it turns out that wont lie on
+ * is _always_ under the mouse cursor, even if it turns out that won't lie on
* the original 'plane' that's been calculated for us. */
plane_normal = rv3d->viewinv[2];
}
@@ -974,7 +974,7 @@ static void view3d_interactive_add_calc_plane(bContext *C,
/* Even if the calculation works, it's possible the point found is behind the view,
* or very far away (past the far clipping).
- * In either case creating objects wont be useful. */
+ * In either case creating objects won't be useful. */
if (rv3d->is_persp) {
float dir[3];
sub_v3_v3v3(dir, rv3d->viewinv[3], r_co_src);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 7547f8ee434..49da1764660 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -788,7 +788,7 @@ bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
/** \name Utility functions for projection
* \{ */
-void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float r_pmat[4][4])
+void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob, float r_pmat[4][4])
{
float vmat[4][4];
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 757ed13ac28..02ed9f6d791 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -520,42 +520,16 @@ static void do_lasso_select_pose__do_tag(void *userData,
const float screen_co_b[2])
{
LassoSelectUserData *data = userData;
- bArmature *arm = data->vc->obact->data;
-
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- bool is_point_done = false;
- int points_proj_tot = 0;
-
- /* project head location to screenspace */
- if (screen_co_a[0] != IS_CLIPPED) {
- points_proj_tot++;
- if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
- is_point_done = true;
- }
- }
-
- /* project tail location to screenspace */
- if (screen_co_b[0] != IS_CLIPPED) {
- points_proj_tot++;
- if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
- is_point_done = true;
- }
- }
+ const bArmature *arm = data->vc->obact->data;
+ if (!PBONE_SELECTABLE(arm, pchan->bone)) {
+ return;
+ }
- /* if one of points selected, we skip the bone itself */
- if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) &&
- BLI_lasso_is_edge_inside(data->mcoords,
- data->mcoords_len,
- UNPACK2(screen_co_a),
- UNPACK2(screen_co_b),
- INT_MAX))) {
- pchan->bone->flag |= BONE_DONE;
- }
- data->is_changed |= is_point_done;
+ if (BLI_rctf_isect_segment(data->rect_fl, screen_co_a, screen_co_b) &&
+ BLI_lasso_is_edge_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ pchan->bone->flag |= BONE_DONE;
+ data->is_changed = true;
}
}
static void do_lasso_tag_pose(ViewContext *vc,
@@ -580,7 +554,11 @@ static void do_lasso_tag_pose(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
- pose_foreachScreenBone(&vc_tmp, do_lasso_select_pose__do_tag, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ /* Treat bones as clipped segments (no joints). */
+ pose_foreachScreenBone(&vc_tmp,
+ do_lasso_select_pose__do_tag,
+ &data,
+ V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
}
static bool do_lasso_select_objects(ViewContext *vc,
@@ -876,11 +854,16 @@ static bool do_lasso_select_mesh(ViewContext *vc,
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
(use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
+ /* Fully inside. */
mesh_foreachScreenEdge_clip_bb_segment(
vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
if (data.is_done == false) {
- mesh_foreachScreenEdge_clip_bb_segment(
- vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, clip_flag);
+ /* Fall back to partially inside.
+ * Clip content to account for edges partially behind the view. */
+ mesh_foreachScreenEdge_clip_bb_segment(vc,
+ do_lasso_select_mesh__doSelectEdge_pass1,
+ &data_for_edge,
+ clip_flag | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
}
}
@@ -1022,46 +1005,76 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
const float screen_co_b[2])
{
LassoSelectUserData *data = userData;
- bArmature *arm = data->vc->obedit->data;
- if (EBONE_VISIBLE(arm, ebone)) {
- int is_ignore_flag = 0;
- int is_inside_flag = 0;
-
- if (screen_co_a[0] != IS_CLIPPED) {
- if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
- is_inside_flag |= BONESEL_ROOT;
- }
- }
- else {
- is_ignore_flag |= BONESEL_ROOT;
- }
+ const bArmature *arm = data->vc->obedit->data;
+ if (!EBONE_VISIBLE(arm, ebone)) {
+ return;
+ }
- if (screen_co_b[0] != IS_CLIPPED) {
- if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
- is_inside_flag |= BONESEL_TIP;
- }
+ int is_ignore_flag = 0;
+ int is_inside_flag = 0;
+
+ if (screen_co_a[0] != IS_CLIPPED) {
+ if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
+ is_inside_flag |= BONESEL_ROOT;
}
- else {
- is_ignore_flag |= BONESEL_TIP;
+ }
+ else {
+ is_ignore_flag |= BONESEL_ROOT;
+ }
+
+ if (screen_co_b[0] != IS_CLIPPED) {
+ if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
+ is_inside_flag |= BONESEL_TIP;
}
+ }
+ else {
+ is_ignore_flag |= BONESEL_TIP;
+ }
- if (is_ignore_flag == 0) {
- if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
- BLI_lasso_is_edge_inside(data->mcoords,
- data->mcoords_len,
- UNPACK2(screen_co_a),
- UNPACK2(screen_co_b),
- INT_MAX)) {
- is_inside_flag |= BONESEL_BONE;
- }
+ if (is_ignore_flag == 0) {
+ if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX)) {
+ is_inside_flag |= BONESEL_BONE;
}
+ }
+
+ ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
+}
+static void do_lasso_select_armature__doSelectBone_clip_content(void *userData,
+ EditBone *ebone,
+ const float screen_co_a[2],
+ const float screen_co_b[2])
+{
+ LassoSelectUserData *data = userData;
+ bArmature *arm = data->vc->obedit->data;
+ if (!EBONE_VISIBLE(arm, ebone)) {
+ return;
+ }
+
+ const int is_ignore_flag = ebone->temp.i << 16;
+ int is_inside_flag = ebone->temp.i & ~0xFFFF;
- ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
+ /* - When #BONESEL_BONE is set, there is nothing to do.
+ * - When #BONE_ROOTSEL or #BONE_TIPSEL have been set - they take priority over bone selection.
+ */
+ if (is_inside_flag & (BONESEL_BONE | BONE_ROOTSEL | BONE_TIPSEL)) {
+ return;
+ }
+
+ if (BLI_lasso_is_edge_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ is_inside_flag |= BONESEL_BONE;
}
+
+ ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
}
static bool do_lasso_select_armature(ViewContext *vc,
@@ -1086,9 +1099,18 @@ static bool do_lasso_select_armature(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ /* Operate on fully visible (non-clipped) points. */
armature_foreachScreenBone(
vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ /* Operate on bones as segments clipped to the viewport bounds
+ * (needed to handle bones with both points outside the view).
+ * A separate pass is needed since clipped coordinates can't be used for selecting joints. */
+ armature_foreachScreenBone(vc,
+ do_lasso_select_armature__doSelectBone_clip_content,
+ &data,
+ V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
+
data.is_changed |= ED_armature_edit_select_op_from_tagged(vc->obedit->data, sel_op);
if (data.is_changed) {
@@ -3071,6 +3093,9 @@ struct BoxSelectUserData_ForMeshEdge {
struct EditSelectBuf_Cache *esel;
uint backbuf_offset;
};
+/**
+ * Pass 0 operates on edges when fully inside.
+ */
static void do_mesh_box_select__doSelectEdge_pass0(
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
@@ -3092,6 +3117,9 @@ static void do_mesh_box_select__doSelectEdge_pass0(
data->is_changed = true;
}
}
+/**
+ * Pass 1 operates on edges when partially inside.
+ */
static void do_mesh_box_select__doSelectEdge_pass1(
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
@@ -3181,11 +3209,16 @@ static bool do_mesh_box_select(ViewContext *vc,
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
(use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
+ /* Fully inside. */
mesh_foreachScreenEdge_clip_bb_segment(
vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
if (data.is_done == false) {
- mesh_foreachScreenEdge_clip_bb_segment(
- vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, clip_flag);
+ /* Fall back to partially inside.
+ * Clip content to account for edges partially behind the view. */
+ mesh_foreachScreenEdge_clip_bb_segment(vc,
+ do_mesh_box_select__doSelectEdge_pass1,
+ &cb_data,
+ clip_flag | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
}
}
@@ -3725,6 +3758,9 @@ static bool mesh_circle_select(ViewContext *vc,
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
+ vc->em->bm->totvertsel = 0;
+ vc->em->bm->totedgesel = 0;
+ vc->em->bm->totfacesel = 0;
changed = true;
}
}
@@ -3771,7 +3807,10 @@ static bool mesh_circle_select(ViewContext *vc,
}
else {
mesh_foreachScreenEdge_clip_bb_segment(
- vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+ vc,
+ mesh_circle_doSelectEdge,
+ &data,
+ (V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT));
}
}
@@ -3790,7 +3829,8 @@ static bool mesh_circle_select(ViewContext *vc,
changed |= data.is_changed;
if (changed) {
- EDBM_selectmode_flush(vc->em);
+ BM_mesh_select_mode_flush_ex(
+ vc->em->bm, vc->em->selectmode, BM_SELECT_LEN_FLUSH_RECALC_NOTHING);
}
return changed;
}
@@ -4016,47 +4056,48 @@ static void do_circle_select_pose__doSelectBone(void *userData,
{
CircleSelectUserData *data = userData;
bArmature *arm = data->vc->obact->data;
+ if (!PBONE_SELECTABLE(arm, pchan->bone)) {
+ return;
+ }
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- bool is_point_done = false;
- int points_proj_tot = 0;
+ bool is_point_done = false;
+ int points_proj_tot = 0;
- /* project head location to screenspace */
- if (screen_co_a[0] != IS_CLIPPED) {
- points_proj_tot++;
- if (pchan_circle_doSelectJoint(data, pchan, screen_co_a)) {
- is_point_done = true;
- }
+ /* project head location to screenspace */
+ if (screen_co_a[0] != IS_CLIPPED) {
+ points_proj_tot++;
+ if (pchan_circle_doSelectJoint(data, pchan, screen_co_a)) {
+ is_point_done = true;
}
+ }
- /* project tail location to screenspace */
- if (screen_co_b[0] != IS_CLIPPED) {
- points_proj_tot++;
- if (pchan_circle_doSelectJoint(data, pchan, screen_co_b)) {
- is_point_done = true;
- }
+ /* project tail location to screenspace */
+ if (screen_co_b[0] != IS_CLIPPED) {
+ points_proj_tot++;
+ if (pchan_circle_doSelectJoint(data, pchan, screen_co_b)) {
+ is_point_done = true;
}
+ }
- /* check if the head and/or tail is in the circle
- * - the call to check also does the selection already
- */
+ /* check if the head and/or tail is in the circle
+ * - the call to check also does the selection already
+ */
- /* only if the endpoints didn't get selected, deal with the middle of the bone too
- * It works nicer to only do this if the head or tail are not in the circle,
- * otherwise there is no way to circle select joints alone */
- if ((is_point_done == false) && (points_proj_tot == 2) &&
- edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
- if (data->select) {
- pchan->bone->flag |= BONE_SELECTED;
- }
- else {
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- data->is_changed = true;
+ /* only if the endpoints didn't get selected, deal with the middle of the bone too
+ * It works nicer to only do this if the head or tail are not in the circle,
+ * otherwise there is no way to circle select joints alone */
+ if ((is_point_done == false) && (points_proj_tot == 2) &&
+ edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
+ if (data->select) {
+ pchan->bone->flag |= BONE_SELECTED;
}
-
- data->is_changed |= is_point_done;
+ else {
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ data->is_changed = true;
}
+
+ data->is_changed |= is_point_done;
}
static bool pose_circle_select(ViewContext *vc,
const eSelectOp sel_op,
@@ -4075,8 +4116,11 @@ static bool pose_circle_select(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
- pose_foreachScreenBone(
- vc, do_circle_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ /* Treat bones as clipped segments (no joints). */
+ pose_foreachScreenBone(vc,
+ do_circle_select_pose__doSelectBone,
+ &data,
+ V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
if (data.is_changed) {
ED_pose_bone_select_tag_update(vc->obact);
@@ -4118,47 +4162,74 @@ static void do_circle_select_armature__doSelectBone(void *userData,
const float screen_co_b[2])
{
CircleSelectUserData *data = userData;
- bArmature *arm = data->vc->obedit->data;
+ const bArmature *arm = data->vc->obedit->data;
+ if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) {
+ return;
+ }
- if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
- bool is_point_done = false;
- int points_proj_tot = 0;
+ /* When true, ignore in the next pass. */
+ ebone->temp.i = false;
- /* project head location to screenspace */
- if (screen_co_a[0] != IS_CLIPPED) {
- points_proj_tot++;
- if (armature_circle_doSelectJoint(data, ebone, screen_co_a, true)) {
- is_point_done = true;
- }
+ bool is_point_done = false;
+ bool is_edge_done = false;
+ int points_proj_tot = 0;
+
+ /* project head location to screenspace */
+ if (screen_co_a[0] != IS_CLIPPED) {
+ points_proj_tot++;
+ if (armature_circle_doSelectJoint(data, ebone, screen_co_a, true)) {
+ is_point_done = true;
}
+ }
- /* project tail location to screenspace */
- if (screen_co_b[0] != IS_CLIPPED) {
- points_proj_tot++;
- if (armature_circle_doSelectJoint(data, ebone, screen_co_b, false)) {
- is_point_done = true;
- }
+ /* project tail location to screenspace */
+ if (screen_co_b[0] != IS_CLIPPED) {
+ points_proj_tot++;
+ if (armature_circle_doSelectJoint(data, ebone, screen_co_b, false)) {
+ is_point_done = true;
}
+ }
- /* check if the head and/or tail is in the circle
- * - the call to check also does the selection already
- */
+ /* check if the head and/or tail is in the circle
+ * - the call to check also does the selection already
+ */
- /* only if the endpoints didn't get selected, deal with the middle of the bone too
- * It works nicer to only do this if the head or tail are not in the circle,
- * otherwise there is no way to circle select joints alone */
- if ((is_point_done == false) && (points_proj_tot == 2) &&
- edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
- if (data->select) {
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- data->is_changed = true;
- }
+ /* only if the endpoints didn't get selected, deal with the middle of the bone too
+ * It works nicer to only do this if the head or tail are not in the circle,
+ * otherwise there is no way to circle select joints alone */
+ if ((is_point_done == false) && (points_proj_tot == 2) &&
+ edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
+ SET_FLAG_FROM_TEST(ebone->flag, data->select, BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ is_edge_done = true;
+ data->is_changed = true;
+ }
+
+ if (is_point_done || is_edge_done) {
+ ebone->temp.i = true;
+ }
+
+ data->is_changed |= is_point_done;
+}
+static void do_circle_select_armature__doSelectBone_clip_content(void *userData,
+ struct EditBone *ebone,
+ const float screen_co_a[2],
+ const float screen_co_b[2])
+{
+ CircleSelectUserData *data = userData;
+ bArmature *arm = data->vc->obedit->data;
- data->is_changed |= is_point_done;
+ if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) {
+ return;
+ }
+
+ /* Set in the first pass, needed so circle select prioritizes joints. */
+ if (ebone->temp.i == true) {
+ return;
+ }
+
+ if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
+ SET_FLAG_FROM_TEST(ebone->flag, data->select, BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ data->is_changed = true;
}
}
static bool armature_circle_select(ViewContext *vc,
@@ -4179,9 +4250,18 @@ static bool armature_circle_select(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ /* Operate on fully visible (non-clipped) points. */
armature_foreachScreenBone(
vc, do_circle_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ /* Operate on bones as segments clipped to the viewport bounds
+ * (needed to handle bones with both points outside the view).
+ * A separate pass is needed since clipped coordinates can't be used for selecting joints. */
+ armature_foreachScreenBone(vc,
+ do_circle_select_armature__doSelectBone_clip_content,
+ &data,
+ V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
+
if (data.is_changed) {
ED_armature_edit_sync_selection(arm->edbo);
ED_armature_edit_validate_active(arm);
@@ -4362,7 +4442,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
FOREACH_OBJECT_IN_MODE_END;
}
else if (obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) {
- if (PE_circle_select(C, sel_op, mval, (float)radius)) {
+ if (PE_circle_select(C, wm_userdata, sel_op, mval, (float)radius)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 8ae5d4a29e9..ea0b1f396c3 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -1017,7 +1017,7 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int
}
ViewDepths depth_temp = {0};
- view3d_update_depths_rect(region, &depth_temp, &rect);
+ view3d_depths_rect_create(region, &rect, &depth_temp);
float depth_close = view3d_depth_near(&depth_temp);
MEM_SAFE_FREE(depth_temp.depths);
return depth_close;
@@ -1044,7 +1044,7 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
- ED_view3d_depth_override(depsgraph, region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false);
+ ED_view3d_depth_override(depsgraph, region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
/* Attempt with low margin's first */
int i = 0;
@@ -1694,7 +1694,8 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
return false;
}
-bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
+bool ED_view3d_depth_read_cached_normal(const ARegion *region,
+ const ViewDepths *depths,
const int mval[2],
float r_normal[3])
{
@@ -1705,9 +1706,6 @@ bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
bool depths_valid[9] = {false};
float coords[9][3] = {{0}};
- ARegion *region = vc->region;
- const ViewDepths *depths = vc->rv3d->depths;
-
for (int x = 0, i = 0; x < 2; x++) {
for (int y = 0; y < 2; y++) {
const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
@@ -1761,11 +1759,4 @@ bool ED_view3d_depth_unproject_v3(const ARegion *region,
return ED_view3d_unproject_v3(region, centx, centy, depth, r_location_world);
}
-void ED_view3d_depth_tag_update(RegionView3D *rv3d)
-{
- if (rv3d->depths) {
- rv3d->depths->damaged = true;
- }
-}
-
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 21cb8560e9b..056b2507745 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -235,7 +235,7 @@ void ED_view3d_smooth_view_ex(
/* grid draw as floor */
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
/* use existing if exists, means multiple calls to smooth view
- * wont lose the original 'view' setting */
+ * won't lose the original 'view' setting */
rv3d->view = RV3D_VIEW_USER;
}
@@ -244,7 +244,7 @@ void ED_view3d_smooth_view_ex(
/* if this is view rotation only
* we can decrease the time allowed by
* the angle between quats
- * this means small rotations wont lag */
+ * this means small rotations won't lag */
if (sview->quat && !sview->ofs && !sview->dist) {
/* scale the time allowed by the rotation */
/* 180deg == 1.0 */
@@ -1393,6 +1393,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
MEM_freeN(v3d->localvd);
v3d->localvd = NULL;
+ MEM_SAFE_FREE(v3d->runtime.local_stats);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
@@ -1516,7 +1517,7 @@ static int localview_remove_from_exec(bContext *C, wmOperator *op)
}
if (changed) {
- DEG_on_visible_update(bmain, false);
+ DEG_tag_on_visible_update(bmain, false);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index f0ced665679..2b26ef3b3e4 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -149,6 +149,9 @@ typedef enum {
T_AUTOMERGE = 1 << 20,
/** Runs auto-merge & splits. */
T_AUTOSPLIT = 1 << 21,
+
+ /** No cursor wrapping on region bounds */
+ T_NO_CURSOR_WRAP = 1 << 23,
} eTFlag;
/** #TransInfo.modifiers */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index aaea9d05f84..f29f323558a 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -1449,9 +1449,9 @@ void recalcData_pose(TransInfo *t)
/* TODO: autokeyframe calls need some setting to specify to add samples
* (FPoints) instead of keyframes? */
if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
- int targetless_ik =
- (t->flag &
- T_AUTOIK); /* XXX this currently doesn't work, since flags aren't set yet! */
+
+ /* XXX: this currently doesn't work, since flags aren't set yet! */
+ int targetless_ik = (t->flag & T_AUTOIK);
animrecord_check_state(t, ob);
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index e57fd85470f..cc3091ae70e 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -453,7 +453,7 @@ void recalcData_curve(TransInfo *t)
if (t->state == TRANS_CANCEL) {
while (nu) {
- /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
+ /* Can't do testhandlesNurb here, it messes up the h1 and h2 flags */
BKE_nurb_handles_calc(nu);
nu = nu->next;
}
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 422370cb13b..4c674136b6a 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1842,13 +1842,11 @@ void recalcData_mesh(TransInfo *t)
* It's impractical to calculate this ahead of time.
* Further, the down side of using partial updates when their not needed is negligible. */
if (em->bm->totvert == em->bm->totvertsel) {
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
+ BKE_editmesh_looptri_and_normals_calc(em);
}
else {
BMPartialUpdate *partial_update_cache = tc_mesh_ensure_partial_update(t, tc);
- BM_mesh_normals_update_with_partial(em->bm, partial_update_cache);
- BKE_editmesh_looptri_calc_with_partial(em, partial_update_cache);
+ BKE_editmesh_looptri_and_normals_calc_with_partial(em, partial_update_cache);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index 7c61da31f72..69b44998980 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -300,8 +300,7 @@ void recalcData_mesh_skin(TransInfo *t)
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
+ BKE_editmesh_looptri_and_normals_calc(em);
}
}
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index 12c4d0816ae..9d2d3713bf0 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -27,6 +27,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
#include "BKE_node.h"
@@ -35,6 +36,7 @@
#include "ED_node.h"
#include "UI_interface.h"
+#include "UI_view2d.h"
#include "transform.h"
#include "transform_convert.h"
@@ -44,6 +46,12 @@
/** \name Node Transform Creation
* \{ */
+typedef struct NodeTransCustomData {
+ /* Initial rect of the view2d, used for computing offset during edge panning */
+ rctf initial_v2d_cur;
+ View2DEdgePanData edge_pan;
+} NodeTransCustomData;
+
/* transcribe given node into TransData2D for Transforming */
static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
{
@@ -107,6 +115,24 @@ void createTransNodeData(TransInfo *t)
const float dpi_fac = UI_DPI_FAC;
SpaceNode *snode = t->area->spacedata.first;
+ if (t->mode == TFM_TRANSLATION) {
+ /* Disable cursor wrapping in the node editor for edge pan */
+ t->flag |= T_NO_CURSOR_WRAP;
+ }
+
+ /* Custom data to enable edge panning during the node transform */
+ NodeTransCustomData *customdata = MEM_callocN(sizeof(*customdata), __func__);
+ UI_view2d_edge_pan_init(t->context,
+ &customdata->edge_pan,
+ NODE_EDGE_PAN_INSIDE_PAD,
+ NODE_EDGE_PAN_OUTSIDE_PAD,
+ NODE_EDGE_PAN_SPEED_RAMP,
+ NODE_EDGE_PAN_MAX_SPEED,
+ NODE_EDGE_PAN_DELAY);
+ customdata->initial_v2d_cur = t->region->v2d.cur;
+ t->custom.type.data = customdata;
+ t->custom.type.use_free = true;
+
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
tc->data_len = 0;
@@ -150,6 +176,19 @@ void flushTransNodes(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
+ NodeTransCustomData *customdata = (NodeTransCustomData *)t->custom.type.data;
+
+ if (t->mode == TFM_TRANSLATION) {
+ /* Edge panning functions expect window coordinates, mval is relative to region */
+ const float x = t->region->winrct.xmin + t->mval[0];
+ const float y = t->region->winrct.ymin + t->mval[1];
+ UI_view2d_edge_pan_apply(t->context, &customdata->edge_pan, x, y);
+ }
+
+ /* Initial and current view2D rects for additional transform due to view panning and zooming */
+ const rctf *rect_src = &customdata->initial_v2d_cur;
+ const rctf *rect_dst = &t->region->v2d.cur;
+
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
applyGridAbsolute(t);
@@ -159,23 +198,28 @@ void flushTransNodes(TransInfo *t)
TransData2D *td2d = &tc->data_2d[i];
bNode *node = td->extra;
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+ float loc[2];
+ copy_v2_v2(loc, td2d->loc);
+
+ /* additional offset due to change in view2D rect */
+ BLI_rctf_transform_pt_v(rect_dst, rect_src, loc, loc);
+
#ifdef USE_NODE_CENTER
- float locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
- float locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
-#else
- float locx = td2d->loc[0] / dpi_fac;
- float locy = td2d->loc[1] / dpi_fac;
+ loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr);
+ loc[1] += 0.5f * BLI_rctf_size_y(&node->totr);
#endif
+ /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+ loc[0] /= dpi_fac;
+ loc[1] /= dpi_fac;
+
/* account for parents (nested nodes) */
if (node->parent) {
- nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
- }
- else {
- node->locx = locx;
- node->locy = locy;
+ nodeFromView(node->parent, loc[0], loc[1], &loc[0], &loc[1]);
}
+
+ node->locx = loc[0];
+ node->locy = loc[1];
}
/* handle intersection with noodles */
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 6a09008e657..a67d18db37b 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -33,6 +33,7 @@
#include "ED_markers.h"
+#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@@ -76,12 +77,9 @@ typedef struct TransSeq {
/* This function applies the rules for transforming a strip so duplicate
* checks don't need to be added in multiple places.
*
- * recursive, count and flag MUST be set.
- *
- * seq->depth must be set before running this function so we know if the strips
- * are root level or not
+ * count and flag MUST be set.
*/
-static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_count, int *r_flag)
+static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag)
{
/* for extend we need to do some tricks */
if (t->mode == TFM_TIME_EXTEND) {
@@ -93,13 +91,11 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c
int left = SEQ_transform_get_left_handle_frame(seq);
int right = SEQ_transform_get_right_handle_frame(seq);
- if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
- *r_recursive = false;
+ if (((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
*r_count = 0;
*r_flag = 0;
}
else {
- *r_recursive = false;
*r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */
*r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
@@ -131,61 +127,34 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c
/* *** Normal Transform *** */
- if (seq->depth == 0) {
-
- /* Count */
+ /* Count */
- /* Non nested strips (resect selection and handles) */
- if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
- *r_recursive = false;
- *r_count = 0;
- *r_flag = 0;
+ /* Non nested strips (resect selection and handles) */
+ if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
+ *r_count = 0;
+ *r_flag = 0;
+ }
+ else {
+ if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ *r_flag = seq->flag;
+ *r_count = 2; /* we need 2 transdata's */
}
else {
- if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- *r_flag = seq->flag;
- *r_count = 2; /* we need 2 transdata's */
- }
- else {
- *r_flag = seq->flag;
- *r_count = 1; /* selected or with a handle selected */
- }
-
- /* Recursive */
-
- if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
- /* if any handles are selected, don't recurse */
- *r_recursive = true;
- }
- else {
- *r_recursive = false;
- }
+ *r_flag = seq->flag;
+ *r_count = 1; /* selected or with a handle selected */
}
}
- else {
- /* Nested, different rules apply */
-
- *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *r_count = 1; /* ignore the selection for nested */
- *r_recursive = (seq->type == SEQ_TYPE_META);
- }
}
}
-static int SeqTransCount(TransInfo *t, ListBase *seqbase, int depth)
+static int SeqTransCount(TransInfo *t, ListBase *seqbase)
{
Sequence *seq;
- int tot = 0, recursive, count, flag;
+ int tot = 0, count, flag;
for (seq = seqbase->first; seq; seq = seq->next) {
- seq->depth = depth;
-
- SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */
+ SeqTransInfo(t, seq, &count, &flag); /* ignore the flag */
tot += count;
-
- if (recursive) {
- tot += SeqTransCount(t, &seq->seqbase, depth + 1);
- }
}
return tot;
@@ -251,27 +220,16 @@ static TransData *SeqToTransData(
return td;
}
-static int SeqToTransData_Recursive(
+static int SeqToTransData_build(
TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
{
Sequence *seq;
- int recursive, count, flag;
+ int count, flag;
int tot = 0;
for (seq = seqbase->first; seq; seq = seq->next) {
- SeqTransInfo(t, seq, &recursive, &count, &flag);
-
- /* add children first so recalculating metastrips does nested strips first */
- if (recursive) {
- int tot_children = SeqToTransData_Recursive(t, &seq->seqbase, td, td2d, tdsq);
-
- td = td + tot_children;
- td2d = td2d + tot_children;
- tdsq = tdsq + tot_children;
-
- tot += tot_children;
- }
+ SeqTransInfo(t, seq, &count, &flag);
/* use 'flag' which is derived from seq->flag but modified for special cases */
if (flag & SELECT) {
@@ -297,13 +255,13 @@ static int SeqToTransData_Recursive(
static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
{
Sequence *seq;
- int recursive, count, flag;
+ int count, flag;
int max = INT32_MIN, min = INT32_MAX;
for (seq = seqbase->first; seq; seq = seq->next) {
/* just to get the flag since there are corner cases where this isn't totally obvious */
- SeqTransInfo(t, seq, &recursive, &count, &flag);
+ SeqTransInfo(t, seq, &count, &flag);
/* use 'flag' which is derived from seq->flag but modified for special cases */
if (flag & SELECT) {
@@ -330,188 +288,199 @@ static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
}
}
-static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
+static void free_transform_custom_data(TransCustomData *custom_data)
{
- Editing *ed = SEQ_editing_get(t->scene, false);
+ if ((custom_data->data != NULL) && custom_data->use_free) {
+ TransSeq *ts = custom_data->data;
+ MEM_freeN(ts->tdseq);
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
+ }
+}
+
+/* Canceled, need to update the strips display. */
+static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips)
+{
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ SEQ_time_update_sequence_bounds(t->scene, seq);
+ }
+}
- if (ed != NULL) {
+static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
+{
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if (seq->flag & SEQ_OVERLAP) {
+ return true;
+ }
+ }
+ return false;
+}
- ListBase *seqbasep = ed->seqbasep;
- TransData *td = tc->data;
- int a;
+static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_collection_create();
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
- /* prevent updating the same seq twice
- * if the transdata order is changed this will mess up
- * but so will TransDataSeq */
- Sequence *seq_prev = NULL;
+/* Query strips positioned after left edge of transformed strips boundbox. */
+static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
+{
+ int minframe = MAXFRAME;
+ {
Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ minframe = min_ii(minframe, seq->startdisp);
+ }
+ }
- if (!(t->state == TRANS_CANCEL)) {
+ SeqCollection *collection = SEQ_collection_create();
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if ((seq->flag & SELECT) == 0 && seq->startdisp >= minframe) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
-#if 0 /* Default 2.4 behavior. */
+static void seq_transform_update_effects(TransInfo *t, SeqCollection *collection)
+{
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
+ SEQ_time_update_sequence(t->scene, seq);
+ }
+ }
+}
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0; a < t->total; a++, td++) {
- if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
- seq = ((TransDataSeq *)td->extra)->seq;
- SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene);
- }
+/* Check if effect strips with input are transformed. */
+static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips)
+{
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
+ return true;
+ }
+ }
+ return false;
+}
- seq_prev = seq;
- }
+/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal
+ * to overlap of transformed strips. */
+static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips)
+{
+ Editing *ed = SEQ_editing_get(t->scene, false);
+ ListBase *seqbasep = SEQ_active_seqbase_get(ed);
+ ListBase *markers = &t->scene->markers;
+ const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
+ SEQ_MARKER_TRANS) != 0;
-#else /* durian hack */
- {
- int overlap = 0;
+ SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips);
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
- overlap = 1;
- break;
- }
- }
+ /* Temporarily move right side strips beyond timeline boundary. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine += MAXSEQ * 2;
+ }
- if (overlap) {
- const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
- SEQ_MARKER_TRANS) != 0;
- ListBase *markers = &t->scene->markers;
+ /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
+ * strips on left side. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, seqbasep, t->scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
- bool has_effect_root = false, has_effect_any = false;
- for (seq = seqbasep->first; seq; seq = seq->next) {
- seq->tmp = NULL;
- }
+ /* Move temporarily moved strips back to their original place and tag for shuffling. */
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine -= MAXSEQ * 2;
+ }
+ /* Shuffle again to displace strips on right side. Final effect shuffling is done in
+ * seq_transform_handle_overlap. */
+ SEQ_transform_seqbase_shuffle_time(
+ right_side_strips, seqbasep, t->scene, markers, use_sync_markers);
+ seq_transform_update_effects(t, right_side_strips);
+ SEQ_collection_free(right_side_strips);
+}
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
- /* check effects strips, we cant change their time */
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect_any = true;
- if (seq->depth == 0) {
- has_effect_root = true;
- }
- }
- else {
- /* Tag seq with a non zero value, used by
- * SEQ_transform_seqbase_shuffle_time to identify the ones to shuffle */
- if (seq->depth == 0) {
- seq->tmp = (void *)1;
- }
- }
- }
- }
+static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transformed_strips)
+{
+ Editing *ed = SEQ_editing_get(t->scene, false);
+ ListBase *seqbasep = SEQ_active_seqbase_get(ed);
- if (t->flag & T_ALT_TRANSFORM) {
- int minframe = MAXFRAME;
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- minframe = min_ii(minframe, seq->startdisp);
- }
- }
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (!(seq->flag & SELECT)) {
- if (seq->startdisp >= minframe) {
- seq->machine += MAXSEQ * 2;
- }
- }
- }
-
- SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->machine >= MAXSEQ * 2) {
- seq->machine -= MAXSEQ * 2;
- seq->tmp = (void *)1;
- }
- else {
- seq->tmp = NULL;
- }
- }
-
- SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
- }
- else {
- SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
- }
+ if (t->flag & T_ALT_TRANSFORM) {
+ seq_transform_handle_expand_to_fit(t, transformed_strips);
+ }
+ else {
+ ListBase *markers = &t->scene->markers;
+ const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
+ SEQ_MARKER_TRANS) != 0;
+ /* Shuffle non strips with no effects attached. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, seqbasep, t->scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+ }
- if (has_effect_any) {
- /* update effects strips based on strips just moved in time */
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- SEQ_time_update_sequence(t->scene, seq);
- }
- }
- }
- }
+ if (seq_transform_check_strip_effects(transformed_strips)) {
+ /* Update effect strips based on strips just moved in time. */
+ seq_transform_update_effects(t, transformed_strips);
- if (has_effect_root) {
- /* now if any effects _still_ overlap, we need to move them up */
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
- SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene);
- }
- }
- }
- }
- /* done with effects */
- }
+ /* If any effects still overlap, we need to move them up. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene);
}
}
-#endif
+ }
+ }
+}
- for (seq = seqbasep->first; seq; seq = seq->next) {
- /* We might want to build a list of effects that need to be updated during transform */
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->flag & SELECT) {
- SEQ_time_update_sequence(t->scene, seq);
- }
- else if (seq->seq2 && seq->seq2->flag & SELECT) {
- SEQ_time_update_sequence(t->scene, seq);
- }
- else if (seq->seq3 && seq->seq3->flag & SELECT) {
- SEQ_time_update_sequence(t->scene, seq);
- }
- }
- }
+static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc)
+{
+ SeqCollection *collection = SEQ_collection_create();
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
+ Sequence *seq = ((TransDataSeq *)td->extra)->seq;
+ SEQ_collection_append_strip(seq, collection);
+ }
+ return collection;
+}
- SEQ_sort(seqbasep);
- }
- else {
- /* Canceled, need to update the strips display */
- for (a = 0; a < tc->data_len; a++, td++) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- if (seq->flag & SEQ_OVERLAP) {
- SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene);
- }
+static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
+{
+ Editing *ed = SEQ_editing_get(t->scene, false);
+ if (ed == NULL) {
+ free_transform_custom_data(custom_data);
+ return;
+ }
- SEQ_time_update_sequence_bounds(t->scene, seq);
- }
- seq_prev = seq;
- }
- }
+ SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc);
+
+ if ((t->state == TRANS_CANCEL)) {
+ seq_transform_cancel(t, transformed_strips);
+ free_transform_custom_data(custom_data);
+ return;
}
- if ((custom_data->data != NULL) && custom_data->use_free) {
- TransSeq *ts = custom_data->data;
- MEM_freeN(ts->tdseq);
- MEM_freeN(custom_data->data);
- custom_data->data = NULL;
+ if (seq_transform_check_overlap(transformed_strips)) {
+ seq_transform_handle_overlap(t, transformed_strips);
}
+ seq_transform_update_effects(t, transformed_strips);
+ SEQ_collection_free(transformed_strips);
+
+ SEQ_sort(ed->seqbasep);
DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ free_transform_custom_data(custom_data);
}
void createTransSeqData(TransInfo *t)
@@ -557,7 +526,7 @@ void createTransSeqData(TransInfo *t)
}
#endif
- count = SeqTransCount(t, ed->seqbasep, 0);
+ count = SeqTransCount(t, ed->seqbasep);
/* allocate memory for data */
tc->data_len = count;
@@ -574,7 +543,7 @@ void createTransSeqData(TransInfo *t)
ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
/* loop 2: build transdata array */
- SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
+ SeqToTransData_build(t, ed->seqbasep, td, td2d, tdsq);
SeqTransDataBounds(t, ed->seqbasep, ts);
if (t->flag & T_MODAL) {
@@ -607,15 +576,10 @@ void createTransSeqData(TransInfo *t)
BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
{
- if (seq->depth == 0) {
- /* Calculate this strip and all nested strips.
- * Children are ALWAYS transformed first so we don't need to do this in another loop.
- */
- SEQ_time_update_sequence(sce, seq);
- }
- else {
- SEQ_time_update_sequence_bounds(sce, seq);
- }
+ /* Calculate this strip and all nested strips.
+ * Children are ALWAYS transformed first so we don't need to do this in another loop.
+ */
+ SEQ_time_update_sequence(sce, seq);
if (sel_flag == SELECT) {
SEQ_offset_animdata(sce, seq, seq->start - old_start);
@@ -635,102 +599,49 @@ static void flushTransSeq(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- /* prevent updating the same seq twice
- * if the transdata order is changed this will mess up
- * but so will TransDataSeq */
- Sequence *seq_prev = NULL;
- int old_start_prev = 0, sel_flag_prev = 0;
-
/* flush to 2d vector from internally used 3d vector */
for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
- int old_start;
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
- old_start = seq->start;
new_frame = round_fl_to_int(td2d->loc[0]);
switch (tdsq->sel_flag) {
case SELECT:
- if ((seq->depth != 0 || SEQ_transform_sequence_can_be_translated(seq))) {
- /* for meta's, their children move */
- seq->start = new_frame - tdsq->start_offset;
- }
- if (seq->depth == 0) {
- seq->machine = round_fl_to_int(td2d->loc[1]);
- CLAMP(seq->machine, 1, MAXSEQ);
+ if (SEQ_transform_sequence_can_be_translated(seq)) {
+ const int offset = new_frame - tdsq->start_offset - seq->start;
+ SEQ_transform_translate_sequence(t->scene, seq, offset);
}
+ seq->machine = round_fl_to_int(td2d->loc[1]);
+ CLAMP(seq->machine, 1, MAXSEQ);
break;
+
case SEQ_LEFTSEL: /* no vertical transform */
SEQ_transform_set_left_handle_frame(seq, new_frame);
SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
-
- /* todo - move this into aftertrans update? - old seq tx needed it anyway */
SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_update_sequence(t->scene, seq);
break;
case SEQ_RIGHTSEL: /* no vertical transform */
SEQ_transform_set_right_handle_frame(seq, new_frame);
SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
-
- /* todo - move this into aftertrans update? - old seq tx needed it anyway */
SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_update_sequence(t->scene, seq);
break;
}
-
- /* Update *previous* seq! Else, we would update a seq after its first transform,
- * and if it has more than one (like e.g. SEQ_LEFTSEL and SEQ_RIGHTSEL),
- * the others are not updated! See T38469.
- */
- if (seq != seq_prev) {
- if (seq_prev) {
- trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
- }
-
- seq_prev = seq;
- old_start_prev = old_start;
- sel_flag_prev = tdsq->sel_flag;
- }
- else {
- /* We want to accumulate *all* sel_flags for this seq! */
- sel_flag_prev |= tdsq->sel_flag;
- }
}
- /* Don't forget to update the last seq! */
- if (seq_prev) {
- trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
- }
-
- /* originally TFM_TIME_EXTEND, transform changes */
+ /* Update all effects. */
if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
- /* Special annoying case here, need to calc meta-strips with TFM_TIME_EXTEND only */
-
- /* calc all meta's then effects T27953. */
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) {
- SEQ_time_update_sequence(t->scene, seq);
- }
- }
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->seq1 || seq->seq2 || seq->seq3) {
SEQ_time_update_sequence(t->scene, seq);
}
}
-
- /* update effects inside meta's */
- for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d; a < tc->data_len;
- a++, td++, td2d++, seq_prev = seq) {
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
- if ((seq != seq_prev) && (seq->depth != 0)) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- SEQ_time_update_sequence(t->scene, seq);
- }
- }
- }
}
/* need to do the overlap check in a new loop otherwise adjacent strips
* will not be updated and we'll get false positives */
+ Sequence *seq_prev = NULL;
seq_prev = NULL;
for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
@@ -738,12 +649,10 @@ static void flushTransSeq(TransInfo *t)
seq = tdsq->seq;
if (seq != seq_prev) {
- if (seq->depth == 0) {
- /* test overlap, displays red outline */
- seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
- seq->flag |= SEQ_OVERLAP;
- }
+ /* test overlap, displays red outline */
+ seq->flag &= ~SEQ_OVERLAP;
+ if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ seq->flag |= SEQ_OVERLAP;
}
}
seq_prev = seq;
@@ -787,7 +696,7 @@ void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t)
return;
}
/* freeSeqData in transform_conversions.c does this
- * keep here so the else at the end wont run... */
+ * keep here so the else at the end won't run... */
SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index ed6c3eb0255..ca4ed01c0f6 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -367,7 +367,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
}
}
- /* TODO: skip calculating axis which wont be used (above). */
+ /* TODO: skip calculating axis which won't be used (above). */
switch (axis_type) {
case EXTRUDE_AXIS_NORMAL:
for (int i = 0; i < 3; i++) {
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 350be247014..6a946994e06 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -734,9 +734,25 @@ void ElementRotation_ex(TransInfo *t,
/* can be called for texture space translate for example, then opt out */
if (td->ext->quat) {
mul_m3_series(fmat, td->smtx, mat, td->mtx);
+
+ if (!is_zero_v3(td->ext->dquat)) {
+ /* Correct for delta quat */
+ float tmp_mat[3][3];
+ quat_to_mat3(tmp_mat, td->ext->dquat);
+ mul_m3_m3m3(fmat, fmat, tmp_mat);
+ }
+
mat3_to_quat(quat, fmat); /* Actual transform */
+ if (!is_zero_v4(td->ext->dquat)) {
+ /* Correct back for delta quat. */
+ float idquat[4];
+ invert_qt_qt_normalized(idquat, td->ext->dquat);
+ mul_qt_qtqt(quat, idquat, quat);
+ }
+
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
+
/* this function works on end result */
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
}
@@ -761,21 +777,28 @@ void ElementRotation_ex(TransInfo *t,
td->ext->irotAngle);
}
else {
+ /* Calculate the total rotation in eulers. */
float obmat[3][3];
mul_m3_m3m3(totmat, mat, td->mtx);
mul_m3_m3m3(smat, td->smtx, totmat);
- /* Calculate the total rotation in eulers. */
- add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* correct for delta rot */
+ if (!is_zero_v3(td->ext->drot)) {
+ /* Correct for delta rot */
+ add_eul_euleul(eul, td->ext->irot, td->ext->drot, td->ext->rotOrder);
+ }
+ else {
+ copy_v3_v3(eul, td->ext->irot);
+ }
+
eulO_to_mat3(obmat, eul, td->ext->rotOrder);
- /* mat = transform, obmat = object rotation */
mul_m3_m3m3(fmat, smat, obmat);
-
mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
- /* correct back for delta rot */
- sub_v3_v3v3(eul, eul, td->ext->drot);
+ if (!is_zero_v3(td->ext->drot)) {
+ /* Correct back for delta rot. */
+ sub_eul_euleul(eul, eul, td->ext->drot, td->ext->rotOrder);
+ }
/* and apply */
protectedRotateBits(td->protectflag, eul, td->ext->irot);
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 857ee37f0ad..cfbd6030788 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -89,7 +89,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
/* apply shrink/fatten */
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
+ TransData *td;
for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
if (td->flag & TD_SKIP) {
continue;
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
index 8a92978f33f..b08e479a3d0 100644
--- a/source/blender/editors/transform/transform_mode_push_pull.c
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -77,6 +77,8 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
t->con.applyRot(t, NULL, NULL, axis_global, NULL);
}
+ const bool is_data_space = (t->options & CTX_POSE_BONE) != 0;
+
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
@@ -101,6 +103,9 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
}
}
normalize_v3_length(vec, distance * td->factor);
+ if (is_data_space) {
+ mul_m3_v3(td->smtx, vec);
+ }
add_v3_v3v3(td->loc, td->iloc, vec);
}
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
index 15906f2c90c..9bca9b2e9e6 100644
--- a/source/blender/editors/transform/transform_mode_tosphere.c
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -55,8 +55,10 @@ static void to_sphere_radius_update(TransInfo *t)
{
struct ToSphereInfo *data = t->custom.mode.data;
float radius = 0.0f;
+ float vec[3];
const bool is_local_center = transdata_check_local_center(t, t->around);
+ const bool is_data_space = (t->options & CTX_POSE_BONE) != 0;
if (t->flag & T_PROP_EDIT_ALL) {
int factor_accum = 0.0f;
@@ -67,7 +69,15 @@ static void to_sphere_radius_update(TransInfo *t)
continue;
}
const float *center = is_local_center ? td->center : tc->center_local;
- radius += td->factor * len_v3v3(center, td->iloc);
+ if (is_data_space) {
+ copy_v3_v3(vec, td->center);
+ }
+ else {
+ copy_v3_v3(vec, td->iloc);
+ }
+
+ sub_v3_v3(vec, center);
+ radius += td->factor * len_v3(vec);
factor_accum += td->factor;
}
}
@@ -80,7 +90,15 @@ static void to_sphere_radius_update(TransInfo *t)
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
const float *center = is_local_center ? td->center : tc->center_local;
- radius += len_v3v3(center, td->iloc);
+ if (is_data_space) {
+ copy_v3_v3(vec, td->center);
+ }
+ else {
+ copy_v3_v3(vec, td->iloc);
+ }
+
+ sub_v3_v3(vec, center);
+ radius += len_v3(vec);
}
}
radius /= (float)t->data_len_all;
@@ -99,6 +117,7 @@ static void to_sphere_radius_update(TransInfo *t)
static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
{
const bool is_local_center = transdata_check_local_center(t, t->around);
+ const bool is_data_space = (t->options & CTX_POSE_BONE) != 0;
float vec[3];
float ratio, radius;
@@ -142,16 +161,26 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
}
const float *center = is_local_center ? td->center : tc->center_local;
+ if (is_data_space) {
+ copy_v3_v3(vec, td->center);
+ }
+ else {
+ copy_v3_v3(vec, td->iloc);
+ }
- sub_v3_v3v3(vec, td->iloc, center);
-
+ sub_v3_v3(vec, center);
radius = normalize_v3(vec);
-
tratio = ratio * td->factor;
-
mul_v3_fl(vec, radius * (1.0f - tratio) + data->radius * tratio);
+ add_v3_v3(vec, center);
+
+ if (is_data_space) {
+ sub_v3_v3(vec, td->center);
+ mul_m3_v3(td->smtx, vec);
+ add_v3_v3(vec, td->iloc);
+ }
- add_v3_v3v3(td->loc, center, vec);
+ copy_v3_v3(td->loc, vec);
}
}
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 3088f6a7776..0e734b3b74b 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -52,12 +52,26 @@
/** \name Transform (Translation)
* \{ */
+static void translate_dist_to_str(char *r_str,
+ const int len_max,
+ const float val,
+ const UnitSettings *unit)
+{
+ if (unit) {
+ BKE_unit_value_as_string(
+ r_str, len_max, val * unit->scale_length, 4, B_UNIT_LENGTH, unit, false);
+ }
+ else {
+ /* Check range to prevent string buffer overflow. */
+ BLI_snprintf(r_str, len_max, IN_RANGE_INCL(val, -1e10f, 1e10f) ? "%.4f" : "%.4e", val);
+ }
+}
+
static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
{
size_t ofs = 0;
- char tvec[NUM_STR_REP_LEN * 3];
- char distvec[NUM_STR_REP_LEN];
- char autoik[NUM_STR_REP_LEN];
+ char dvec_str[3][NUM_STR_REP_LEN];
+ char dist_str[NUM_STR_REP_LEN];
float dist;
UnitSettings *unit = NULL;
@@ -66,7 +80,7 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
+ outputNumInput(&(t->num), dvec_str[0], &t->scene->unit);
dist = len_v3(t->num.val);
}
else {
@@ -94,84 +108,37 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
dist = len_v3(dvec);
- if (unit) {
- for (int i = 0; i < 3; i++) {
- BKE_unit_value_as_string(&tvec[NUM_STR_REP_LEN * i],
- NUM_STR_REP_LEN,
- dvec[i] * unit->scale_length,
- 4,
- B_UNIT_LENGTH,
- unit,
- true);
- }
+ for (int i = 0; i < 3; i++) {
+ translate_dist_to_str(dvec_str[i], sizeof(dvec_str[i]), dvec[i], unit);
}
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]);
- }
- }
-
- if (unit) {
- BKE_unit_value_as_string(
- distvec, sizeof(distvec), dist * unit->scale_length, 4, B_UNIT_LENGTH, unit, false);
- }
- else if (dist > 1e10f || dist < -1e10f) {
- /* prevent string buffer overflow */
- BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
- }
- else {
- BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist);
}
- if (t->flag & T_AUTOIK) {
- short chainlen = t->settings->autoik_chainlen;
-
- if (chainlen) {
- BLI_snprintf(autoik, NUM_STR_REP_LEN, TIP_("AutoIK-Len: %d"), chainlen);
- }
- else {
- autoik[0] = '\0';
- }
- }
- else {
- autoik[0] = '\0';
- }
+ translate_dist_to_str(dist_str, sizeof(dist_str), dist, unit);
if (t->con.mode & CON_APPLY) {
switch (t->num.idx_max) {
case 0:
- ofs += BLI_snprintf_rlen(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- "D: %s (%s)%s %s %s",
- &tvec[0],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
+ ofs += BLI_snprintf_rlen(
+ str + ofs, UI_MAX_DRAW_STR - ofs, "D: %s (%s)%s", dvec_str[0], dist_str, t->con.text);
break;
case 1:
ofs += BLI_snprintf_rlen(str + ofs,
UI_MAX_DRAW_STR - ofs,
- "D: %s D: %s (%s)%s %s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
+ "D: %s D: %s (%s)%s",
+ dvec_str[0],
+ dvec_str[1],
+ dist_str,
+ t->con.text);
break;
case 2:
ofs += BLI_snprintf_rlen(str + ofs,
UI_MAX_DRAW_STR - ofs,
- "D: %s D: %s D: %s (%s)%s %s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
+ "D: %s D: %s D: %s (%s)%s",
+ dvec_str[0],
+ dvec_str[1],
+ dvec_str[2],
+ dist_str,
+ t->con.text);
break;
}
}
@@ -179,30 +146,42 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
if (t->flag & T_2D_EDIT) {
ofs += BLI_snprintf_rlen(str + ofs,
UI_MAX_DRAW_STR - ofs,
- "Dx: %s Dy: %s (%s)%s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- distvec,
- t->con.text,
- t->proptext);
+ "Dx: %s Dy: %s (%s)%s",
+ dvec_str[0],
+ dvec_str[1],
+ dist_str,
+ t->con.text);
}
else {
ofs += BLI_snprintf_rlen(str + ofs,
UI_MAX_DRAW_STR - ofs,
- "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
+ "Dx: %s Dy: %s Dz: %s (%s)%s",
+ dvec_str[0],
+ dvec_str[1],
+ dvec_str[2],
+ dist_str,
+ t->con.text);
}
}
if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf_rlen(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
+ char prop_str[NUM_STR_REP_LEN];
+ translate_dist_to_str(prop_str, sizeof(prop_str), t->prop_size, unit);
+
+ ofs += BLI_snprintf_rlen(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ " %s %s: %s",
+ TIP_("Proportional Size"),
+ t->proptext,
+ prop_str);
+ }
+
+ if (t->flag & T_AUTOIK) {
+ short chainlen = t->settings->autoik_chainlen;
+ if (chainlen) {
+ ofs += BLI_strncpy_rlen(str + ofs, " ", UI_MAX_DRAW_STR - ofs);
+ ofs += BLI_snprintf_rlen(str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("AutoIK-Len: %d"), chainlen);
+ }
}
if (t->spacetype == SPACE_NODE) {
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 9b5f15a2574..2c424d8ace3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -519,10 +519,11 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* add temp handler */
WM_event_add_modal_handler(C, op);
- op->flag |= OP_IS_MODAL_GRAB_CURSOR; /* XXX maybe we want this with the gizmo only? */
-
/* Use when modal input has some transformation to begin with. */
TransInfo *t = op->customdata;
+ if ((t->flag & T_NO_CURSOR_WRAP) == 0) {
+ op->flag |= OP_IS_MODAL_GRAB_CURSOR; /* XXX maybe we want this with the gizmo only? */
+ }
if (UNLIKELY(!is_zero_v4(t->values_modal_offset))) {
transformApply(C, t);
}
@@ -538,7 +539,7 @@ static bool transform_poll_property(const bContext *UNUSED(C),
/* Orientation/Constraints. */
{
- /* Hide orientation axis if no constraints are set, since it wont be used. */
+ /* Hide orientation axis if no constraints are set, since it won't be used. */
PropertyRNA *prop_con = RNA_struct_find_property(op->ptr, "orient_type");
if (!ELEM(prop_con, NULL, prop)) {
if (STRPREFIX(prop_id, "constraint")) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 193954fffb6..bebef049718 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1072,7 +1072,7 @@ static void TargetSnapClosest(TransInfo *t)
if (t->options & CTX_OBJECT) {
int i;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
+ TransData *td;
for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
const BoundBox *bb = NULL;
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 7811509ab40..df4e6f893ec 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -492,7 +492,7 @@ bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
}
/**
- * Ideally we wont access the stack directly,
+ * Ideally we won't access the stack directly,
* this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
*
* Using global isn't great, this just avoids doing inline,
@@ -693,9 +693,9 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
}
if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) &&
- /* note, undo/redo cant run if there are jobs active,
+ /* note, undo/redo can't run if there are jobs active,
* check for screen jobs only so jobs like material/texture/world preview
- * (which copy their data), wont stop redo, see T29579],
+ * (which copy their data), won't stop redo, see T29579],
*
* note, - WM_operator_check_ui_enabled() jobs test _must_ stay in sync with this */
(WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY) == 0)) {
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index 9189adaf4d1..7c6ce56eab0 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -224,9 +224,21 @@ static void memfile_undosys_step_decode(struct bContext *C,
/* Tag depsgraph to update data-block for changes that happened between the
* current and the target state, see direct_link_id_restore_recalc(). */
- if (id->recalc) {
+ if (id->recalc != 0) {
DEG_id_tag_update_ex(bmain, id, id->recalc);
}
+
+ bNodeTree *nodetree = ntreeFromID(id);
+ if (nodetree != NULL && nodetree->id.recalc != 0) {
+ DEG_id_tag_update_ex(bmain, &nodetree->id, nodetree->id.recalc);
+ }
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ if (scene->master_collection != NULL && scene->master_collection->id.recalc != 0) {
+ DEG_id_tag_update_ex(
+ bmain, &scene->master_collection->id, scene->master_collection->id.recalc);
+ }
+ }
}
FOREACH_MAIN_ID_END;
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 708f04bf044..7b034af1438 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -632,7 +632,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
}
}
else {
- /* error - cant find an endpoint */
+ /* error - can't find an endpoint */
}
}
@@ -1469,7 +1469,12 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (EDBM_mesh_hide(em, swap)) {
- EDBM_update_generic(ob->data, true, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
continue;
}
@@ -1607,7 +1612,12 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
/* call the mesh function if we are in mesh sync sel */
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (EDBM_mesh_reveal(em, select)) {
- EDBM_update_generic(ob->data, true, false);
+ EDBM_update(ob->data,
+ &(const struct EDBMUpdate_Params){
+ .calc_looptri = true,
+ .calc_normals = false,
+ .is_destructive = false,
+ });
}
continue;
}
diff --git a/source/blender/editors/uvedit/uvedit_path.c b/source/blender/editors/uvedit/uvedit_path.c
index 016a054cf21..2613c5b23a0 100644
--- a/source/blender/editors/uvedit/uvedit_path.c
+++ b/source/blender/editors/uvedit/uvedit_path.c
@@ -552,7 +552,7 @@ static bool uv_shortest_path_pick_ex(const SpaceImage *sima,
if (uv_selectmode & UV_SELECT_EDGE) {
/* Special case as we don't use true edge selection,
* flush the selection from the vertices. */
- BM_mesh_select_mode_flush_ex(em->bm, SCE_SELECT_VERTEX);
+ BM_mesh_select_mode_flush_ex(em->bm, SCE_SELECT_VERTEX, BM_SELECT_LEN_FLUSH_RECALC_ALL);
}
}
ED_uvedit_select_sync_flush(scene->toolsettings, em, select);
diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c
index e1b9a287457..f8b53879ac4 100644
--- a/source/blender/editors/uvedit/uvedit_rip.c
+++ b/source/blender/editors/uvedit/uvedit_rip.c
@@ -572,7 +572,7 @@ static UVRipPairs *uv_rip_pairs_from_loop(BMLoop *l_init,
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. */
+ * so the stack won't 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,
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 39950f9d0c7..0a7cd579a0a 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -1296,7 +1296,7 @@ static int uv_select_edgering(
l_step = uvedit_loop_find_other_radial_loop_with_visible_face(
scene, l_step_opposite, cd_loop_uv_offset);
if (l_step == NULL) {
- /* Ensure we touch the opposite edge if we cant walk over it. */
+ /* Ensure we touch the opposite edge if we can't walk over it. */
l_step = l_step_opposite;
}
}
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index d530d10b3c8..5fdc7c3f337 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -66,7 +66,7 @@ class GVArray {
bool is_empty() const
{
- return size_;
+ return size_ == 0;
}
/* Copies the value at the given index into the provided storage. The `r_value` pointer is
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
index 685f0cb36cb..7d75ed5804e 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
@@ -29,3 +29,7 @@ void OBJECT_OT_lineart_clear(struct wmOperatorType *ot);
void OBJECT_OT_lineart_clear_all(struct wmOperatorType *ot);
void WM_operatortypes_lineart(void);
+
+struct LineartCache;
+
+void MOD_lineart_clear_cache(struct LineartCache **lc);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index cc79810d2a2..f0aae7e4498 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -38,6 +38,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "MOD_gpencil_lineart.h"
#include "lineart/MOD_lineart.h"
#include "BKE_collection.h"
@@ -88,7 +89,7 @@ static void generate_strokes_actual(
}
MOD_lineart_gpencil_generate(
- lmd->render_buffer,
+ lmd->cache,
depsgraph,
ob,
gpl,
@@ -156,11 +157,31 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
return;
}
- MOD_lineart_compute_feature_lines(depsgraph, lmd);
+ LineartCache *local_lc = gpd->runtime.lineart_cache;
+ if (!gpd->runtime.lineart_cache) {
+ MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
+ MOD_lineart_destroy_render_data(lmd);
+ }
+ else {
+ if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
+ MOD_lineart_compute_feature_lines(depsgraph, lmd, &local_lc);
+ MOD_lineart_destroy_render_data(lmd);
+ }
+ MOD_lineart_chain_clear_picked_flag(local_lc);
+ lmd->cache = local_lc;
+ }
generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
- MOD_lineart_destroy_render_data(lmd);
+ if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
+ /* Clear local cache. */
+ if (local_lc != gpd->runtime.lineart_cache) {
+ MOD_lineart_clear_cache(&local_lc);
+ }
+ /* Restore the original cache pointer so the modifiers below still have access to the "global"
+ * cache. */
+ lmd->cache = gpd->runtime.lineart_cache;
+ }
WM_main_add_notifier(NA_EDITED | NC_GPENCIL, NULL);
}
@@ -182,11 +203,12 @@ static void bakeModifier(Main *UNUSED(bmain),
return;
}
- MOD_lineart_compute_feature_lines(depsgraph, lmd);
+ if (!gpd->runtime.lineart_cache) {
+ MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
+ MOD_lineart_destroy_render_data(lmd);
+ }
generate_strokes_actual(md, depsgraph, ob, gpl, gpf);
-
- MOD_lineart_destroy_render_data(lmd);
}
static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
@@ -198,6 +220,9 @@ static void add_this_collection(Collection *c,
const ModifierUpdateDepsgraphContext *ctx,
const int mode)
{
+ if (!c) {
+ return;
+ }
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (c, ob, mode) {
if (ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
if (ob->lineart.usage != OBJECT_LRT_EXCLUDE) {
@@ -255,10 +280,16 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
const int source_type = RNA_enum_get(ptr, "source_type");
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool use_cache = RNA_boolean_get(ptr, "use_cache");
+ const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, !is_baked);
+ if (!BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data)) {
+ uiItemR(layout, ptr, "use_cache", 0, NULL, ICON_NONE);
+ }
+
uiItemR(layout, ptr, "source_type", 0, NULL, ICON_NONE);
if (source_type == LRT_SOURCE_OBJECT) {
@@ -277,12 +308,17 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
- uiItemR(col, ptr, "use_crease", 0, IFACE_("Crease"), ICON_NONE);
- uiLayout *sub = uiLayoutRow(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_crease"));
- uiLayoutSetPropSep(sub, true);
- uiItemR(sub, ptr, "crease_threshold", UI_ITEM_R_SLIDER, " ", ICON_NONE);
+ uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease"));
+ uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
+ uiLayout *entry = uiLayoutRow(sub, false);
+ uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
+ if (use_cache && !is_first) {
+ uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO);
+ }
+ else {
+ uiItemR(entry, ptr, "crease_threshold", UI_ITEM_R_SLIDER, " ", ICON_NONE);
+ }
uiItemPointerR(layout, ptr, "target_layer", &obj_data_ptr, "layers", NULL, ICON_GREASEPENCIL);
@@ -305,14 +341,35 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
NULL,
material_valid ? ICON_SHADING_TEXTURE : ICON_ERROR);
- uiItemR(layout, ptr, "use_remove_doubles", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
- uiItemR(layout, ptr, "use_object_instances", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
-
gpencil_modifier_panel_end(layout, ptr);
}
+static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool use_cache = RNA_boolean_get(ptr, "use_cache");
+ const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ if (use_cache && !is_first) {
+ uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ return;
+ }
+
+ uiLayout *col = uiLayoutColumn(layout, true);
+
+ uiItemR(col, ptr, "use_remove_doubles", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
+ uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
+}
+
static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -392,15 +449,23 @@ static void transparency_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
uiLayout *layout = panel->layout;
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool use_cache = RNA_boolean_get(ptr, "use_cache");
+ const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, !is_baked);
+ if (use_cache && !is_first) {
+ uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ return;
+ }
+
uiLayout *col = uiLayoutColumnWithHeading(layout, true, IFACE_("Chain"));
uiItemR(col, ptr, "use_fuzzy_intersections", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
@@ -418,13 +483,21 @@ static void vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *layout = panel->layout;
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool use_cache = RNA_boolean_get(ptr, "use_cache");
+ const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, !is_baked);
+ if (use_cache && !is_first) {
+ uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ return;
+ }
+
uiLayout *col = uiLayoutColumn(layout, true);
uiLayout *row = uiLayoutRow(col, true);
+
uiItemR(row, ptr, "source_vertex_group", 0, IFACE_("Filter Source"), ICON_GROUP_VERTEX);
uiItemR(row, ptr, "invert_source_vertex_group", UI_ITEM_R_TOGGLE, "", ICON_ARROW_LEFTRIGHT);
@@ -471,6 +544,8 @@ static void panelRegister(ARegionType *region_type)
region_type, eGpencilModifierType_Lineart, panel_draw);
gpencil_modifier_subpanel_register(
+ region_type, "geometry", "Geometry Processing", NULL, options_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
region_type, "style", "Style", NULL, style_panel_draw, panel_type);
PanelType *occlusion_panel = gpencil_modifier_subpanel_register(
region_type, "occlusion", "Occlusion", NULL, occlusion_panel_draw, panel_type);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 861085d3e16..b6175762bbe 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -250,6 +250,10 @@ typedef struct LineartRenderBuffer {
ListBase wasted_cuts;
SpinLock lock_cuts;
+ /* This is just a pointer to LineartCache::chain_data_pool, which acts as a cache for line
+ * chains. */
+ LineartStaticMemPool *chain_data_pool;
+
/* Render status */
double view_vector[3];
@@ -309,6 +313,18 @@ typedef struct LineartRenderBuffer {
} LineartRenderBuffer;
+typedef struct LineartCache {
+ /** Separate memory pool for chain data, this goes to the cache, so when we free the main pool,
+ * chains will still be available. */
+ LineartStaticMemPool chain_data_pool;
+
+ /** A copy of rb->chains so we have that data available after rb has been destroyed. */
+ ListBase chains;
+
+ /** Cache only contains edge types specified in this variable. */
+ char rb_edge_types;
+} LineartCache;
+
#define DBL_TRIANGLE_LIM 1e-8
#define DBL_EDGE_LIM 1e-9
@@ -563,10 +579,11 @@ void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float thresh
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
-void MOD_lineart_chain_clear_picked_flag(struct LineartRenderBuffer *rb);
+void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
- struct LineartGpencilModifierData *lmd);
+ struct LineartGpencilModifierData *lmd,
+ LineartCache **cached_result);
struct Scene;
@@ -579,7 +596,7 @@ LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, doub
struct bGPDlayer;
struct bGPDframe;
-void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
+void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Depsgraph *depsgraph,
struct Object *ob,
struct bGPDlayer *gpl,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 23928b4ccda..f90fbaf4ccf 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -74,7 +74,7 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec;
- ec = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeChain));
+ ec = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChain));
BLI_addtail(&rb->chains, ec);
@@ -119,7 +119,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
return old_rlci;
}
- eci = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v2_v2(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -149,7 +149,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
return ec->chain.first;
}
- eci = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v2_v2(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -198,7 +198,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
* so we assign it based on the first segment we found. */
ec->object_ref = e->object_ref;
- LineartEdge *new_e = e;
+ LineartEdge *new_e;
LineartVert *new_vt;
float N[3] = {0};
@@ -889,12 +889,12 @@ int MOD_lineart_chain_count(const LineartEdgeChain *ec)
return count;
}
-void MOD_lineart_chain_clear_picked_flag(LineartRenderBuffer *rb)
+void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
{
- if (rb == NULL) {
+ if (lc == NULL) {
return;
}
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &lc->chains) {
ec->picked = 0;
}
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 06d63c3ddab..3796e374db7 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -21,6 +21,7 @@
* \ingroup editors
*/
+#include "MOD_gpencil_lineart.h"
#include "MOD_lineart.h"
#include "BLI_linklist.h"
@@ -42,6 +43,7 @@
#include "BKE_gpencil_modifier.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
@@ -107,6 +109,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl,
static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e);
+static LineartCache *lineart_init_cache(void);
+
static void lineart_discard_segment(LineartRenderBuffer *rb, LineartEdgeSegment *es)
{
BLI_spin_lock(&rb->lock_cuts);
@@ -482,7 +486,7 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
rb->material.last = rb->material.first;
rb->edge_mark.last = rb->edge_mark.first;
- TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
for (i = 0; i < thread_count; i++) {
rti[i].thread_id = i;
@@ -1987,7 +1991,7 @@ static void lineart_main_load_geometries(
}
DEG_OBJECT_ITER_END;
- TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH, TASK_ISOLATION_ON);
+ TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
for (int i = 0; i < thread_count; i++) {
olti[i].rb = rb;
@@ -2771,13 +2775,13 @@ static void lineart_destroy_render_data(LineartRenderBuffer *rb)
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
{
- LineartRenderBuffer *rb = lmd->render_buffer;
+ LineartRenderBuffer *rb = lmd->render_buffer_ptr;
lineart_destroy_render_data(rb);
if (rb) {
MEM_freeN(rb);
- lmd->render_buffer = NULL;
+ lmd->render_buffer_ptr = NULL;
}
if (G.debug_value == 4000) {
@@ -2785,14 +2789,33 @@ void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
}
}
+static LineartCache *lineart_init_cache()
+{
+ LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache");
+ return lc;
+}
+
+void MOD_lineart_clear_cache(struct LineartCache **lc)
+{
+ if (!(*lc)) {
+ return;
+ }
+ lineart_mem_destroy(&((*lc)->chain_data_pool));
+ MEM_freeN(*lc);
+ (*lc) = NULL;
+}
+
static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
- LineartGpencilModifierData *lmd)
+ LineartGpencilModifierData *lmd,
+ LineartCache *lc)
{
LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
- lmd->render_buffer = rb;
+ lmd->cache = lc;
+ lmd->render_buffer_ptr = rb;
+ lc->rb_edge_types = lmd->edge_types_override;
- if (!scene || !scene->camera) {
+ if (!scene || !scene->camera || !lc) {
return NULL;
}
Camera *c = scene->camera->data;
@@ -2835,11 +2858,15 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
/* See lineart_edge_from_triangle() for how this option may impact performance. */
rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
- rb->use_contour = (lmd->edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
- rb->use_crease = (lmd->edge_types & LRT_EDGE_FLAG_CREASE) != 0;
- rb->use_material = (lmd->edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
- rb->use_edge_marks = (lmd->edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
- rb->use_intersections = (lmd->edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
+ int16_t edge_types = lmd->edge_types_override;
+
+ rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
+ rb->use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
+ rb->use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
+ rb->use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
+ rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
+
+ rb->chain_data_pool = &lc->chain_data_pool;
BLI_spin_init(&rb->lock_task);
BLI_spin_init(&rb->lock_cuts);
@@ -3818,7 +3845,9 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
*
* \return True when a change is made.
*/
-bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModifierData *lmd)
+bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
+ LineartGpencilModifierData *lmd,
+ LineartCache **cached_result)
{
LineartRenderBuffer *rb;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
@@ -3836,7 +3865,10 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
return false;
}
- rb = lineart_create_render_buffer(scene, lmd);
+ LineartCache *lc = lineart_init_cache();
+ *cached_result = lc;
+
+ rb = lineart_create_render_buffer(scene, lmd, lc);
/* Triangle thread testing data size varies depending on the thread count.
* See definition of LineartTriangleThread for details. */
@@ -3844,7 +3876,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
/* This is used to limit calculation to a certain level to save time, lines who have higher
* occlusion levels will get ignored. */
- rb->max_occlusion_level = MAX2(lmd->level_start, lmd->level_end);
+ rb->max_occlusion_level = (lmd->flags & LRT_GPENCIL_USE_CACHE) ?
+ lmd->level_end_override :
+ (lmd->use_multiple_levels ? lmd->level_end : lmd->level_start);
/* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
rb->_source_type = lmd->source_type;
@@ -3907,13 +3941,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
/* Then we connect chains based on the _proximity_ of their end points in image space, here's
* the place threshold value gets involved. */
-
- /* do_geometry_space = true. */
MOD_lineart_chain_connect(rb);
- /* After chaining, we need to clear flags so we don't confuse GPencil generation calls. */
- MOD_lineart_chain_clear_picked_flag(rb);
-
float *t_image = &lmd->chaining_image_threshold;
/* This configuration ensures there won't be accidental lost of short unchained segments. */
MOD_lineart_chain_discard_short(rb, MIN2(*t_image, 0.001f) - FLT_EPSILON);
@@ -3921,6 +3950,12 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
if (rb->angle_splitting_threshold > FLT_EPSILON) {
MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
}
+
+ /* Finally transfer the result list into cache. */
+ memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
+
+ /* At last, we need to clear flags so we don't confuse GPencil generation calls. */
+ MOD_lineart_chain_clear_picked_flag(lc);
}
if (G.debug_value == 4000) {
@@ -3933,7 +3968,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
return true;
}
-static int lineart_rb_edge_types(LineartRenderBuffer *rb)
+static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartRenderBuffer *rb)
{
int types = 0;
types |= rb->use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
@@ -3944,7 +3979,7 @@ static int lineart_rb_edge_types(LineartRenderBuffer *rb)
return types;
}
-static void lineart_gpencil_generate(LineartRenderBuffer *rb,
+static void lineart_gpencil_generate(LineartCache *cache,
Depsgraph *depsgraph,
Object *gpencil_object,
float (*gp_obmat_inverse)[4],
@@ -3964,9 +3999,9 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
const char *vgname,
int modifier_flags)
{
- if (rb == NULL) {
+ if (cache == NULL) {
if (G.debug_value == 4000) {
- printf("NULL Lineart rb!\n");
+ printf("NULL Lineart cache!\n");
}
return;
}
@@ -3990,11 +4025,11 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
float mat[4][4];
unit_m4(mat);
- int enabled_types = lineart_rb_edge_types(rb);
+ int enabled_types = cache->rb_edge_types;
bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &cache->chains) {
if (ec->picked) {
continue;
@@ -4108,7 +4143,7 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
/**
* Wrapper for external calls.
*/
-void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
+void MOD_lineart_gpencil_generate(LineartCache *cache,
Depsgraph *depsgraph,
Object *ob,
bGPDlayer *gpl,
@@ -4156,7 +4191,7 @@ void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
}
float gp_obmat_inverse[4][4];
invert_m4_m4(gp_obmat_inverse, ob->obmat);
- lineart_gpencil_generate(rb,
+ lineart_gpencil_generate(cache,
depsgraph,
ob,
gp_obmat_inverse,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index c023c63ebc9..7ebb869e955 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -88,7 +88,12 @@ static void clear_strokes(Object *ob, GpencilModifierData *md, int frame)
BKE_gpencil_layer_frame_delete(gpl, gpf);
}
-static bool bake_strokes(Object *ob, Depsgraph *dg, GpencilModifierData *md, int frame)
+static bool bake_strokes(Object *ob,
+ Depsgraph *dg,
+ LineartCache **lc,
+ GpencilModifierData *md,
+ int frame,
+ bool is_first)
{
/* Modifier data sanity check. */
if (lineart_mod_is_disabled(md)) {
@@ -111,11 +116,22 @@ static bool bake_strokes(Object *ob, Depsgraph *dg, GpencilModifierData *md, int
/* No greasepencil frame created or found. */
return false;
}
-
- MOD_lineart_compute_feature_lines(dg, lmd);
+ LineartCache *local_lc = *lc;
+ if (!(*lc)) {
+ MOD_lineart_compute_feature_lines(dg, lmd, lc);
+ MOD_lineart_destroy_render_data(lmd);
+ }
+ else {
+ if (is_first || (!(lmd->flags & LRT_GPENCIL_USE_CACHE))) {
+ MOD_lineart_compute_feature_lines(dg, lmd, &local_lc);
+ MOD_lineart_destroy_render_data(lmd);
+ }
+ MOD_lineart_chain_clear_picked_flag(local_lc);
+ lmd->cache = local_lc;
+ }
MOD_lineart_gpencil_generate(
- lmd->render_buffer,
+ lmd->cache,
dg,
ob,
gpl,
@@ -135,7 +151,15 @@ static bool bake_strokes(Object *ob, Depsgraph *dg, GpencilModifierData *md, int
lmd->vgname,
lmd->flags);
- MOD_lineart_destroy_render_data(lmd);
+ if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
+ /* Clear local cache. */
+ if (!is_first) {
+ MOD_lineart_clear_cache(&local_lc);
+ }
+ /* Restore the original cache pointer so the modifiers below still have access to the
+ * "global" cache. */
+ lmd->cache = gpd->runtime.lineart_cache;
+ }
return true;
}
@@ -174,14 +198,21 @@ static bool lineart_gpencil_bake_single_target(LineartBakeJob *bj, Object *ob, i
}
}
+ GpencilLineartLimitInfo info = BKE_gpencil_get_lineart_modifier_limits(ob);
+
+ LineartCache *lc = NULL;
+ bool is_first = true;
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (md->type != eGpencilModifierType_Lineart) {
continue;
}
- if (bake_strokes(ob, bj->dg, md, frame)) {
+ BKE_gpencil_set_lineart_modifier_limits(md, &info, is_first);
+ if (bake_strokes(ob, bj->dg, &lc, md, frame, is_first)) {
touched = true;
+ is_first = false;
}
}
+ MOD_lineart_clear_cache(&lc);
return touched;
}
diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h
index 03d60c60b4b..197077cf76c 100644
--- a/source/blender/gpu/GPU_index_buffer.h
+++ b/source/blender/gpu/GPU_index_buffer.h
@@ -44,7 +44,6 @@ typedef struct GPUIndexBufBuilder {
uint index_max;
GPUPrimType prim_type;
uint32_t *data;
- const struct GPUIndexBufBuilder *parent;
} GPUIndexBufBuilder;
/* supports all primitive types. */
@@ -55,17 +54,11 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint ve
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len);
/*
- * Thread safe sub builders.
+ * Thread safe.
*
- * Note that `GPU_indexbuf_subbuilder_init` and `GPU_indexbuf_subbuilder_finish` are not thread
- * safe and should be called when no threads are active. The pattern is to create a subbuilder for
- * each thread/task. Each thread/task would update their sub builder. When all thread are completed
- * the sub-builders can then be merged back to the parent builder.
+ * Function inspired by the reduction directives of multithread work APIs..
*/
-void GPU_indexbuf_subbuilder_init(const GPUIndexBufBuilder *parent_builder,
- GPUIndexBufBuilder *sub_builder);
-void GPU_indexbuf_subbuilder_finish(GPUIndexBufBuilder *builder,
- const GPUIndexBufBuilder *parent_builder);
+void GPU_indexbuf_join(GPUIndexBufBuilder *builder, const GPUIndexBufBuilder *builder_from);
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v);
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *);
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 3cdcaac5544..be7470e79c1 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -57,7 +57,6 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder,
builder->index_max = 0;
builder->prim_type = prim_type;
builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
- builder->parent = nullptr;
}
void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
@@ -80,21 +79,12 @@ GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len)
return elem_;
}
-void GPU_indexbuf_subbuilder_init(const GPUIndexBufBuilder *parent_builder,
- GPUIndexBufBuilder *sub_builder)
+void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
{
- BLI_assert(parent_builder->parent == nullptr);
- memcpy(sub_builder, parent_builder, sizeof(GPUIndexBufBuilder));
- sub_builder->parent = parent_builder;
-}
-
-void GPU_indexbuf_subbuilder_finish(GPUIndexBufBuilder *parent_builder,
- const GPUIndexBufBuilder *sub_builder)
-{
- BLI_assert(parent_builder == sub_builder->parent);
- parent_builder->index_len = max_uu(parent_builder->index_len, sub_builder->index_len);
- parent_builder->index_min = min_uu(parent_builder->index_min, sub_builder->index_min);
- parent_builder->index_max = max_uu(parent_builder->index_max, sub_builder->index_max);
+ BLI_assert(builder_to->data == builder_from->data);
+ builder_to->index_len = max_uu(builder_to->index_len, builder_from->index_len);
+ builder_to->index_min = min_uu(builder_to->index_min, builder_from->index_min);
+ builder_to->index_max = max_uu(builder_to->index_max, builder_from->index_max);
}
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 265dec7c56a..e2eb8953292 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -159,7 +159,7 @@ void Shader::print_log(Span<const char *> sources, char *log, const char *stage,
}
/* Print line from the source file that is producing the error. */
if ((error_line != -1) && (error_line != last_error_line || error_char != last_error_char)) {
- const char *src_line_end = src_line;
+ const char *src_line_end;
found_line_id = false;
/* error_line is 1 based in this case. */
int src_line_index = 1;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
index 21c7f79a57c..6dd0201535d 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
@@ -36,6 +36,9 @@ vec3 compute_masks(vec2 uv)
corner_rad = right_half ? outRoundCorners.y : outRoundCorners.x;
}
+ /* Fade emboss at the border. */
+ float emboss_size = upper_half ? 0.0 : min(1.0, uv_sdf.x / (corner_rad * ratio));
+
/* Signed distance field from the corner (in pixel).
* inner_sdf is sharp and outer_sdf is rounded. */
uv_sdf -= corner_rad;
@@ -43,9 +46,6 @@ vec3 compute_masks(vec2 uv)
float outer_sdf = -length(min(uv_sdf, 0.0));
float sdf = inner_sdf + outer_sdf + corner_rad;
- /* Fade emboss at the border. */
- float emboss_size = clamp((upper_half) ? 0.0 : (uv.x / corner_rad), 0.0, 1.0);
-
/* Clamp line width to be at least 1px wide. This can happen if the projection matrix
* has been scaled (i.e: Node editor)... */
float line_width = (lineWidth > 0.0) ? max(fwidth(uv.y), lineWidth) : 0.0;
diff --git a/source/blender/gpu/tests/gpu_index_buffer_test.cc b/source/blender/gpu/tests/gpu_index_buffer_test.cc
index ebc110056e3..78e351af7f1 100644
--- a/source/blender/gpu/tests/gpu_index_buffer_test.cc
+++ b/source/blender/gpu/tests/gpu_index_buffer_test.cc
@@ -21,7 +21,7 @@ TEST_F(GPUTest, gpu_index_buffer_subbuilders)
GPUIndexBufBuilder subbuilders[num_subbuilders];
for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) {
- GPU_indexbuf_subbuilder_init(&builder, &subbuilders[subbuilder_index]);
+ memcpy(&subbuilders[subbuilder_index], &builder, sizeof(builder));
}
for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) {
@@ -35,7 +35,7 @@ TEST_F(GPUTest, gpu_index_buffer_subbuilders)
for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) {
EXPECT_EQ(builder.index_len, subbuilder_index * verts_per_subbuilders);
- GPU_indexbuf_subbuilder_finish(&builder, &subbuilders[subbuilder_index]);
+ GPU_indexbuf_join(&builder, &subbuilders[subbuilder_index]);
EXPECT_EQ(builder.index_len, (subbuilder_index + 1) * verts_per_subbuilders);
}
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 9c84127105a..69a80d6e0d3 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -70,6 +70,7 @@ extern "C" {
*/
struct ImBuf;
struct rcti;
+struct rctf;
/**
*
@@ -323,6 +324,11 @@ typedef enum IMB_Proxy_Size {
IMB_PROXY_MAX_SLOT = 4,
} IMB_Proxy_Size;
+typedef enum eIMBInterpolationFilterMode {
+ IMB_FILTER_NEAREST,
+ IMB_FILTER_BILINEAR,
+} eIMBInterpolationFilterMode;
+
/* Defaults to BL_proxy within the directory of the animation. */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
void IMB_anim_get_fname(struct anim *anim, char *file, int size);
@@ -727,11 +733,17 @@ void IMB_processor_apply_threaded(
void(init_handle)(void *handle, int start_line, int tot_line, void *customdata),
void *(do_thread)(void *));
-typedef void (*ScanlineThreadFunc)(void *custom_data, int start_scanline, int num_scanlines);
+typedef void (*ScanlineThreadFunc)(void *custom_data, int scanline);
void IMB_processor_apply_threaded_scanlines(int total_scanlines,
ScanlineThreadFunc do_thread,
void *custom_data);
+void IMB_transform(struct ImBuf *src,
+ struct ImBuf *dst,
+ float transform_matrix[3][3],
+ struct rctf *src_crop,
+ const eIMBInterpolationFilterMode filter);
+
/* ffmpeg */
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
diff --git a/source/blender/imbuf/intern/IMB_indexer.h b/source/blender/imbuf/intern/IMB_indexer.h
index 363ad45e0e6..37309ccc13a 100644
--- a/source/blender/imbuf/intern/IMB_indexer.h
+++ b/source/blender/imbuf/intern/IMB_indexer.h
@@ -49,6 +49,7 @@
typedef struct anim_index_entry {
int frameno;
uint64_t seek_pos;
+ uint64_t seek_pos_pts;
uint64_t seek_pos_dts;
uint64_t pts;
} anim_index_entry;
@@ -77,14 +78,19 @@ typedef struct anim_index_builder {
} anim_index_builder;
anim_index_builder *IMB_index_builder_create(const char *name);
-void IMB_index_builder_add_entry(
- anim_index_builder *fp, int frameno, uint64_t seek_pos, uint64_t seek_pos_dts, uint64_t pts);
+void IMB_index_builder_add_entry(anim_index_builder *fp,
+ int frameno,
+ uint64_t seek_pos,
+ uint64_t seek_pos_pts,
+ uint64_t seek_pos_dts,
+ uint64_t pts);
void IMB_index_builder_proc_frame(anim_index_builder *fp,
unsigned char *buffer,
int data_size,
int frameno,
uint64_t seek_pos,
+ uint64_t seek_pos_pts,
uint64_t seek_pos_dts,
uint64_t pts);
@@ -92,6 +98,7 @@ void IMB_index_builder_finish(anim_index_builder *fp, int rollback);
struct anim_index *IMB_indexer_open(const char *name);
uint64_t IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index);
+uint64_t IMB_indexer_get_seek_pos_pts(struct anim_index *idx, int frame_index);
uint64_t IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index);
int IMB_indexer_get_frame_index(struct anim_index *idx, int frameno);
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index b65c3e364db..450c76630a8 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -924,7 +924,7 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->cur_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+ anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
if (anim->pFrame->key_frame) {
anim->cur_key_frame_pts = anim->cur_pts;
@@ -949,7 +949,7 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->cur_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+ anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
if (anim->pFrame->key_frame) {
anim->cur_key_frame_pts = anim->cur_pts;
@@ -1048,25 +1048,31 @@ static int64_t ffmpeg_get_seek_pos(struct anim *anim, int position)
return pos;
}
+/* This gives us an estimate of which pts our requested frame will have.
+ * Note that this might be off a bit in certain video files, but it should still be close enough.
+ */
static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
struct anim_index *tc_index,
int position)
{
int64_t pts_to_search;
- int64_t st_time = anim->pFormatCtx->start_time;
- AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
- double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
- double pts_time_base = av_q2d(v_st->time_base);
if (tc_index) {
int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
pts_to_search = IMB_indexer_get_pts(tc_index, new_frame_index);
}
else {
- pts_to_search = (long long)floor(((double)position) / pts_time_base / frame_rate + 0.5);
+ int64_t st_time = anim->pFormatCtx->start_time;
+ AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
+ AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL);
+ AVRational time_base = v_st->time_base;
+
+ int64_t steps_per_frame = (frame_rate.den * time_base.den) / (frame_rate.num * time_base.num);
+ pts_to_search = position * steps_per_frame;
- if (st_time != AV_NOPTS_VALUE) {
- pts_to_search += st_time / pts_time_base / AV_TIME_BASE;
+ if (st_time != AV_NOPTS_VALUE && st_time != 0) {
+ int64_t start_frame = (double)st_time / AV_TIME_BASE * av_q2d(frame_rate);
+ pts_to_search += start_frame * steps_per_frame;
}
}
return pts_to_search;
@@ -1100,6 +1106,7 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea
(int64_t)pts_to_search);
int64_t start_gop_frame = anim->cur_key_frame_pts;
+ bool scan_fuzzy = false;
while (anim->cur_pts < pts_to_search) {
av_log(anim->pFormatCtx,
@@ -1114,6 +1121,14 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea
if (start_gop_frame != anim->cur_key_frame_pts) {
break;
}
+
+ if (anim->cur_pts < pts_to_search &&
+ anim->cur_pts + anim->pFrame->pkt_duration > pts_to_search) {
+ /* Our estimate of the pts was a bit off, but we have the frame we want. */
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN fuzzy frame match\n");
+ scan_fuzzy = true;
+ break;
+ }
}
if (start_gop_frame != anim->cur_key_frame_pts) {
@@ -1126,7 +1141,8 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea
(int64_t)anim->cur_pts,
(int64_t)pts_to_search);
}
- if (anim->cur_pts == pts_to_search) {
+
+ if (scan_fuzzy || anim->cur_pts == pts_to_search) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
}
else {
@@ -1139,17 +1155,19 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea
* necessary I-frame is not honored. It is not even guaranteed that I-frame, that must be
* decoded will be read. See https://trac.ffmpeg.org/ticket/1607 and
* https://developer.blender.org/T86944. */
-static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t *requested_pos)
+static int ffmpeg_generic_seek_workaround(struct anim *anim,
+ int64_t *requested_pos,
+ int64_t pts_to_search)
{
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
int64_t current_pos = *requested_pos;
+ int64_t offset = 0;
+
+ int64_t cur_pts, prev_pts = -1;
- /* This time offset maximum limit is arbitrary. If some files fails to decode it may be
- * increased. Seek performance will be negatively affected. Small initial offset is
- * necessary because encoder can re-arrange frames as it needs but within it's delay, which
- * is usually small. */
- for (int offset = 5; offset < 25; offset++) {
+ /* Step backward frame by frame until we find the key frame we are looking for. */
+ while (current_pos != 0) {
current_pos = *requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate);
current_pos = max_ii(current_pos, 0);
@@ -1161,17 +1179,34 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t *requested_
/* Read first video stream packet. */
AVPacket *read_packet = av_packet_alloc();
while (av_read_frame(anim->pFormatCtx, read_packet) >= 0) {
- if (anim->cur_packet->stream_index == anim->videoStream) {
+ if (read_packet->stream_index == anim->videoStream) {
break;
}
+ av_packet_unref(read_packet);
}
- /* If this packet contains I-frame, exit loop. This should be the frame that we need. */
+ /* If this packet contains an I-frame, this could be the frame that we need. */
bool is_key_frame = read_packet->flags & AV_PKT_FLAG_KEY;
+ /* We need to check the packet timestamp as the key frame could be for a GOP forward in the the
+ * video stream. So if it has a larger timestamp than the frame we want, ignore it.
+ */
+ cur_pts = timestamp_from_pts_or_dts(read_packet->pts, read_packet->dts);
av_packet_free(&read_packet);
+
if (is_key_frame) {
- break;
+ if (cur_pts <= pts_to_search) {
+ /* We found the I-frame we were looking for! */
+ break;
+ }
+ if (cur_pts == prev_pts) {
+ /* We got the same key frame packet twice.
+ * This probably means that we have hit the beginning of the stream. */
+ break;
+ }
}
+
+ prev_pts = cur_pts;
+ offset++;
}
*requested_pos = current_pos;
@@ -1181,10 +1216,11 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t *requested_
}
/* Seek to last necessary key frame. */
-static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim_index *tc_index)
+static int ffmpeg_seek_to_key_frame(struct anim *anim,
+ int position,
+ struct anim_index *tc_index,
+ int64_t pts_to_search)
{
- AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
-
int64_t pos;
int ret;
@@ -1197,25 +1233,28 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim
/* No need to seek, return early. */
return 0;
}
+ uint64_t pts;
uint64_t dts;
pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index);
+ pts = IMB_indexer_get_seek_pos_pts(tc_index, new_frame_index);
dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index);
- anim->cur_key_frame_pts = pos;
+ anim->cur_key_frame_pts = timestamp_from_pts_or_dts(pts, dts);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pts = %" PRIu64 "\n", pts);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts);
if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE pos\n");
ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BYTE);
- av_update_cur_dts(anim->pFormatCtx, v_st, dts);
}
else {
- av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using DTS pos\n");
- ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, dts, AVSEEK_FLAG_BACKWARD);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using PTS pos\n");
+ ret = av_seek_frame(
+ anim->pFormatCtx, anim->videoStream, anim->cur_key_frame_pts, AVSEEK_FLAG_BACKWARD);
}
}
else {
@@ -1230,7 +1269,7 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim
ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
}
else {
- ret = ffmpeg_generic_seek_workaround(anim, &pos);
+ ret = ffmpeg_generic_seek_workaround(anim, &pos, pts_to_search);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "Adjusted final seek pos = %" PRId64 "\n", pos);
}
@@ -1243,31 +1282,40 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim
}
av_packet_unref(current_gop_start_packet);
}
- bool same_gop = current_gop_start_packet->pts == anim->cur_key_frame_pts;
+ int64_t gop_pts = timestamp_from_pts_or_dts(current_gop_start_packet->pts,
+ current_gop_start_packet->dts);
+
+ av_packet_free(&current_gop_start_packet);
+ bool same_gop = gop_pts == anim->cur_key_frame_pts;
if (same_gop && position > anim->cur_position) {
/* Change back to our old frame position so we can simply continue decoding from there. */
+ int64_t cur_pts = timestamp_from_pts_or_dts(anim->cur_packet->pts, anim->cur_packet->dts);
+
+ if (cur_pts == gop_pts) {
+ /* We are already at the correct position. */
+ return 0;
+ }
AVPacket *temp = av_packet_alloc();
+
while (av_read_frame(anim->pFormatCtx, temp) >= 0) {
- if (temp->stream_index == anim->videoStream && temp->pts == anim->cur_packet->pts) {
+ int64_t temp_pts = timestamp_from_pts_or_dts(temp->pts, temp->dts);
+ if (temp->stream_index == anim->videoStream && temp_pts == cur_pts) {
break;
}
av_packet_unref(temp);
}
- av_packet_free(&current_gop_start_packet);
av_packet_free(&temp);
return 0;
}
- anim->cur_key_frame_pts = current_gop_start_packet->pts;
- av_packet_free(&current_gop_start_packet);
+ anim->cur_key_frame_pts = gop_pts;
/* Seek back so we are at the correct position after we decoded a frame. */
av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
}
}
if (ret < 0) {
- int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
av_log(anim->pFormatCtx,
AV_LOG_ERROR,
"FETCH: "
@@ -1278,6 +1326,8 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim
pts_to_search,
ret);
}
+ /* Flush the internal buffers of ffmpeg. This needs to be done after seeking to avoid decoding
+ * errors. */
avcodec_flush_buffers(anim->pCodecCtx);
anim->cur_pts = -1;
@@ -1328,7 +1378,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: no seek necessary, just continue...\n");
ffmpeg_decode_video_frame(anim);
}
- else if (ffmpeg_seek_to_key_frame(anim, position, tc_index) >= 0) {
+ else if (ffmpeg_seek_to_key_frame(anim, position, tc_index, pts_to_search) >= 0) {
ffmpeg_decode_video_frame_scan(anim, pts_to_search);
}
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 68d0b516828..71e513fb405 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -3539,12 +3539,11 @@ typedef struct PartialThreadData {
int xmin, ymin, xmax;
} PartialThreadData;
-static void partial_buffer_update_rect_thread_do(void *data_v,
- int start_scanline,
- int num_scanlines)
+static void partial_buffer_update_rect_thread_do(void *data_v, int scanline)
{
PartialThreadData *data = (PartialThreadData *)data_v;
- int ymin = data->ymin + start_scanline;
+ int ymin = data->ymin + scanline;
+ const int num_scanlines = 1;
partial_buffer_update_rect(data->ibuf,
data->display_buffer,
data->linear_buffer,
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
index a05c7e2a70d..1a67975b5f0 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.cpp
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -113,9 +113,8 @@ void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y)
const uint idx = ((y + by) * w + x + bx);
Color32 &c = color(e, i);
- c.r = uint8(255 * CLAMP(data[idx + 0 * srcPlane],
- 0.0f,
- 1.0f)); /* @@ Is this the right way to quantize floats to bytes? */
+ /* @@ Is this the right way to quantize floats to bytes? */
+ c.r = uint8(255 * CLAMP(data[idx + 0 * srcPlane], 0.0f, 1.0f));
c.g = uint8(255 * CLAMP(data[idx + 1 * srcPlane], 0.0f, 1.0f));
c.b = uint8(255 * CLAMP(data[idx + 2 * srcPlane], 0.0f, 1.0f));
c.a = uint8(255 * CLAMP(data[idx + 3 * srcPlane], 0.0f, 1.0f));
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 5f580449e12..47712456014 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -536,13 +536,12 @@ typedef struct FloatToFloatThreadData {
int stride_from;
} FloatToFloatThreadData;
-static void imb_buffer_float_from_float_thread_do(void *data_v,
- int start_scanline,
- int num_scanlines)
+static void imb_buffer_float_from_float_thread_do(void *data_v, int scanline)
{
+ const int num_scanlines = 1;
FloatToFloatThreadData *data = (FloatToFloatThreadData *)data_v;
- size_t offset_from = ((size_t)start_scanline) * data->stride_from * data->channels_from;
- size_t offset_to = ((size_t)start_scanline) * data->stride_to * data->channels_from;
+ size_t offset_from = ((size_t)scanline) * data->stride_from * data->channels_from;
+ size_t offset_to = ((size_t)scanline) * data->stride_to * data->channels_from;
IMB_buffer_float_from_float(data->rect_to + offset_to,
data->rect_from + offset_from,
data->channels_from,
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 1fe3a7717fb..e2d469ab5a3 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -127,6 +127,22 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
/** \name Bi-Linear Interpolation
* \{ */
+BLI_INLINE void bilinear_interpolation_color_fl(
+ struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+{
+ BLI_assert(outF);
+ BLI_assert(in->rect_float);
+ BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
+}
+
+BLI_INLINE void bilinear_interpolation_color_char(
+ struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+{
+ BLI_assert(outI);
+ BLI_assert(in->rect);
+ BLI_bilinear_interpolation_char((unsigned char *)in->rect, outI, in->x, in->y, 4, u, v);
+}
+
void bilinear_interpolation_color(
struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
@@ -238,60 +254,58 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i
/** \name Nearest Interpolation
* \{ */
-/* function assumes out to be zero'ed, only does RGBA */
-void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+/* functions assumes out to be zero'ed, only does RGBA */
+BLI_INLINE void nearest_interpolation_color_char(
+ struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
- const float *dataF;
- unsigned char *dataI;
- int y1, x1;
-
+ BLI_assert(outI);
+ BLI_assert(in->rect);
/* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+ int x1 = (int)(u);
+ int y1 = (int)(v);
- x1 = (int)(u);
- y1 = (int)(v);
+ /* sample area entirely outside image? */
+ if (x1 < 0 || x1 >= in->x || y1 < 0 || y1 >= in->y) {
+ outI[0] = outI[1] = outI[2] = outI[3] = 0;
+ return;
+ }
+
+ const size_t offset = (in->x * y1 + x1) * 4;
+ const unsigned char *dataI = (unsigned char *)in->rect + offset;
+ outI[0] = dataI[0];
+ outI[1] = dataI[1];
+ outI[2] = dataI[2];
+ outI[3] = dataI[3];
+}
+
+BLI_INLINE void nearest_interpolation_color_fl(
+ struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+{
+ BLI_assert(outF);
+ BLI_assert(in->rect_float);
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+ int x1 = (int)(u);
+ int y1 = (int)(v);
/* sample area entirely outside image? */
- if (x1 < 0 || x1 > in->x - 1 || y1 < 0 || y1 > in->y - 1) {
- if (outI) {
- outI[0] = outI[1] = outI[2] = outI[3] = 0;
- }
- if (outF) {
- outF[0] = outF[1] = outF[2] = outF[3] = 0.0f;
- }
+ if (x1 < 0 || x1 >= in->x || y1 < 0 || y1 >= in->y) {
+ zero_v4(outF);
return;
}
- /* sample including outside of edges of image */
- if (x1 < 0 || y1 < 0) {
- if (outI) {
- outI[0] = 0;
- outI[1] = 0;
- outI[2] = 0;
- outI[3] = 0;
- }
- if (outF) {
- outF[0] = 0.0f;
- outF[1] = 0.0f;
- outF[2] = 0.0f;
- outF[3] = 0.0f;
- }
+ const size_t offset = (in->x * y1 + x1) * 4;
+ const float *dataF = in->rect_float + offset;
+ copy_v4_v4(outF, dataF);
+}
+
+void nearest_interpolation_color(
+ struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+{
+ if (outF) {
+ nearest_interpolation_color_fl(in, outI, outF, u, v);
}
else {
- dataI = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
- if (outI) {
- outI[0] = dataI[0];
- outI[1] = dataI[1];
- outI[2] = dataI[2];
- outI[3] = dataI[3];
- }
- dataF = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
- if (outF) {
- outF[0] = dataF[0];
- outF[1] = dataF[1];
- outF[2] = dataF[2];
- outF[3] = dataF[3];
- }
+ nearest_interpolation_color_char(in, outI, outF, u, v);
}
}
@@ -350,6 +364,141 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
}
/* -------------------------------------------------------------------- */
+/** \name Image transform
+ * \{ */
+typedef struct TransformUserData {
+ ImBuf *src;
+ ImBuf *dst;
+ float start_uv[2];
+ float add_x[2];
+ float add_y[2];
+ rctf src_crop;
+} TransformUserData;
+
+static void imb_transform_calc_start_uv(const float transform_matrix[3][3], float r_start_uv[2])
+{
+ float orig[2];
+ orig[0] = 0.0f;
+ orig[1] = 0.0f;
+ mul_v2_m3v2(r_start_uv, transform_matrix, orig);
+}
+
+static void imb_transform_calc_add_x(const float transform_matrix[3][3],
+ const float start_uv[2],
+ const int width,
+ float r_add_x[2])
+{
+ float uv_max_x[2];
+ uv_max_x[0] = width;
+ uv_max_x[1] = 0.0f;
+ mul_v2_m3v2(r_add_x, transform_matrix, uv_max_x);
+ sub_v2_v2(r_add_x, start_uv);
+ mul_v2_fl(r_add_x, 1.0f / width);
+}
+
+static void imb_transform_calc_add_y(const float transform_matrix[3][3],
+ const float start_uv[2],
+ const int height,
+ float r_add_y[2])
+{
+ float uv_max_y[2];
+ uv_max_y[0] = 0.0f;
+ uv_max_y[1] = height;
+ mul_v2_m3v2(r_add_y, transform_matrix, uv_max_y);
+ sub_v2_v2(r_add_y, start_uv);
+ mul_v2_fl(r_add_y, 1.0f / height);
+}
+
+typedef void (*InterpolationColorFunction)(
+ struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+BLI_INLINE void imb_transform_scanlines(const TransformUserData *user_data,
+ int scanline,
+ InterpolationColorFunction interpolation)
+{
+ const int width = user_data->dst->x;
+
+ float uv[2];
+ madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
+
+ unsigned char *outI = NULL;
+ float *outF = NULL;
+ pixel_from_buffer(user_data->dst, &outI, &outF, 0, scanline);
+
+ for (int xi = 0; xi < width; xi++) {
+ if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax &&
+ uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) {
+ interpolation(user_data->src, outI, outF, uv[0], uv[1]);
+ }
+ add_v2_v2(uv, user_data->add_x);
+ if (outI) {
+ outI += 4;
+ }
+ if (outF) {
+ outF += 4;
+ }
+ }
+}
+
+static void imb_transform_nearest_scanlines(void *custom_data, int scanline)
+{
+ const TransformUserData *user_data = custom_data;
+ InterpolationColorFunction interpolation = NULL;
+ if (user_data->dst->rect_float) {
+ interpolation = nearest_interpolation_color_fl;
+ }
+ else {
+ interpolation = nearest_interpolation_color_char;
+ }
+ imb_transform_scanlines(user_data, scanline, interpolation);
+}
+
+static void imb_transform_bilinear_scanlines(void *custom_data, int scanline)
+{
+ const TransformUserData *user_data = custom_data;
+ InterpolationColorFunction interpolation = NULL;
+ if (user_data->dst->rect_float) {
+ interpolation = bilinear_interpolation_color_fl;
+ }
+ else if (user_data->dst->rect) {
+ interpolation = bilinear_interpolation_color_char;
+ }
+ imb_transform_scanlines(user_data, scanline, interpolation);
+}
+
+static ScanlineThreadFunc imb_transform_scanline_func(const eIMBInterpolationFilterMode filter)
+{
+ ScanlineThreadFunc scanline_func = NULL;
+ switch (filter) {
+ case IMB_FILTER_NEAREST:
+ scanline_func = imb_transform_nearest_scanlines;
+ break;
+ case IMB_FILTER_BILINEAR:
+ scanline_func = imb_transform_bilinear_scanlines;
+ break;
+ }
+ return scanline_func;
+}
+
+void IMB_transform(struct ImBuf *src,
+ struct ImBuf *dst,
+ float transform_matrix[3][3],
+ struct rctf *src_crop,
+ const eIMBInterpolationFilterMode filter)
+{
+ TransformUserData user_data;
+ user_data.src = src;
+ user_data.dst = dst;
+ user_data.src_crop = *src_crop;
+ imb_transform_calc_start_uv(transform_matrix, user_data.start_uv);
+ imb_transform_calc_add_x(transform_matrix, user_data.start_uv, src->x, user_data.add_x);
+ imb_transform_calc_add_y(transform_matrix, user_data.start_uv, src->y, user_data.add_y);
+ ScanlineThreadFunc scanline_func = imb_transform_scanline_func(filter);
+ IMB_processor_apply_threaded_scanlines(dst->y, scanline_func, &user_data);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Threaded Image Processing
* \{ */
@@ -374,7 +523,7 @@ void IMB_processor_apply_threaded(
int total_tasks = (buffer_lines + lines_per_task - 1) / lines_per_task;
int i, start_line;
- task_pool = BLI_task_pool_create(do_thread, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
+ task_pool = BLI_task_pool_create(do_thread, TASK_PRIORITY_LOW);
handles = MEM_callocN(handle_size * total_tasks, "processor apply threaded handles");
@@ -409,41 +558,28 @@ void IMB_processor_apply_threaded(
typedef struct ScanlineGlobalData {
void *custom_data;
ScanlineThreadFunc do_thread;
- int scanlines_per_task;
- int total_scanlines;
} ScanlineGlobalData;
-static void processor_apply_scanline_func(TaskPool *__restrict pool, void *taskdata)
+static void processor_apply_parallel(void *__restrict userdata,
+ const int scanline,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
- ScanlineGlobalData *data = BLI_task_pool_user_data(pool);
- int start_scanline = POINTER_AS_INT(taskdata);
- int num_scanlines = min_ii(data->scanlines_per_task, data->total_scanlines - start_scanline);
- data->do_thread(data->custom_data, start_scanline, num_scanlines);
+ ScanlineGlobalData *data = userdata;
+ data->do_thread(data->custom_data, scanline);
}
void IMB_processor_apply_threaded_scanlines(int total_scanlines,
ScanlineThreadFunc do_thread,
void *custom_data)
{
- const int scanlines_per_task = 64;
- ScanlineGlobalData data;
- data.custom_data = custom_data;
- data.do_thread = do_thread;
- data.scanlines_per_task = scanlines_per_task;
- data.total_scanlines = total_scanlines;
- const int total_tasks = (total_scanlines + scanlines_per_task - 1) / scanlines_per_task;
- TaskPool *task_pool = BLI_task_pool_create(&data, TASK_PRIORITY_LOW, TASK_ISOLATION_ON);
- for (int i = 0, start_line = 0; i < total_tasks; i++) {
- BLI_task_pool_push(
- task_pool, processor_apply_scanline_func, POINTER_FROM_INT(start_line), false, NULL);
- start_line += scanlines_per_task;
- }
-
- /* work and wait until tasks are done */
- BLI_task_pool_work_and_wait(task_pool);
-
- /* Free memory. */
- BLI_task_pool_free(task_pool);
+ TaskParallelSettings settings;
+ ScanlineGlobalData data = {
+ .do_thread = do_thread,
+ .custom_data = custom_data,
+ };
+
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, total_scanlines, &data, processor_apply_parallel, &settings);
}
/** \} */
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 4d116eb73b8..a530acb15b0 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -50,7 +50,7 @@
# include <libavutil/imgutils.h>
#endif
-static const char magic[] = "BlenMIdx";
+static const char binary_header_str[] = "BlenMIdx";
static const char temp_ext[] = "_part";
static const int proxy_sizes[] = {IMB_PROXY_25, IMB_PROXY_50, IMB_PROXY_75, IMB_PROXY_100};
@@ -65,7 +65,7 @@ static int tc_types[] = {
};
#endif
-#define INDEX_FILE_VERSION 1
+#define INDEX_FILE_VERSION 2
/* ----------------------------------------------------------------------
* - time code index functions
@@ -96,16 +96,25 @@ anim_index_builder *IMB_index_builder_create(const char *name)
return NULL;
}
- fprintf(rv->fp, "%s%c%.3d", magic, (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v', INDEX_FILE_VERSION);
+ fprintf(rv->fp,
+ "%s%c%.3d",
+ binary_header_str,
+ (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v',
+ INDEX_FILE_VERSION);
return rv;
}
-void IMB_index_builder_add_entry(
- anim_index_builder *fp, int frameno, uint64_t seek_pos, uint64_t seek_pos_dts, uint64_t pts)
+void IMB_index_builder_add_entry(anim_index_builder *fp,
+ int frameno,
+ uint64_t seek_pos,
+ uint64_t seek_pos_pts,
+ uint64_t seek_pos_dts,
+ uint64_t pts)
{
fwrite(&frameno, sizeof(int), 1, fp->fp);
fwrite(&seek_pos, sizeof(uint64_t), 1, fp->fp);
+ fwrite(&seek_pos_pts, sizeof(uint64_t), 1, fp->fp);
fwrite(&seek_pos_dts, sizeof(uint64_t), 1, fp->fp);
fwrite(&pts, sizeof(uint64_t), 1, fp->fp);
}
@@ -115,6 +124,7 @@ void IMB_index_builder_proc_frame(anim_index_builder *fp,
int data_size,
int frameno,
uint64_t seek_pos,
+ uint64_t seek_pos_pts,
uint64_t seek_pos_dts,
uint64_t pts)
{
@@ -122,13 +132,14 @@ void IMB_index_builder_proc_frame(anim_index_builder *fp,
anim_index_entry e;
e.frameno = frameno;
e.seek_pos = seek_pos;
+ e.seek_pos_pts = seek_pos_pts;
e.seek_pos_dts = seek_pos_dts;
e.pts = pts;
fp->proc_frame(fp, buffer, data_size, &e);
}
else {
- IMB_index_builder_add_entry(fp, frameno, seek_pos, seek_pos_dts, pts);
+ IMB_index_builder_add_entry(fp, frameno, seek_pos, seek_pos_pts, seek_pos_dts, pts);
}
}
@@ -159,22 +170,26 @@ struct anim_index *IMB_indexer_open(const char *name)
int i;
if (!fp) {
+ fprintf(stderr, "Couldn't open indexer file: %s\n", name);
return NULL;
}
if (fread(header, 12, 1, fp) != 1) {
+ fprintf(stderr, "Couldn't read indexer file: %s\n", name);
fclose(fp);
return NULL;
}
header[12] = 0;
- if (memcmp(header, magic, 8) != 0) {
+ if (memcmp(header, binary_header_str, 8) != 0) {
+ fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name);
fclose(fp);
return NULL;
}
if (atoi(header + 9) != INDEX_FILE_VERSION) {
+ fprintf(stderr, "Error reading %s: File version missmatch\n", name);
fclose(fp);
return NULL;
}
@@ -187,6 +202,7 @@ struct anim_index *IMB_indexer_open(const char *name)
idx->num_entries = (ftell(fp) - 12) / (sizeof(int) + /* framepos */
sizeof(uint64_t) + /* seek_pos */
+ sizeof(uint64_t) + /* seek_pos_pts */
sizeof(uint64_t) + /* seek_pos_dts */
sizeof(uint64_t) /* pts */
);
@@ -200,12 +216,13 @@ struct anim_index *IMB_indexer_open(const char *name)
for (i = 0; i < idx->num_entries; i++) {
items_read += fread(&idx->entries[i].frameno, sizeof(int), 1, fp);
items_read += fread(&idx->entries[i].seek_pos, sizeof(uint64_t), 1, fp);
+ items_read += fread(&idx->entries[i].seek_pos_pts, sizeof(uint64_t), 1, fp);
items_read += fread(&idx->entries[i].seek_pos_dts, sizeof(uint64_t), 1, fp);
items_read += fread(&idx->entries[i].pts, sizeof(uint64_t), 1, fp);
}
- if (UNLIKELY(items_read != idx->num_entries * 4)) {
- perror("error reading animation index file");
+ if (UNLIKELY(items_read != idx->num_entries * 5)) {
+ fprintf(stderr, "Error: Element data size missmatch in: %s\n", name);
MEM_freeN(idx->entries);
MEM_freeN(idx);
fclose(fp);
@@ -216,6 +233,7 @@ struct anim_index *IMB_indexer_open(const char *name)
for (i = 0; i < idx->num_entries; i++) {
BLI_endian_switch_int32(&idx->entries[i].frameno);
BLI_endian_switch_uint64(&idx->entries[i].seek_pos);
+ BLI_endian_switch_uint64(&idx->entries[i].seek_pos_pts);
BLI_endian_switch_uint64(&idx->entries[i].seek_pos_dts);
BLI_endian_switch_uint64(&idx->entries[i].pts);
}
@@ -237,6 +255,17 @@ uint64_t IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index)
return idx->entries[frame_index].seek_pos;
}
+uint64_t IMB_indexer_get_seek_pos_pts(struct anim_index *idx, int frame_index)
+{
+ if (frame_index < 0) {
+ frame_index = 0;
+ }
+ if (frame_index >= idx->num_entries) {
+ frame_index = idx->num_entries - 1;
+ }
+ return idx->entries[frame_index].seek_pos_pts;
+}
+
uint64_t IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index)
{
if (frame_index < 0) {
@@ -318,8 +347,7 @@ int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
{
switch (pr_size) {
case IMB_PROXY_NONE:
- /* if we got here, something is broken anyways, so sane defaults... */
- return 0;
+ return -1;
case IMB_PROXY_25:
return 0;
case IMB_PROXY_50:
@@ -329,16 +357,16 @@ int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
case IMB_PROXY_100:
return 3;
default:
- return 0;
+ BLI_assert(!"Unhandled proxy size enum!");
+ return -1;
}
}
int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
{
switch (tc) {
- case IMB_TC_NONE: /* if we got here, something is broken anyways,
- * so sane defaults... */
- return 0;
+ case IMB_TC_NONE:
+ return -1;
case IMB_TC_RECORD_RUN:
return 0;
case IMB_TC_FREE_RUN:
@@ -348,7 +376,8 @@ int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
case IMB_TC_RECORD_RUN_NO_GAPS:
return 3;
default:
- return 0;
+ BLI_assert(!"Unhandled timecode type enum!");
+ return -1;
}
}
@@ -384,6 +413,8 @@ static bool get_proxy_filename(struct anim *anim,
char index_dir[FILE_MAXDIR];
int i = IMB_proxy_size_to_array_index(preview_size);
+ BLI_assert(i >= 0);
+
char proxy_name[256];
char stream_suffix[20];
const char *name = (temp) ? "proxy_%d%s_part.avi" : "proxy_%d%s.avi";
@@ -415,6 +446,9 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname
{
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
+
+ BLI_assert(i >= 0);
+
const char *index_names[] = {
"record_run%s%s.blen_tc",
"free_run%s%s.blen_tc",
@@ -771,9 +805,10 @@ typedef struct FFmpegIndexBuilderContext {
IMB_Proxy_Size proxy_sizes_in_use;
uint64_t seek_pos;
- uint64_t last_seek_pos;
- uint64_t seek_pos_dts;
uint64_t seek_pos_pts;
+ uint64_t seek_pos_dts;
+ uint64_t last_seek_pos;
+ uint64_t last_seek_pos_pts;
uint64_t last_seek_pos_dts;
uint64_t start_pts;
double frame_rate;
@@ -926,8 +961,9 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
{
int i;
uint64_t s_pos = context->seek_pos;
+ uint64_t s_pts = context->seek_pos_pts;
uint64_t s_dts = context->seek_pos_dts;
- uint64_t pts = av_get_pts_from_frame(context->iFormatCtx, in_frame);
+ uint64_t pts = av_get_pts_from_frame(in_frame);
for (i = 0; i < context->num_proxy_sizes; i++) {
add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame);
@@ -941,15 +977,15 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
context->frameno = floor(
(pts - context->start_pts) * context->pts_time_base * context->frame_rate + 0.5);
- /* decoding starts *always* on I-Frames,
- * so: P-Frames won't work, even if all the
- * information is in place, when we seek
- * to the I-Frame presented *after* the P-Frame,
- * but located before the P-Frame within
- * the stream */
+ int64_t seek_pos_pts = timestamp_from_pts_or_dts(context->seek_pos_pts, context->seek_pos_dts);
- if (pts < context->seek_pos_pts) {
+ if (pts < seek_pos_pts) {
+ /* Decoding starts *always* on I-Frames. In this case our position is
+ * before our seek I-Frame. So we need to pick the previous available
+ * I-Frame to be able to decode this one properly.
+ */
s_pos = context->last_seek_pos;
+ s_pts = context->last_seek_pos_pts;
s_dts = context->last_seek_pos_dts;
}
@@ -966,6 +1002,7 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
curr_packet->size,
tc_frameno,
s_pos,
+ s_pts,
s_dts,
pts);
}
@@ -1004,10 +1041,12 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
if (next_packet->stream_index == context->videoStream) {
if (next_packet->flags & AV_PKT_FLAG_KEY) {
context->last_seek_pos = context->seek_pos;
+ context->last_seek_pos_pts = context->seek_pos_pts;
context->last_seek_pos_dts = context->seek_pos_dts;
+
context->seek_pos = next_packet->pos;
- context->seek_pos_dts = next_packet->dts;
context->seek_pos_pts = next_packet->pts;
+ context->seek_pos_dts = next_packet->dts;
}
int ret = avcodec_send_packet(context->iCodecCtx, next_packet);
@@ -1389,6 +1428,10 @@ struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
char fname[FILE_MAX];
int i = IMB_proxy_size_to_array_index(preview_size);
+ if (i < 0) {
+ return NULL;
+ }
+
if (anim->proxy_anim[i]) {
return anim->proxy_anim[i];
}
@@ -1412,6 +1455,10 @@ struct anim_index *IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc)
char fname[FILE_MAX];
int i = IMB_timecode_to_array_index(tc);
+ if (i < 0) {
+ return NULL;
+ }
+
if (anim->curr_idx[i]) {
return anim->curr_idx[i];
}
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 6ae93def50f..4b5d68b9c13 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -988,8 +988,9 @@ typedef struct RectBlendThreadData {
bool accumulate;
} RectBlendThreadData;
-static void rectblend_thread_do(void *data_v, int start_scanline, int num_scanlines)
+static void rectblend_thread_do(void *data_v, int scanline)
{
+ const int num_scanlines = 1;
RectBlendThreadData *data = (RectBlendThreadData *)data_v;
IMB_rectblend(data->dbuf,
data->obuf,
@@ -999,11 +1000,11 @@ static void rectblend_thread_do(void *data_v, int start_scanline, int num_scanli
data->texmask,
data->mask_max,
data->destx,
- data->desty + start_scanline,
+ data->desty + scanline,
data->origx,
- data->origy + start_scanline,
+ data->origy + scanline,
data->srcx,
- data->srcy + start_scanline,
+ data->srcy + scanline,
data->width,
num_scanlines,
data->mode,
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 61bc185eb8d..7b4bf704096 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -112,13 +112,13 @@ static bool get_thumb_dir(char *dir, ThumbSize size)
#endif
switch (size) {
case THB_NORMAL:
- subdir = "/" THUMBNAILS "/normal/";
+ subdir = SEP_STR THUMBNAILS SEP_STR "normal" SEP_STR;
break;
case THB_LARGE:
- subdir = "/" THUMBNAILS "/large/";
+ subdir = SEP_STR THUMBNAILS SEP_STR "large" SEP_STR;
break;
case THB_FAIL:
- subdir = "/" THUMBNAILS "/fail/blender/";
+ subdir = SEP_STR THUMBNAILS SEP_STR "fail" SEP_STR "blender" SEP_STR;
break;
default:
return 0; /* unknown size */
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index b7b31b3e56a..48e7f171bb4 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -47,7 +47,8 @@ ImBuf *IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const
if (blen_group && blen_id) {
LinkNode *ln, *names, *lp, *previews = NULL;
- struct BlendHandle *libfiledata = BLO_blendhandle_from_file(blen_path, NULL);
+ struct BlendHandle *libfiledata = BLO_blendhandle_from_file(
+ blen_path, &(BlendFileReadReport){.reports = NULL});
int idcode = BKE_idtype_idcode_from_name(blen_group);
int i, nprevs, nnames;
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index ccf353595c9..e3ed897458d 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -44,6 +44,7 @@
* in the write code for the conventions. */
using Alembic::AbcGeom::kFacevaryingScope;
+using Alembic::AbcGeom::kVaryingScope;
using Alembic::AbcGeom::kVertexScope;
using Alembic::Abc::C4fArraySample;
@@ -292,6 +293,7 @@ void write_custom_data(const OCompoundProperty &prop,
using Alembic::Abc::C3fArraySamplePtr;
using Alembic::Abc::C4fArraySamplePtr;
using Alembic::Abc::PropertyHeader;
+using Alembic::Abc::UInt32ArraySamplePtr;
using Alembic::AbcGeom::IC3fGeomParam;
using Alembic::AbcGeom::IC4fGeomParam;
@@ -300,21 +302,26 @@ using Alembic::AbcGeom::IV3fGeomParam;
static void read_uvs(const CDStreamConfig &config,
void *data,
+ const AbcUvScope uv_scope,
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
- const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
+ const UInt32ArraySamplePtr &indices)
{
MPoly *mpolys = config.mpoly;
+ MLoop *mloops = config.mloop;
MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
unsigned int uv_index, loop_index, rev_loop_index;
+ BLI_assert(uv_scope != ABC_UV_SCOPE_NONE);
+ const bool do_uvs_per_loop = (uv_scope == ABC_UV_SCOPE_LOOP);
+
for (int i = 0; i < config.totpoly; i++) {
MPoly &poly = mpolys[i];
unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1;
for (int f = 0; f < poly.totloop; f++) {
- loop_index = poly.loopstart + f;
rev_loop_index = rev_loop_offset - f;
+ loop_index = do_uvs_per_loop ? poly.loopstart + f : mloops[rev_loop_index].v;
uv_index = (*indices)[loop_index];
const Imath::V2f &uv = (*uvs)[uv_index];
@@ -473,20 +480,24 @@ static void read_custom_data_uvs(const ICompoundProperty &prop,
IV2fGeomParam::Sample sample;
uv_param.getIndexed(sample, iss);
- if (uv_param.getScope() != kFacevaryingScope) {
+ UInt32ArraySamplePtr uvs_indices = sample.getIndices();
+
+ const AbcUvScope uv_scope = get_uv_scope(uv_param.getScope(), config, uvs_indices);
+
+ if (uv_scope == ABC_UV_SCOPE_NONE) {
return;
}
void *cd_data = config.add_customdata_cb(config.mesh, prop_header.getName().c_str(), CD_MLOOPUV);
- read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
+ read_uvs(config, cd_data, uv_scope, sample.getVals(), uvs_indices);
}
void read_generated_coordinates(const ICompoundProperty &prop,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss)
{
- if (prop.getPropertyHeader(propNameOriginalCoordinates) == nullptr) {
+ if (!prop.valid() || prop.getPropertyHeader(propNameOriginalCoordinates) == nullptr) {
/* The ORCO property isn't there, so don't bother trying to process it. */
return;
}
@@ -559,4 +570,28 @@ void read_custom_data(const std::string &iobject_full_name,
}
}
+/* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
+ * vertex). The first case is the most common, as this is the standard way of storing this data
+ * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
+ * second case can happen when the mesh is split according to the UV islands, in which case storing
+ * a single UV value per vertex allows to deduplicate data and thus to reduce the file size since
+ * vertices are guaranteed to only have a single UV coordinate. */
+AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
+ const CDStreamConfig &config,
+ const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
+{
+ if (scope == kFacevaryingScope && indices->size() == config.totloop) {
+ return ABC_UV_SCOPE_LOOP;
+ }
+
+ /* kVaryingScope is sometimes used for vertex scopes as the values vary across the vertices. To
+ * be sure, one has to check the size of the data against the number of vertices, as it could
+ * also be a varying attribute across the faces (i.e. one value per face). */
+ if ((scope == kVaryingScope || scope == kVertexScope) && indices->size() == config.totvert) {
+ return ABC_UV_SCOPE_VERTEX;
+ }
+
+ return ABC_UV_SCOPE_NONE;
+}
+
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 9ee964c0545..e9736555ead 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -122,4 +122,14 @@ void read_custom_data(const std::string &iobject_full_name,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);
+typedef enum {
+ ABC_UV_SCOPE_NONE,
+ ABC_UV_SCOPE_LOOP,
+ ABC_UV_SCOPE_VERTEX,
+} AbcUvScope;
+
+AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
+ const CDStreamConfig &config,
+ const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
+
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 11b6c1c18ca..79f34f671c7 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -121,6 +121,7 @@ struct AbcMeshData {
P3fArraySamplePtr positions;
P3fArraySamplePtr ceil_positions;
+ AbcUvScope uv_scope;
V2fArraySamplePtr uvs;
UInt32ArraySamplePtr uvs_indices;
};
@@ -192,8 +193,9 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
- const bool do_uvs = (mloopuvs && uvs && uvs_indices) &&
- (uvs_indices->size() == face_indices->size());
+ const bool do_uvs = (mloopuvs && uvs && uvs_indices);
+ const bool do_uvs_per_loop = do_uvs && mesh_data.uv_scope == ABC_UV_SCOPE_LOOP;
+ BLI_assert(!do_uvs || mesh_data.uv_scope != ABC_UV_SCOPE_NONE);
unsigned int loop_index = 0;
unsigned int rev_loop_index = 0;
unsigned int uv_index = 0;
@@ -227,8 +229,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
if (do_uvs) {
MLoopUV &loopuv = mloopuvs[rev_loop_index];
-
- uv_index = (*uvs_indices)[loop_index];
+ uv_index = (*uvs_indices)[do_uvs_per_loop ? loop_index : loop.v];
/* Some Alembic files are broken (or at least export UVs in a way we don't expect). */
if (uv_index >= uvs_size) {
@@ -357,22 +358,29 @@ BLI_INLINE void read_uvs_params(CDStreamConfig &config,
IV2fGeomParam::Sample uvsamp;
uv.getIndexed(uvsamp, selector);
- abc_data.uvs = uvsamp.getVals();
- abc_data.uvs_indices = uvsamp.getIndices();
+ UInt32ArraySamplePtr uvs_indices = uvsamp.getIndices();
- if (abc_data.uvs_indices->size() == config.totloop) {
- std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
+ const AbcUvScope uv_scope = get_uv_scope(uv.getScope(), config, uvs_indices);
- /* According to the convention, primary UVs should have had their name
- * set using Alembic::Abc::SetSourceName, but you can't expect everyone
- * to follow it! :) */
- if (name.empty()) {
- name = uv.getName();
- }
+ if (uv_scope == ABC_UV_SCOPE_NONE) {
+ return;
+ }
- void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
- config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
+ abc_data.uv_scope = uv_scope;
+ abc_data.uvs = uvsamp.getVals();
+ abc_data.uvs_indices = uvs_indices;
+
+ std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
+
+ /* According to the convention, primary UVs should have had their name
+ * set using Alembic::Abc::SetSourceName, but you can't expect everyone
+ * to follow it! :) */
+ if (name.empty()) {
+ name = uv.getName();
}
+
+ void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
+ config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
}
static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
@@ -462,6 +470,7 @@ CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
config.mvert = mesh->mvert;
config.mloop = mesh->mloop;
config.mpoly = mesh->mpoly;
+ config.totvert = mesh->totvert;
config.totloop = mesh->totloop;
config.totpoly = mesh->totpoly;
config.loopdata = &mesh->ldata;
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index 0521fda5fb1..51c86ee53f2 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -67,8 +67,9 @@ BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis
mat3_from_axis_conversion(
BC_DEFAULT_FORWARD, BC_DEFAULT_UP, global_forward_axis, global_up_axis, mrot);
- transpose_m3(
- mrot); /* TODO: Verify that mat3_from_axis_conversion() returns a transposed matrix */
+ /* TODO: Verify that `mat3_from_axis_conversion()` returns a transposed matrix */
+ transpose_m3(mrot);
+
copy_m4_m3(mat, mrot);
set_transform(mat);
}
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
index 0f90855dcb8..3b20ac9f110 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -288,8 +288,8 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
}
/**
- * Set color
- * @param do_fill: True if the stroke is only fill
+ * Set color.
+ * \param do_fill: True if the stroke is only fill.
*/
void GpencilExporterPDF::color_set(bGPDlayer *gpl, const bool do_fill)
{
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
index c62764cca06..438263167ca 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -353,8 +353,8 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
/**
* Set color SVG string for stroke
- * \param node_gps: Stroke node
- * @param do_fill: True if the stroke is only fill
+ * \param node_gps: Stroke node.
+ * \param do_fill: True if the stroke is only fill.
*/
void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
bGPDstroke *gps,
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 583e56de9c2..a5ed870ee78 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -328,11 +328,12 @@ typedef struct bPoseChannel {
* and are applied on top of the copies in pchan->bone
*/
float roll1, roll2;
- float curve_in_x, curve_in_y;
- float curve_out_x, curve_out_y;
+ float curve_in_x, curve_in_z;
+ float curve_out_x, curve_out_z;
float ease1, ease2;
- float scale_in_x, scale_in_y;
- float scale_out_x, scale_out_y;
+ float scale_in_x DNA_DEPRECATED, scale_in_z DNA_DEPRECATED;
+ float scale_out_x DNA_DEPRECATED, scale_out_z DNA_DEPRECATED;
+ float scale_in[3], scale_out[3];
/** B-Bone custom handles; set on read file or rebuild pose based on pchan->bone data. */
struct bPoseChannel *bbone_prev;
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 85780bc33c5..3d83d0d2f6f 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -86,12 +86,13 @@ typedef struct Bone {
/** Curved bones settings - these define the "rest-pose" for a curved bone. */
float roll1, roll2;
- float curve_in_x, curve_in_y;
- float curve_out_x, curve_out_y;
+ float curve_in_x, curve_in_z;
+ float curve_out_x, curve_out_z;
/** Length of bezier handles. */
float ease1, ease2;
- float scale_in_x, scale_in_y;
- float scale_out_x, scale_out_y;
+ float scale_in_x DNA_DEPRECATED, scale_in_z DNA_DEPRECATED;
+ float scale_out_x DNA_DEPRECATED, scale_out_z DNA_DEPRECATED;
+ float scale_in[3], scale_out[3];
/** Patch for upward compatibility, UNUSED! */
float size[3];
@@ -103,6 +104,10 @@ typedef struct Bone {
/** Type of next/prev bone handles. */
char bbone_prev_type;
char bbone_next_type;
+ /** B-Bone flags. */
+ int bbone_flag;
+ short bbone_prev_flag;
+ short bbone_next_flag;
/** Next/prev bones to use as handle references when calculating bbones (optional). */
struct Bone *bbone_prev;
struct Bone *bbone_next;
@@ -259,8 +264,10 @@ typedef enum eBone_Flag {
BONE_NO_LOCAL_LOCATION = (1 << 22),
/** object child will use relative transform (like deform) */
BONE_RELATIVE_PARENTING = (1 << 23),
+#ifdef DNA_DEPRECATED_ALLOW
/** it will add the parent end roll to the inroll */
BONE_ADD_PARENT_END_ROLL = (1 << 24),
+#endif
/** this bone was transformed by the mirror function */
BONE_TRANSFORM_MIRROR = (1 << 25),
/** this bone is associated with a locked vertex group, ONLY USE FOR DRAWING */
@@ -291,6 +298,29 @@ typedef enum eBone_BBoneHandleType {
BBONE_HANDLE_TANGENT = 3, /* Custom handle in tangent mode (use direction, not location). */
} eBone_BBoneHandleType;
+/* bone->bbone_flag */
+typedef enum eBone_BBoneFlag {
+ /** Add the parent Out roll to the In roll. */
+ BBONE_ADD_PARENT_END_ROLL = (1 << 0),
+ /** Multiply B-Bone easing values with Scale Length. */
+ BBONE_SCALE_EASING = (1 << 1),
+} eBone_BBoneFlag;
+
+/* bone->bbone_prev/next_flag */
+typedef enum eBone_BBoneHandleFlag {
+ /** Use handle bone scaling for scale X. */
+ BBONE_HANDLE_SCALE_X = (1 << 0),
+ /** Use handle bone scaling for scale Y (length). */
+ BBONE_HANDLE_SCALE_Y = (1 << 1),
+ /** Use handle bone scaling for scale Z. */
+ BBONE_HANDLE_SCALE_Z = (1 << 2),
+ /** Use handle bone scaling for easing. */
+ BBONE_HANDLE_SCALE_EASE = (1 << 3),
+ /** Is handle scale required? */
+ BBONE_HANDLE_SCALE_ANY = BBONE_HANDLE_SCALE_X | BBONE_HANDLE_SCALE_Y | BBONE_HANDLE_SCALE_Z |
+ BBONE_HANDLE_SCALE_EASE,
+} eBone_BBoneHandleFlag;
+
#define MAXBONENAME 64
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index e4f6a1eea41..debf2c3475e 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -43,7 +43,7 @@ typedef struct CurveMapPoint {
short flag, shorty;
} CurveMapPoint;
-/* curvepoint->flag */
+/** #CurveMapPoint.flag */
enum {
CUMA_SELECT = (1 << 0),
CUMA_HANDLE_VECTOR = (1 << 1),
@@ -95,19 +95,18 @@ typedef struct CurveMapping {
char _pad[6];
} CurveMapping;
-/* CurveMapping.flag */
+/** #CurveMapping.flag */
typedef enum eCurveMappingFlags {
CUMA_DO_CLIP = (1 << 0),
CUMA_PREMULLED = (1 << 1),
CUMA_DRAW_CFRA = (1 << 2),
CUMA_DRAW_SAMPLE = (1 << 3),
- /* The curve is extended by extrapolation. When not set the curve is extended
- * Horizontally */
+ /** The curve is extended by extrapolation. When not set the curve is extended horizontally. */
CUMA_EXTEND_EXTRAPOLATE = (1 << 4),
} eCurveMappingFlags;
-/* cumapping->preset */
+/** #CurveMapping.preset */
typedef enum eCurveMappingPreset {
CURVE_PRESET_LINE = 0,
CURVE_PRESET_SHARP = 1,
@@ -120,13 +119,13 @@ typedef enum eCurveMappingPreset {
CURVE_PRESET_BELL = 8,
} eCurveMappingPreset;
-/* CurveMapping->tone */
+/** #CurveMapping.tone */
typedef enum eCurveMappingTone {
CURVE_TONE_STANDARD = 0,
CURVE_TONE_FILMLIKE = 2,
} eCurveMappingTone;
-/* histogram->mode */
+/** #Histogram.mode */
enum {
HISTO_MODE_LUMA = 0,
HISTO_MODE_RGB = 1,
@@ -154,8 +153,7 @@ typedef struct Histogram {
short flag;
int height;
- /* sample line only */
- /* image coords src -> dst */
+ /** Sample line only (image coords: source -> destination). */
float co[2][2];
} Histogram;
@@ -180,13 +178,15 @@ typedef struct Scopes {
char _pad[4];
} Scopes;
-/* scopes->wavefrm_mode */
-#define SCOPES_WAVEFRM_LUMA 0
-#define SCOPES_WAVEFRM_RGB_PARADE 1
-#define SCOPES_WAVEFRM_YCC_601 2
-#define SCOPES_WAVEFRM_YCC_709 3
-#define SCOPES_WAVEFRM_YCC_JPEG 4
-#define SCOPES_WAVEFRM_RGB 5
+/** #Scopes.wavefrm_mode */
+enum {
+ SCOPES_WAVEFRM_LUMA = 0,
+ SCOPES_WAVEFRM_RGB_PARADE = 1,
+ SCOPES_WAVEFRM_YCC_601 = 2,
+ SCOPES_WAVEFRM_YCC_709 = 3,
+ SCOPES_WAVEFRM_YCC_JPEG = 4,
+ SCOPES_WAVEFRM_RGB = 5,
+};
typedef struct ColorManagedViewSettings {
int flag;
@@ -214,7 +214,7 @@ typedef struct ColorManagedColorspaceSettings {
char name[64];
} ColorManagedColorspaceSettings;
-/* ColorManagedViewSettings->flag */
+/** #ColorManagedViewSettings.flag */
enum {
COLORMANAGE_VIEW_USE_CURVES = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index e3b5ecfac04..e5282409329 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -72,7 +72,7 @@ typedef struct CustomData {
CustomDataLayer *layers;
/**
* runtime only! - maps types to indices of first layer of that type,
- * MUST be >= CD_NUMTYPES, but we cant use a define here.
+ * MUST be >= CD_NUMTYPES, but we can't use a define here.
* Correct size is ensured in CustomData_update_typemap assert().
*/
int typemap[51];
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index e3dcd283efa..5f3c54a0482 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -156,7 +156,7 @@ typedef struct DynamicPaintSurface {
/* canvas flags */
enum {
- /** surface is already baking, so it wont get updated (loop) */
+ /** surface is already baking, so it won't get updated (loop) */
MOD_DPAINT_BAKING = 1 << 1,
};
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 410212ce100..3977ad326da 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -878,6 +878,7 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 1),
LRT_GPENCIL_BINARY_WEIGHTS = (1 << 2) /* Deprecated, this is removed for lack of use case. */,
LRT_GPENCIL_IS_BAKED = (1 << 3),
+ LRT_GPENCIL_USE_CACHE = (1 << 4),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilTransparencyFlags {
@@ -886,6 +887,8 @@ typedef enum eLineartGpencilTransparencyFlags {
LRT_GPENCIL_TRANSPARENCY_MATCH = (1 << 1),
} eLineartGpencilTransparencyFlags;
+struct LineartCache;
+
typedef struct LineartGpencilModifierData {
GpencilModifierData modifier;
@@ -925,16 +928,24 @@ typedef struct LineartGpencilModifierData {
/* CPU mode */
float chaining_image_threshold;
- int _pad;
-
/* Ported from SceneLineArt flags. */
int calculation_flags;
/* Additional Switches. */
int flags;
- /* Runtime only. */
- void *render_buffer;
+ /* Runtime data. */
+
+ /* Because we can potentially only compute features lines once per modifier stack (Use Cache), we
+ * need to have these override values to ensure that we have the data we need is computed and
+ * stored in the cache. */
+ char level_start_override;
+ char level_end_override;
+ short edge_types_override;
+
+ struct LineartCache *cache;
+ /* Keep a pointer to the render buffer so we can call destroy from ModifierData. */
+ struct LineartRenderBuffer *render_buffer_ptr;
} LineartGpencilModifierData;
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index ea3c1ff7275..6b7b89e91fa 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -629,6 +629,7 @@ typedef struct bGPdata_Runtime {
/** Brush pointer */
Brush *sbuffer_brush;
struct GpencilBatchCache *gpencil_cache;
+ struct LineartCache *lineart_cache;
} bGPdata_Runtime;
/* grid configuration */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 3eb5920dfe6..566173aac0f 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -276,7 +276,7 @@ enum {
#define ME_USING_MIRROR_X_VERTEX_GROUPS(_me) \
(((_me)->editflag & ME_EDIT_MIRROR_VERTEX_GROUPS) && ((_me)->symmetry & ME_SYMMETRY_X))
-/* We cant have both flags enabled at once,
+/* We can't have both flags enabled at once,
* flags defined in DNA_scene_types.h */
#define ME_EDIT_PAINT_SEL_MODE(_me) \
(((_me)->editflag & ME_EDIT_PAINT_FACE_SEL) ? \
@@ -296,7 +296,7 @@ enum {
ME_REMESH_REPROJECT_VERTEX_COLORS = 1 << 8,
ME_DS_EXPAND = 1 << 9,
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
- ME_REMESH_SMOOTH_NORMALS = 1 << 11,
+ ME_FLAG_UNUSED_8 = 1 << 11, /* cleared */
ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12,
ME_REMESH_FIX_POLES = 1 << 13,
ME_REMESH_REPROJECT_VOLUME = 1 << 14,
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 05be31262a6..346e65f0fa1 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -130,7 +130,7 @@ typedef struct MLoop {
/**
* Optionally store the order of selected elements.
- * This wont always be set since only some selection operations have an order.
+ * This won't always be set since only some selection operations have an order.
*
* Typically accessed from #Mesh.mselect
*/
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 6c1a141448f..186d5cc9884 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1367,6 +1367,16 @@ typedef struct NodeGeometryCurveDeform {
uint8_t axis;
} NodeGeometryCurveDeform;
+typedef struct NodeGeometryCurveSubdivide {
+ /* GeometryNodeAttributeInputMode (integer or attribute). */
+ uint8_t cuts_type;
+} NodeGeometryCurveSubdivide;
+
+typedef struct NodeGeometryCurveToPoints {
+ /* GeometryNodeCurveSampleMode. */
+ uint8_t mode;
+} NodeGeometryCurveToPoints;
+
typedef struct NodeGeometryAttributeTransfer {
/* AttributeDomain. */
int8_t domain;
@@ -1374,6 +1384,15 @@ typedef struct NodeGeometryAttributeTransfer {
uint8_t mapping;
} NodeGeometryAttributeTransfer;
+typedef struct NodeGeometryRaycast {
+ /* GeometryNodeRaycastMapMode. */
+ uint8_t mapping;
+
+ uint8_t input_type_ray_direction;
+ uint8_t input_type_ray_length;
+ char _pad[1];
+} NodeGeometryRaycast;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1878,6 +1897,7 @@ typedef enum GeometryNodeMeshLineCountMode {
typedef enum GeometryNodeCurveSampleMode {
GEO_NODE_CURVE_SAMPLE_COUNT = 0,
GEO_NODE_CURVE_SAMPLE_LENGTH = 1,
+ GEO_NODE_CURVE_SAMPLE_EVALUATED = 2,
} GeometryNodeCurveSampleMode;
typedef enum GeometryNodeAttributeTransferMapMode {
@@ -1894,6 +1914,11 @@ typedef enum GeometryNodeCurveDeformAxis {
GEO_NODE_CURVE_DEFORM_NEGZ = 5,
} GeometryNodeCurveDeformAxis;
+typedef enum GeometryNodeRaycastMapMode {
+ GEO_NODE_RAYCAST_INTERPOLATED = 0,
+ GEO_NODE_RAYCAST_NEAREST = 1,
+} GeometryNodeRaycastMapMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 7e0bf81457d..59b153397c1 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -45,6 +45,7 @@ struct MovieClip;
struct Scene;
struct VFont;
struct bSound;
+struct SequenceLookup;
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
@@ -166,8 +167,9 @@ typedef struct Sequence {
* frames that use the last frame after data ends.
*/
int startstill, endstill;
- /** Machine: the strip channel, depth the depth in the sequence when dealing with metastrips. */
- int machine, depth;
+ /** Machine: the strip channel */
+ int machine;
+ int _pad3;
/** Starting and ending points of the strip in the sequence. */
int startdisp, enddisp;
float sat;
@@ -257,6 +259,10 @@ typedef struct MetaStack {
int disp_range[2];
} MetaStack;
+typedef struct EditingRuntime {
+ struct SequenceLookup *sequence_lookup;
+} EditingRuntime;
+
typedef struct Editing {
/** Pointer to the current list of seq's being edited (can be within a meta strip). */
ListBase *seqbasep;
@@ -287,6 +293,8 @@ typedef struct Editing {
/* Must be initialized only by seq_cache_create() */
int64_t disk_cache_timestamp;
+
+ EditingRuntime runtime;
} Editing;
/* ************* Effect Variable Structs ********* */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 9f3576a2cbe..7804ece9769 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -780,8 +780,16 @@ typedef struct FileAssetSelectParams {
FileSelectParams base_params;
FileSelectAssetLibraryUID asset_library;
+
+ short import_type; /* eFileAssetImportType */
+ char _pad[6];
} FileAssetSelectParams;
+typedef enum eFileAssetImportType {
+ FILE_ASSET_IMPORT_LINK = 0,
+ FILE_ASSET_IMPORT_APPEND = 1,
+} eFileAssetImportType;
+
/**
* A wrapper to store previous and next folder lists (#FolderList) for a specific browse mode
* (#eFileBrowse_Mode).
@@ -1866,6 +1874,19 @@ typedef struct SpreadsheetColumn {
* #SpreadsheetColumnID in the future for different kinds of ids.
*/
SpreadsheetColumnID *id;
+
+ /**
+ * An indicator of the type of values in the column, set at runtime.
+ * #eSpreadsheetColumnValueType.
+ */
+ uint8_t data_type;
+ char _pad0[7];
+
+ /**
+ * The final column name generated by the data source, also just
+ * cached at runtime when the data source columns are generated.
+ */
+ char *display_name;
} SpreadsheetColumn;
/**
@@ -1906,6 +1927,9 @@ typedef struct SpaceSpreadsheet {
/* List of #SpreadsheetColumn. */
ListBase columns;
+ /* SpreadsheetRowFilter. */
+ ListBase row_filters;
+
/**
* List of #SpreadsheetContext.
* This is a path to the data that is displayed in the spreadsheet.
@@ -1937,8 +1961,44 @@ typedef enum eSpaceSpreadsheet_Flag {
typedef enum eSpaceSpreadsheet_FilterFlag {
SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
+ SPREADSHEET_FILTER_ENABLE = (1 << 1),
} eSpaceSpreadsheet_FilterFlag;
+typedef struct SpreadsheetRowFilter {
+ struct SpreadsheetRowFilter *next, *prev;
+
+ char column_name[64]; /* MAX_NAME. */
+
+ /* eSpreadsheetFilterOperation. */
+ uint8_t operation;
+ /* eSpaceSpreadsheet_RowFilterFlag. */
+ uint8_t flag;
+
+ char _pad0[2];
+
+ int value_int;
+ char *value_string;
+ float value_float;
+ float threshold;
+ float value_float2[2];
+ float value_float3[3];
+ float value_color[4];
+
+ char _pad1[4];
+} SpreadsheetRowFilter;
+
+typedef enum eSpaceSpreadsheet_RowFilterFlag {
+ SPREADSHEET_ROW_FILTER_UI_EXPAND = (1 << 0),
+ SPREADSHEET_ROW_FILTER_BOOL_VALUE = (1 << 1),
+ SPREADSHEET_ROW_FILTER_ENABLED = (1 << 2),
+} eSpaceSpreadsheet_RowFilterFlag;
+
+typedef enum eSpreadsheetFilterOperation {
+ SPREADSHEET_ROW_FILTER_EQUAL = 0,
+ SPREADSHEET_ROW_FILTER_GREATER = 1,
+ SPREADSHEET_ROW_FILTER_LESS = 2,
+} eSpreadsheetFilterOperation;
+
typedef enum eSpaceSpreadsheet_ObjectEvalState {
SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED = 0,
SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
@@ -1950,6 +2010,16 @@ typedef enum eSpaceSpreadsheet_ContextType {
SPREADSHEET_CONTEXT_NODE = 2,
} eSpaceSpreadsheet_ContextType;
+typedef enum eSpreadsheetColumnValueType {
+ SPREADSHEET_VALUE_TYPE_BOOL = 0,
+ SPREADSHEET_VALUE_TYPE_INT32 = 1,
+ SPREADSHEET_VALUE_TYPE_FLOAT = 2,
+ SPREADSHEET_VALUE_TYPE_FLOAT2 = 3,
+ SPREADSHEET_VALUE_TYPE_FLOAT3 = 4,
+ SPREADSHEET_VALUE_TYPE_COLOR = 5,
+ SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
+} eSpreadsheetColumnValueType;
+
/**
* We can't just use UI_UNIT_X, because it does not take `widget.points` into account, which
* modifies the width of text as well.
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 9e7e30d913e..3b35b527584 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -72,7 +72,6 @@ typedef struct RegionView3D {
/** Allocated backup of its self while in localview. */
struct RegionView3D *localvd;
struct RenderEngine *render_engine;
- struct ViewDepths *depths;
/** Animated smooth view. */
struct SmoothView3DStore *sms;
@@ -102,7 +101,7 @@ typedef struct RegionView3D {
/** Viewport zoom on the camera frame, see BKE_screen_view3d_zoom_to_fac. */
float camzoom;
/**
- * Check if persp/ortho view, since 'persp' cant be used for this since
+ * Check if persp/ortho view, since 'persp' can't be used for this since
* it can have cameras assigned as well. (only set in #view3d_winmatrix_set)
*/
char is_persp;
@@ -258,6 +257,8 @@ typedef struct View3D_Runtime {
int flag;
char _pad1[4];
+ /* Only used for overlay stats while in localview. */
+ struct SceneStats *local_stats;
} View3D_Runtime;
/** 3D ViewPort Struct. */
@@ -515,7 +516,6 @@ enum {
V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
V3D_OVERLAY_STATS = (1 << 11),
V3D_OVERLAY_FADE_INACTIVE = (1 << 12),
- V3D_OVERLAY_MODE_TRANSFER = (1 << 13),
};
/** #View3DOverlay.edit_flag */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 6c88d5f7230..2a4bf53702f 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -855,7 +855,7 @@ static void cast_pointer_64_to_32(const int array_len,
uint32_t *new_data)
{
/* WARNING: 32-bit Blender trying to load file saved by 64-bit Blender,
- * pointers may lose uniqueness on truncation! (Hopefully this wont
+ * pointers may lose uniqueness on truncation! (Hopefully this won't
* happen unless/until we ever get to multi-gigabyte .blend files...) */
for (int a = 0; a < array_len; a++) {
new_data[a] = old_data[a] >> 3;
@@ -1564,9 +1564,8 @@ DNA_ReconstructInfo *DNA_reconstruct_info_create(const SDNA *oldsdna,
ReconstructStep *steps = create_reconstruct_steps_for_struct(
oldsdna, newsdna, compare_flags, old_struct, new_struct);
- int steps_len = new_struct->members_len;
/* Comment the line below to skip the compression for debugging purposes. */
- steps_len = compress_reconstruct_steps(steps, new_struct->members_len);
+ const int steps_len = compress_reconstruct_steps(steps, new_struct->members_len);
reconstruct_info->steps[new_struct_nr] = steps;
reconstruct_info->step_counts[new_struct_nr] = steps_len;
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 34413730eb3..84120a54da4 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -59,11 +59,13 @@ DNA_STRUCT_RENAME(SpaceOops, SpaceOutliner)
DNA_STRUCT_RENAME_ELEM(BPoint, alfa, tilt)
DNA_STRUCT_RENAME_ELEM(BezTriple, alfa, tilt)
DNA_STRUCT_RENAME_ELEM(Bone, curveInX, curve_in_x)
-DNA_STRUCT_RENAME_ELEM(Bone, curveInY, curve_in_y)
+DNA_STRUCT_RENAME_ELEM(Bone, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutX, curve_out_x)
-DNA_STRUCT_RENAME_ELEM(Bone, curveOutY, curve_out_y)
+DNA_STRUCT_RENAME_ELEM(Bone, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleIn, scale_in_x)
+DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(Bone, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_f, hardeness)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_s, aspect_ratio)
DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance)
@@ -101,11 +103,13 @@ DNA_STRUCT_RENAME_ELEM(View3D, ob_centre_cursor, ob_center_cursor)
DNA_STRUCT_RENAME_ELEM(bGPDstroke, gradient_f, hardeness)
DNA_STRUCT_RENAME_ELEM(bGPDstroke, gradient_s, aspect_ratio)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInX, curve_in_x)
-DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInY, curve_in_y)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutX, curve_out_x)
-DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_y)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(bSameVolumeConstraint, flag, free_axis)
DNA_STRUCT_RENAME_ELEM(bSound, name, filepath)
DNA_STRUCT_RENAME_ELEM(bTheme, tact, space_action)
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 85bcc94c335..e6b4ae97355 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -361,7 +361,7 @@ static int add_type(const char *str, int size)
}
if (strchr(str, '*')) {
/* note: this is valid C syntax but we can't parse, complain!
- * `struct SomeStruct* some_var;` <-- correct but we cant handle right now. */
+ * `struct SomeStruct* some_var;` <-- correct but we can't handle right now. */
return -1;
}
@@ -725,7 +725,7 @@ static int convert_include(const char *filename)
const int strct = add_type(md1, 0);
if (strct == -1) {
- fprintf(stderr, "File '%s' contains struct we cant parse \"%s\"\n", filename, md1);
+ fprintf(stderr, "File '%s' contains struct we can't parse \"%s\"\n", filename, md1);
return 1;
}
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 379e3e77b6e..c691eb3b534 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -615,10 +615,12 @@ extern StructRNA RNA_Spline;
extern StructRNA RNA_SplineIKConstraint;
extern StructRNA RNA_SplinePoint;
extern StructRNA RNA_SpotLight;
+extern StructRNA RNA_SpreadsheetColumnID;
extern StructRNA RNA_SpreadsheetContext;
extern StructRNA RNA_SpreadsheetContextObject;
extern StructRNA RNA_SpreadsheetContextModifier;
extern StructRNA RNA_SpreadsheetContextNode;
+extern StructRNA RNA_SpreadsheetRowFilter;
extern StructRNA RNA_Stereo3dDisplay;
extern StructRNA RNA_StretchToConstraint;
extern StructRNA RNA_StringAttribute;
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 8e1cfafcc42..17396a6a000 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -255,7 +255,7 @@ typedef enum PropertyFlag {
* Currently only used for UI, this is similar to PROP_NEVER_NULL
* except that the value may be NULL at times, used for ObData, where an Empty's will be NULL
* but setting NULL on a mesh object is not possible.
- * So, if its not NULL, setting NULL cant be done!
+ * So if it's not NULL, setting NULL can't be done!
*/
PROP_NEVER_UNLINK = (1 << 25),
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 7a9cfa79324..a75921859cb 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4229,7 +4229,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
}
fprintf(f, "\t");
rna_print_c_string(f, srna->identifier);
- fprintf(f, ", NULL, NULL"); /* PyType - Cant initialize here */
+ fprintf(f, ", NULL, NULL"); /* PyType - Can't initialize here */
fprintf(f, ", %d, NULL, ", srna->flag);
rna_print_c_string(f, srna->name);
fprintf(f, ",\n\t");
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 948fef1b51e..edcfcd130f7 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -226,7 +226,7 @@ void RNA_pointer_recast(PointerRNA *ptr, PointerRNA *r_ptr)
{
StructRNA *base;
PointerRNA t_ptr;
- *r_ptr = *ptr; /* initialize as the same in case cant recast */
+ *r_ptr = *ptr; /* initialize as the same in case can't recast */
for (base = ptr->type->base; base; base = base->base) {
t_ptr = rna_pointer_inherit_refine(ptr, base, ptr->data);
@@ -6869,7 +6869,7 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C,
if (as_function && RNA_property_type(prop) == PROP_POINTER) {
/* don't expand pointers for functions */
if (flag & PROP_NEVER_NULL) {
- /* we cant really do the right thing here. arg=arg?, hrmf! */
+ /* we can't really do the right thing here. arg=arg?, hrmf! */
buf = BLI_strdup(arg_name);
}
else {
@@ -8184,7 +8184,7 @@ void _RNA_warning(const char *format, ...)
vprintf(format, args);
va_end(args);
- /* gcc macro adds '\n', but cant use for other compilers */
+ /* gcc macro adds '\n', but can't use for other compilers */
#ifndef __GNUC__
fputc('\n', stdout);
#endif
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index c8fccfc27f8..f07aae0bb15 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -720,7 +720,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb
prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop, "Inherit End Roll", "Add Roll Out of the Start Handle bone to the Roll In value");
- RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ADD_PARENT_END_ROLL);
+ RNA_def_property_boolean_sdna(prop, NULL, "bbone_flag", BBONE_ADD_PARENT_END_ROLL);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_Armature_dependency_update");
}
@@ -733,11 +733,11 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb
prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
- prop = RNA_def_property(srna, "bbone_curveiny", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "curve_in_y");
+ prop = RNA_def_property(srna, "bbone_curveinz", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curve_in_z");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
- prop, "In Y", "Y-axis handle offset for start of the B-Bone's curve, adjusts curvature");
+ prop, "In Z", "Z-axis handle offset for start of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE);
@@ -747,11 +747,11 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb
prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
- prop = RNA_def_property(srna, "bbone_curveouty", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "curve_out_y");
+ prop = RNA_def_property(srna, "bbone_curveoutz", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "curve_out_z");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
- prop, "Out Y", "Y-axis handle offset for end of the B-Bone's curve, adjusts curvature");
+ prop, "Out Z", "Z-axis handle offset for end of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
/* Ease In/Out */
@@ -769,49 +769,37 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editb
RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
- /* Scale In/Out */
- prop = RNA_def_property(srna, "bbone_scaleinx", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scale_in_x");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
- RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop,
- "Scale In X",
- "X-axis scale factor for start of the B-Bone, "
- "adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
-
- prop = RNA_def_property(srna, "bbone_scaleiny", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scale_in_y");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
- RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop,
- "Scale In Y",
- "Y-axis scale factor for start of the B-Bone, "
- "adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
+ if (is_posebone == false) {
+ prop = RNA_def_property(srna, "use_scale_easing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Scale Easing", "Multiply the final easing values by the Scale In/Out Y factors");
+ RNA_def_property_boolean_sdna(prop, NULL, "bbone_flag", BBONE_SCALE_EASING);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
+ }
- prop = RNA_def_property(srna, "bbone_scaleoutx", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scale_out_x");
+ /* Scale In/Out */
+ prop = RNA_def_property(srna, "bbone_scalein", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale_in");
+ RNA_def_property_array(prop, 3);
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop,
- "Scale Out X",
- "X-axis scale factor for end of the B-Bone, "
- "adjusts thickness (for tapering effects)");
+ RNA_def_property_float_array_default(prop, rna_default_scale_3d);
+ RNA_def_property_ui_text(
+ prop,
+ "Scale In",
+ "Scale factors for the start of the B-Bone, adjusts thickness (for tapering effects)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
- prop = RNA_def_property(srna, "bbone_scaleouty", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scale_out_y");
+ prop = RNA_def_property(srna, "bbone_scaleout", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale_out");
+ RNA_def_property_array(prop, 3);
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop,
- "Scale Out Y",
- "Y-axis scale factor for end of the B-Bone, "
- "adjusts thickness (for tapering effects)");
+ RNA_def_property_float_array_default(prop, rna_default_scale_3d);
+ RNA_def_property_ui_text(
+ prop,
+ "Scale Out",
+ "Scale factors for the end of the B-Bone, adjusts thickness (for tapering effects)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
# undef RNA_DEF_CURVEBONE_UPDATE
@@ -1072,6 +1060,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "B-Bone Display Z Width", "B-Bone Z size");
+ /* B-Bone Start Handle settings. */
prop = RNA_def_property(srna, "bbone_handle_type_start", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "bbone_prev_type");
RNA_def_property_enum_items(prop, prop_bbone_handle_type);
@@ -1096,6 +1085,26 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(
prop, "B-Bone Start Handle", "Bone that serves as the start handle for the B-Bone curve");
+ prop = RNA_def_property(srna, "bbone_handle_use_scale_start", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop,
+ "Start Handle Scale",
+ "Multiply B-Bone Scale In channels by the local scale values of the start handle. "
+ "This is done after the Scale Easing option and isn't affected by it");
+ RNA_def_property_boolean_sdna(prop, NULL, "bbone_prev_flag", BBONE_HANDLE_SCALE_X);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
+ prop = RNA_def_property(srna, "bbone_handle_use_ease_start", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop,
+ "Start Handle Ease",
+ "Multiply the B-Bone Ease In channel by the local Y scale value of the start handle. "
+ "This is done after the Scale Easing option and isn't affected by it");
+ RNA_def_property_boolean_sdna(prop, NULL, "bbone_prev_flag", BBONE_HANDLE_SCALE_EASE);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
+ /* B-Bone End Handle settings. */
prop = RNA_def_property(srna, "bbone_handle_type_end", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "bbone_next_type");
RNA_def_property_enum_items(prop, prop_bbone_handle_type);
@@ -1120,6 +1129,25 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(
prop, "B-Bone End Handle", "Bone that serves as the end handle for the B-Bone curve");
+ prop = RNA_def_property(srna, "bbone_handle_use_scale_end", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop,
+ "End Handle Scale",
+ "Multiply B-Bone Scale Out channels by the local scale values of the end handle. "
+ "This is done after the Scale Easing option and isn't affected by it");
+ RNA_def_property_boolean_sdna(prop, NULL, "bbone_next_flag", BBONE_HANDLE_SCALE_X);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
+ prop = RNA_def_property(srna, "bbone_handle_use_ease_end", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop,
+ "End Handle Ease",
+ "Multiply the B-Bone Ease Out channel by the local Y scale value of the end handle. "
+ "This is done after the Scale Easing option and isn't affected by it");
+ RNA_def_property_boolean_sdna(prop, NULL, "bbone_next_flag", BBONE_HANDLE_SCALE_EASE);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
RNA_define_lib_overridable(false);
}
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index dd7d50a80ba..2a4cd1d934a 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -183,7 +183,7 @@ static const EnumPropertyItem curve2d_fill_mode_items[] = {
# include "ED_curve.h" /* for BKE_curve_nurbs_get */
-/* highly irritating but from RNA we cant know this */
+/* highly irritating but from RNA we can't know this */
static Nurb *curve_nurb_from_point(Curve *cu, const void *point, int *nu_index, int *pt_index)
{
ListBase *nurbs = BKE_curve_nurbs_get(cu);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 9b9d561603b..6b0a2b324c3 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -783,7 +783,7 @@ void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *rna_ext)
rna_ext->free(rna_ext->data); /* decref's the PyObject that the srna owns */
RNA_struct_blender_type_set(srna, NULL); /* this gets accessed again - XXX fixme */
- /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+ /* NULL the srna's value so RNA_struct_free won't complain of a leak */
RNA_struct_py_type_set(srna, NULL);
#else
@@ -1053,7 +1053,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *
if (from) {
/* find struct to derive from */
- /* Inline RNA_struct_find(...) because it wont link from here. */
+ /* Inline RNA_struct_find(...) because it won't link from here. */
srnafrom = BLI_ghash_lookup(brna->structs_map, from);
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found to define %s.", from, identifier);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 1b89d866aba..399f45a2382 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -543,8 +543,8 @@ static void rna_FCurve_group_set(PointerRNA *ptr,
return;
}
else if (value.data && (pid != vid)) {
- /* id's differ, cant do this, should raise an error */
- printf("ERROR: ID's differ - ptr=%p vs value=%p\n", pid, vid);
+ /* ids differ, can't do this, should raise an error */
+ printf("ERROR: IDs differ - ptr=%p vs value=%p\n", pid, vid);
return;
}
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 92d65961743..e2cee2836b1 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -2930,6 +2930,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Is Baked", "This modifier has baked data");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_cache", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_USE_CACHE);
+ RNA_def_property_ui_text(prop,
+ "Use Cache",
+ "Use cached scene data from the first line art modifier in the stack. "
+ "Certain settings will be unavailable");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Thickness", "The thickness for the generated strokes");
RNA_def_property_ui_range(prop, 1, 100, 1, 1);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index b3272f44826..c058ab6cfcc 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -1092,7 +1092,7 @@ static void rna_def_image(BlenderRNA *brna)
0,
0,
"Size",
- "Width and height in pixels, zero when image data cant be loaded",
+ "Width and height in pixels, zero when image data can't be loaded",
0,
0);
RNA_def_property_subtype(prop, PROP_PIXEL);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index d5a1047d287..8e475f43e1d 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -82,7 +82,8 @@ static const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
# include "rna_mesh_utils.h"
/* -------------------------------------------------------------------- */
-/* Generic helpers */
+/** \name Generic Helpers
+ * \{ */
static Mesh *rna_mesh(PointerRNA *ptr)
{
@@ -139,8 +140,11 @@ static CustomData *rna_mesh_ldata(PointerRNA *ptr)
return rna_mesh_ldata_helper(me);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Generic CustomData Layer Functions */
+/** \name Generic CustomData Layer Functions
+ * \{ */
static void rna_cd_layer_name_set(CustomData *cdata, CustomDataLayer *cdl, const char *value)
{
@@ -205,49 +209,67 @@ static bool rna_Mesh_has_custom_normals_get(PointerRNA *ptr)
return BKE_mesh_has_custom_loop_normals(me);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Update Callbacks */
+/** \name Update Callbacks
+ *
+ * \note Skipping meshes without users is a simple way to avoid updates on newly created meshes.
+ * This speeds up importers that manipulate mesh data before linking it to an object & collection.
+ *
+ * \{ */
-static void rna_Mesh_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+/**
+ * \warning This calls `DEG_id_tag_update(id, 0)` which is something that should be phased out
+ * (see #deg_graph_node_tag_zero), for now it's kept since changes to updates must be carefully
+ * tested to make sure there aren't any regressions.
+ *
+ * This function should be replaced with more specific update flags where possible.
+ */
+static void rna_Mesh_update_data_legacy_deg_tag_all(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
{
ID *id = ptr->owner_id;
-
- /* cheating way for importers to avoid slow updates */
- if (id->us > 0) {
- DEG_id_tag_update(id, 0);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+ if (id->us <= 0) { /* See note in section heading. */
+ return;
}
+
+ DEG_id_tag_update(id, 0);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
static void rna_Mesh_update_data_edit_weight(Main *bmain, Scene *scene, PointerRNA *ptr)
{
BKE_mesh_batch_cache_dirty_tag(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_ALL);
- rna_Mesh_update_data(bmain, scene, ptr);
+ rna_Mesh_update_data_legacy_deg_tag_all(bmain, scene, ptr);
}
static void rna_Mesh_update_data_edit_active_color(Main *bmain, Scene *scene, PointerRNA *ptr)
{
BKE_mesh_batch_cache_dirty_tag(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_ALL);
- rna_Mesh_update_data(bmain, scene, ptr);
+ rna_Mesh_update_data_legacy_deg_tag_all(bmain, scene, ptr);
}
static void rna_Mesh_update_select(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->owner_id;
- /* cheating way for importers to avoid slow updates */
- if (id->us > 0) {
- WM_main_add_notifier(NC_GEOM | ND_SELECT, id);
+ if (id->us <= 0) { /* See note in section heading. */
+ return;
}
+
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, id);
}
void rna_Mesh_update_draw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->owner_id;
- /* cheating way for importers to avoid slow updates */
- if (id->us > 0) {
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+ if (id->us <= 0) { /* See note in section heading. */
+ return;
}
+
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
static void rna_Mesh_update_vertmask(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -274,8 +296,11 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
rna_Mesh_update_draw(bmain, scene, ptr);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Property get/set Callbacks */
+/** \name Property get/set Callbacks
+ * \{ */
static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
{
@@ -1047,7 +1072,7 @@ static int rna_MeshPoly_vertices_get_length(PointerRNA *ptr, int length[RNA_MAX_
{
MPoly *mp = (MPoly *)ptr->data;
/* note, raw access uses dummy item, this _could_ crash,
- * watch out for this, mface uses it but it cant work here. */
+ * watch out for this, mface uses it but it can't work here. */
return (length[0] = mp->totloop);
}
@@ -1599,8 +1624,14 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
/* end unused function block */
}
+/** \} */
+
#else
+/* -------------------------------------------------------------------- */
+/** \name RNA Mesh Definition
+ * \{ */
+
static void rna_def_mvert_group(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1619,7 +1650,7 @@ static void rna_def_mvert_group(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "def_nr");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Group Index", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1640,7 +1671,7 @@ static void rna_def_mvert(BlenderRNA *brna)
prop = RNA_def_property(srna, "co", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_ui_text(prop, "Location", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
/* RNA_def_property_float_sdna(prop, NULL, "no"); */
@@ -1665,7 +1696,7 @@ static void rna_def_mvert(BlenderRNA *brna)
prop, "rna_MeshVertex_bevel_weight_get", "rna_MeshVertex_bevel_weight_set", NULL);
RNA_def_property_ui_text(
prop, "Bevel Weight", "Weight used by the Bevel modifier 'Only Vertices' option");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop,
@@ -1718,13 +1749,13 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_MEdge_crease_get", "rna_MEdge_crease_set", NULL);
RNA_def_property_ui_text(
prop, "Crease", "Weight used by the Subdivision Surface modifier for creasing");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "bevel_weight", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(
prop, "rna_MEdge_bevel_weight_get", "rna_MEdge_bevel_weight_set", NULL);
RNA_def_property_ui_text(prop, "Bevel Weight", "Weight used by the Bevel modifier");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT);
@@ -1744,7 +1775,7 @@ static void rna_def_medge(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_edge_sharp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP);
RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the Edge Split modifier");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_LOOSEEDGE);
@@ -1754,7 +1785,7 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_boolean_funcs(
prop, "rna_MEdge_freestyle_edge_mark_get", "rna_MEdge_freestyle_edge_mark_set");
RNA_def_property_ui_text(prop, "Freestyle Edge Mark", "Edge mark for Freestyle line rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1937,7 +1968,7 @@ static void rna_def_mpolygon(BlenderRNA *brna)
# if 0
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range");
# endif
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FACE_SEL);
@@ -1952,13 +1983,13 @@ static void rna_def_mpolygon(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
RNA_def_property_ui_text(prop, "Smooth", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "use_freestyle_mark", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_MPoly_freestyle_face_mark_get", "rna_MPoly_freestyle_face_mark_set");
RNA_def_property_ui_text(prop, "Freestyle Face Mark", "Face mark for Freestyle line rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
@@ -2015,34 +2046,34 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshLoopLayer_name_set");
RNA_def_property_ui_text(prop, "Name", "Name of UV map");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_MeshUVLoopLayer_active_get", "rna_MeshUVLoopLayer_active_set");
RNA_def_property_ui_text(prop, "Active", "Set the map as active for display and editing");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
RNA_def_property_boolean_funcs(
prop, "rna_MeshUVLoopLayer_active_render_get", "rna_MeshUVLoopLayer_active_render_set");
RNA_def_property_ui_text(prop, "Active Render", "Set the map as active for rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_clone", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_clone", 0);
RNA_def_property_boolean_funcs(
prop, "rna_MeshUVLoopLayer_clone_get", "rna_MeshUVLoopLayer_clone_set");
RNA_def_property_ui_text(prop, "Active Clone", "Set the map as active for cloning");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
srna = RNA_def_struct(brna, "MeshUVLoop", NULL);
RNA_def_struct_sdna(srna, "MLoopUV");
RNA_def_struct_path_func(srna, "rna_MeshUVLoop_path");
prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "pin_uv", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_PINNED);
@@ -2069,13 +2100,13 @@ static void rna_def_mloopcol(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshLoopLayer_name_set");
RNA_def_property_ui_text(prop, "Name", "Name of Vertex color layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_MeshLoopColorLayer_active_get", "rna_MeshLoopColorLayer_active_set");
RNA_def_property_ui_text(prop, "Active", "Sets the layer as active for display and editing");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
@@ -2083,7 +2114,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
"rna_MeshLoopColorLayer_active_render_get",
"rna_MeshLoopColorLayer_active_render_set");
RNA_def_property_ui_text(prop, "Active Render", "Sets the layer as active for rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshLoopColor");
@@ -2109,7 +2140,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
RNA_def_property_float_funcs(
prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL);
RNA_def_property_ui_text(prop, "Color", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_MPropCol(BlenderRNA *brna)
@@ -2129,14 +2160,14 @@ static void rna_def_MPropCol(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshVertexLayer_name_set");
RNA_def_property_ui_text(prop, "Name", "Name of Sculpt Vertex color layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_MeshVertColorLayer_active_get", "rna_MeshVertColorLayer_active_set");
RNA_def_property_ui_text(
prop, "Active", "Sets the sculpt vertex color layer as active for display and editing");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
@@ -2145,7 +2176,7 @@ static void rna_def_MPropCol(BlenderRNA *brna)
"rna_MeshVertColorLayer_active_render_set");
RNA_def_property_ui_text(
prop, "Active Render", "Sets the sculpt vertex color layer as active for rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertColor");
@@ -2169,7 +2200,7 @@ static void rna_def_MPropCol(BlenderRNA *brna)
RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Color", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_mproperties(BlenderRNA *brna)
{
@@ -2189,7 +2220,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop); \
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); \
RNA_def_property_ui_text(prop, "Name", ""); \
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); \
\
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "FloatProperty"); \
@@ -2215,7 +2246,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); \
RNA_def_property_float_sdna(prop, NULL, "f"); \
RNA_def_property_ui_text(prop, "Value", ""); \
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); \
((void)0)
/* Int */
@@ -2231,7 +2262,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop); \
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); \
RNA_def_property_ui_text(prop, "Name", ""); \
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); \
\
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "IntProperty"); \
@@ -2256,7 +2287,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); \
RNA_def_property_int_sdna(prop, NULL, "i"); \
RNA_def_property_ui_text(prop, "Value", ""); \
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); \
((void)0)
/* String */
@@ -2272,7 +2303,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop); \
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); \
RNA_def_property_ui_text(prop, "Name", ""); \
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); \
\
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "StringProperty"); \
@@ -2302,7 +2333,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
"rna_MeshStringProperty_s_length", \
"rna_MeshStringProperty_s_set"); \
RNA_def_property_ui_text(prop, "Value", ""); \
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
MESH_FLOAT_PROPERTY_LAYER("Vertex");
MESH_FLOAT_PROPERTY_LAYER("Polygon");
@@ -2330,7 +2361,7 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
RNA_def_property_ui_text(prop, "Texture Space Location", "Texture space location");
RNA_def_property_float_funcs(prop, "rna_Mesh_texspace_loc_get", NULL, NULL);
RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "texspace_size", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
@@ -2338,7 +2369,7 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
RNA_def_property_ui_text(prop, "Texture Space Size", "Texture space size");
RNA_def_property_float_funcs(prop, "rna_Mesh_texspace_size_get", NULL, NULL);
RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
@@ -2602,7 +2633,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
prop, "rna_Mesh_uv_layer_active_get", "rna_Mesh_uv_layer_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
RNA_def_property_ui_text(prop, "Active UV Loop Layer", "Active UV loop layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
@@ -2610,7 +2641,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
"rna_Mesh_uv_layer_active_index_set",
"rna_Mesh_uv_layer_index_range");
RNA_def_property_ui_text(prop, "Active UV Loop Layer Index", "Active UV loop layer index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
/* mesh float layers */
@@ -2760,7 +2791,7 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshVertexLayer_name_set");
RNA_def_property_ui_text(prop, "Name", "Name of skin layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshSkinVertex");
@@ -2786,7 +2817,7 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_property_array(prop, 2);
RNA_def_property_ui_range(prop, 0.001, 100.0, 1, 3);
RNA_def_property_ui_text(prop, "Radius", "Radius of the skin");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
/* Flags */
@@ -2796,13 +2827,13 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
"Root",
"Vertex is a root for rotation calculations and armature generation, "
"setting this flag does not clear other roots in the same mesh island");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "use_loose", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MVERT_SKIN_LOOSE);
RNA_def_property_ui_text(
prop, "Loose", "If vertex has multiple adjacent edges, it is hulled to them directly");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
@@ -2837,7 +2868,7 @@ static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f");
RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_face_map(BlenderRNA *brna)
@@ -2854,7 +2885,7 @@ static void rna_def_face_map(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshPolyLayer_name_set");
RNA_def_property_ui_text(prop, "Name", "Name of face map layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshFaceMap");
@@ -2878,7 +2909,7 @@ static void rna_def_face_map(BlenderRNA *brna)
prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "i");
RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_face_maps(BlenderRNA *brna, PropertyRNA *cprop)
@@ -2897,7 +2928,7 @@ static void rna_def_face_maps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_struct_type(prop, "MeshFaceMapLayer");
RNA_def_property_pointer_funcs(prop, "rna_Mesh_face_map_active_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Active Face Map Layer", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
FunctionRNA *func;
PropertyRNA *parm;
@@ -3017,7 +3048,7 @@ static void rna_def_mesh(BlenderRNA *brna)
"rna_Mesh_uv_layer_stencil_index_set",
"rna_Mesh_uv_layer_index_range");
RNA_def_property_ui_text(prop, "Mask UV Loop Layer Index", "Mask UV loop layer index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
/* Vertex colors */
@@ -3229,11 +3260,6 @@ static void rna_def_mesh(BlenderRNA *brna)
"generating triangles. A value greater than 0 disables Fix Poles");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
- prop = RNA_def_property(srna, "use_remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_SMOOTH_NORMALS);
- RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
prop = RNA_def_property(srna, "use_remesh_fix_poles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES);
RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow");
@@ -3307,7 +3333,7 @@ static void rna_def_mesh(BlenderRNA *brna)
"Auto Smooth",
"Auto smooth (based on smooth/sharp faces/edges and angle between faces), "
"or use custom split normals data if available");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "smoothresh");
@@ -3316,7 +3342,7 @@ static void rna_def_mesh(BlenderRNA *brna)
"Auto Smooth Angle",
"Maximum angle between face normals that will be considered as smooth "
"(unused if custom split normals data are available)");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
RNA_define_verify_sdna(false);
prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE);
@@ -3347,7 +3373,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop,
"Auto Texture Space",
"Adjust active object's texture space automatically when transforming object");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
# if 0
prop = RNA_def_property(srna, "texspace_location", PROP_FLOAT, PROP_TRANSLATION);
@@ -3437,3 +3463,5 @@ void RNA_def_mesh(BlenderRNA *brna)
}
#endif
+
+/** \} */
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index f8fa2aab5e7..a32ed49ae1e 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -354,7 +354,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
0,
0,
"Size",
- "Width and height in pixels, zero when image data cant be loaded",
+ "Width and height in pixels, zero when image data can't be loaded",
0,
0);
RNA_def_property_int_funcs(prop, "rna_MovieClip_size_get", NULL, NULL);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 1a0a6a9514d..e27c3e6dada 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -464,6 +464,10 @@ static EnumPropertyItem rna_node_geometry_mesh_circle_fill_type_items[] = {
{ \
GEO_NODE_ATTRIBUTE_INPUT_COLOR, "COLOR", 0, "Color", "" \
}
+#define ITEM_INTEGER \
+ { \
+ GEO_NODE_ATTRIBUTE_INPUT_INTEGER, "INTEGER", 0, "Integer", "" \
+ }
#define ITEM_BOOLEAN \
{ \
GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN, "BOOLEAN", 0, "Boolean", "" \
@@ -475,6 +479,7 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_any[]
ITEM_FLOAT,
ITEM_VECTOR,
ITEM_COLOR,
+ ITEM_INTEGER,
ITEM_BOOLEAN,
{0, NULL, 0, NULL, NULL},
};
@@ -497,6 +502,11 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float
ITEM_FLOAT,
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_int[] = {
+ ITEM_ATTRIBUTE,
+ ITEM_INTEGER,
+ {0, NULL, 0, NULL, NULL},
+};
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_boolean[] = {
ITEM_ATTRIBUTE,
ITEM_FLOAT,
@@ -1283,6 +1293,13 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree,
if (nodeCountSocketLinks(ntree, tosock) + 1 > nodeSocketLinkLimit(tosock)) {
nodeRemSocketLinks(ntree, tosock);
}
+ if (tosock->flag & SOCK_MULTI_INPUT) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == fromsock && link->tosock == tosock) {
+ nodeRemLink(ntree, link);
+ }
+ }
+ }
}
ret = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
@@ -9864,6 +9881,50 @@ static void def_geo_curve_deform(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_subdivide(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSubdivide", "storage");
+
+ prop = RNA_def_property(srna, "cuts_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_int);
+ RNA_def_property_ui_text(prop, "Cuts Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
+static void def_geo_curve_to_points(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mode_items[] = {
+ {GEO_NODE_CURVE_SAMPLE_EVALUATED,
+ "EVALUATED",
+ 0,
+ "Evaluated",
+ "Create points from the curve's evaluated points, based on the resolution attribute for "
+ "NURBS and Bezier splines"},
+ {GEO_NODE_CURVE_SAMPLE_COUNT,
+ "COUNT",
+ 0,
+ "Count",
+ "Sample each spline by evenly distributing the specified number of points"},
+ {GEO_NODE_CURVE_SAMPLE_LENGTH,
+ "LENGTH",
+ 0,
+ "Length",
+ "Sample each spline by splitting it into segments with the specified length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveToPoints", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How to generate points from the input curve");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_attribute_transfer(StructRNA *srna)
{
static EnumPropertyItem mapping_items[] = {
@@ -9911,6 +9972,42 @@ static void def_geo_input_material(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_raycast(StructRNA *srna)
+{
+ static EnumPropertyItem mapping_items[] = {
+ {GEO_NODE_RAYCAST_INTERPOLATED,
+ "INTERPOLATED",
+ 0,
+ "Interpolated",
+ "Interpolate the attribute from the corners of the hit face"},
+ {GEO_NODE_RAYCAST_NEAREST,
+ "NEAREST",
+ 0,
+ "Nearest",
+ "Use the attribute value of the closest mesh element"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryRaycast", "storage");
+
+ prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mapping_items);
+ RNA_def_property_ui_text(prop, "Mapping", "Mapping from the target geometry to hit points");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "input_type_ray_direction", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
+ RNA_def_property_ui_text(prop, "Input Type Ray Direction", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "input_type_ray_length", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
+ RNA_def_property_ui_text(prop, "Input Type Ray Length", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index b339682222c..3d3faf0c56f 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -476,8 +476,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *UNUSED(scene), Po
DEG_id_tag_update(&me->id, 0);
- EDBM_mesh_normals_update(em);
- BKE_editmesh_looptri_calc(em);
+ BKE_editmesh_looptri_and_normals_calc(em);
break;
}
case OB_CURVE:
@@ -2000,8 +1999,8 @@ static void rna_VertexGroup_vertex_add(ID *id,
}
while (index_len--) {
- ED_vgroup_vert_add(
- ob, def, *index++, weight, assignmode); /* XXX, not efficient calling within loop*/
+ /* XXX: not efficient calling within loop. */
+ ED_vgroup_vert_add(ob, def, *index++, weight, assignmode);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index e463323c6dc..d08504dd6fe 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -575,8 +575,10 @@ static void rna_Object_ray_cast(Object *ob,
/* Test BoundBox first (efficiency) */
BoundBox *bb = BKE_object_boundbox_get(ob);
float distmin;
- normalize_v3(
- direction); /* Needed for valid distance check from isect_ray_aabb_v3_simple() call. */
+
+ /* Needed for valid distance check from #isect_ray_aabb_v3_simple() call. */
+ normalize_v3(direction);
+
if (!bb ||
(isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) &&
distmin <= distance)) {
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index b8bb4f58dcd..f736885df77 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -620,8 +620,8 @@ static void rna_PoseChannel_constraints_remove(
ED_object_constraint_update(bmain, ob);
- BKE_constraints_active_set(&pchan->constraints,
- NULL); /* XXX, is this really needed? - Campbell */
+ /* XXX(Campbell): is this really needed? */
+ BKE_constraints_active_set(&pchan->constraints, NULL);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, id);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index dd91a5509f5..6715941ae2a 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -856,6 +856,15 @@ static void rna_def_render_engine(BlenderRNA *brna)
"Use Custom Freestyle",
"Handles freestyle rendering on its own, instead of delegating it to EEVEE");
+ prop = RNA_def_property(srna, "bl_use_image_save", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "type->flag", RE_USE_NO_IMAGE_SAVE);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(
+ prop,
+ "Use Image Save",
+ "Save images/movie to disk while rendering an animation. "
+ "Disabling image saving is only supported when bl_use_postprocess is also disabled");
+
prop = RNA_def_property(srna, "bl_use_gpu_context", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_GPU_CONTEXT);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index be7c938a525..7f23d9bc754 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -1912,10 +1912,9 @@ static void rna_Scene_transform_orientation_slots_begin(CollectionPropertyIterat
iter, orient_slot, sizeof(*orient_slot), ARRAY_SIZE(scene->orientation_slots), 0, NULL);
}
-static int rna_Scene_transform_orientation_slots_length(PointerRNA *ptr)
+static int rna_Scene_transform_orientation_slots_length(PointerRNA *UNUSED(ptr))
{
- Scene *scene = (Scene *)ptr->owner_id;
- return ARRAY_SIZE(scene->orientation_slots);
+ return ARRAY_SIZE(((Scene *)NULL)->orientation_slots);
}
static bool rna_Scene_use_audio_get(PointerRNA *ptr)
@@ -6441,12 +6440,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
/* sequencer draw options */
-# if 0 /* see R_SEQ_GL_REND comment */
- prop = RNA_def_property(srna, "use_sequencer_gl_render", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_GL_REND);
- RNA_def_property_ui_text(prop, "Sequencer OpenGL", "");
-# endif
-
prop = RNA_def_property(srna, "sequencer_gl_preview", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "seq_prev_type");
RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
@@ -6454,15 +6447,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop, "Sequencer Preview Shading", "Display method used in the sequencer view");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
-# if 0 /* UNUSED, see R_SEQ_GL_REND comment */
- prop = RNA_def_property(srna, "sequencer_gl_render", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "seq_rend_type");
- RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
- /* XXX Label and tooltips are obviously wrong! */
- RNA_def_property_ui_text(
- prop, "Sequencer Preview Shading", "Display method used in the sequencer view");
-# endif
-
prop = RNA_def_property(srna, "use_sequencer_override_scene_strip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_OVERRIDE_SCENE_SETTINGS);
RNA_def_property_ui_text(prop,
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index c49b41867a8..caecd9a07d8 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -89,7 +89,7 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
/* don't do notifier when we're rendering, avoid some viewport crashes
* redrawing while the data is being modified for render */
if (!G.is_rendering) {
- /* cant use NC_SCENE|ND_FRAME because this causes wm_event_do_notifiers to call
+ /* can't use NC_SCENE|ND_FRAME because this causes wm_event_do_notifiers to call
* BKE_scene_graph_update_for_newframe which will lose any un-keyed changes T24690. */
/* WM_main_add_notifier(NC_SCENE|ND_FRAME, scene); */
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index fba1d3cda9a..25f29a3efe0 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -169,7 +169,7 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
/* It is possible that new layers becomes visible. */
if (area->spacetype == SPACE_VIEW3D) {
- DEG_on_visible_update(CTX_data_main(C), false);
+ DEG_tag_on_visible_update(CTX_data_main(C), false);
}
CTX_wm_window_set(C, prevwin);
@@ -288,7 +288,7 @@ static PointerRNA rna_Region_data_get(PointerRNA *ptr)
if (region->regiondata != NULL) {
if (region->regiontype == RGN_TYPE_WINDOW) {
- /* We could make this static, it wont change at run-time. */
+ /* We could make this static, it won't change at run-time. */
SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
if (region->type == BKE_regiontype_from_id(st, region->regiontype)) {
PointerRNA newptr;
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 9851d65ece3..29100cd7658 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -94,6 +94,8 @@ const EnumPropertyItem rna_enum_sequence_modifier_type_items[] = {
# include "IMB_imbuf.h"
+# include "SEQ_edit.h"
+
typedef struct SequenceSearchData {
Sequence *seq;
void *data;
@@ -243,6 +245,21 @@ static void rna_SequenceEditor_sequences_all_next(CollectionPropertyIterator *it
iter->valid = (internal->link != NULL);
}
+static int rna_SequenceEditor_sequences_all_lookup_string(PointerRNA *ptr,
+ const char *key,
+ PointerRNA *r_ptr)
+{
+ ID *id = ptr->owner_id;
+ Scene *scene = (Scene *)id;
+
+ Sequence *seq = SEQ_sequence_lookup_by_name(scene, key);
+ if (seq) {
+ RNA_pointer_create(ptr->owner_id, &RNA_Sequence, seq, r_ptr);
+ return true;
+ }
+ return false;
+}
+
/* internal use */
static int rna_SequenceEditor_elements_length(PointerRNA *ptr)
{
@@ -627,11 +644,10 @@ static void rna_Sequence_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy(oldname, seq->name + 2, sizeof(seq->name) - 2);
/* copy the new name into the name slot */
- BLI_strncpy_utf8(seq->name + 2, value, sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, value);
/* make sure the name is unique */
- SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
-
+ SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
/* fix all the animation data which may link to this */
/* Don't rename everywhere because these are per scene. */
@@ -1997,7 +2013,7 @@ static void rna_def_editor(BlenderRNA *brna)
NULL,
NULL,
NULL,
- NULL,
+ "rna_SequenceEditor_sequences_all_lookup_string",
NULL);
prop = RNA_def_property(srna, "meta_stack", PROP_COLLECTION, PROP_NONE);
@@ -2922,7 +2938,7 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "use_box", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_TEXT_BOX);
- RNA_def_property_ui_text(prop, "Shadow", "Display colored box behind text");
+ RNA_def_property_ui_text(prop, "Box", "Display colored box behind text");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "use_bold", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index bb356e4b532..f3871e625de 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -177,7 +177,11 @@ const EnumPropertyItem rna_enum_space_graph_mode_items[] = {
const EnumPropertyItem rna_enum_space_sequencer_view_type_items[] = {
{SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
{SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""},
- {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SPLITVIEW, "Sequencer/Preview", ""},
+ {SEQ_VIEW_SEQUENCE_PREVIEW,
+ "SEQUENCER_PREVIEW",
+ ICON_SEQ_SPLITVIEW,
+ "Sequencer & Preview",
+ ""},
{0, NULL, 0, NULL, NULL},
};
@@ -891,8 +895,8 @@ static void rna_SpaceView3D_use_local_camera_set(PointerRNA *ptr, bool value)
if (!value) {
Scene *scene = ED_screen_scene_find(screen, G_MAIN->wm.first);
/* NULL if the screen isn't in an active window (happens when setting from Python).
- * This could be moved to the update function, in that case the scene wont relate to the screen
- * so keep it working this way. */
+ * This could be moved to the update function, in that case the scene won't relate to the
+ * screen so keep it working this way. */
if (scene != NULL) {
v3d->camera = scene->camera;
}
@@ -4129,14 +4133,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Fade Inactive Objects", "Fade inactive geometry using the viewport background color");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_mode_transfer", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_MODE_TRANSFER);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop,
- "Flash on Mode Transfer",
- "Flash the target object when tranfering the active mode to it");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "fade_inactive_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.fade_alpha");
RNA_def_property_ui_text(prop, "Opacity", "Strength of the fade effect");
@@ -4970,7 +4966,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "view_location", PROP_FLOAT, PROP_TRANSLATION);
# if 0
- RNA_def_property_float_sdna(prop, NULL, "ofs"); /* cant use because its negated */
+ RNA_def_property_float_sdna(prop, NULL, "ofs"); /* can't use because it's negated */
# else
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(
@@ -4981,7 +4977,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(
- srna, "view_rotation", PROP_FLOAT, PROP_QUATERNION); /* cant use because its inverted */
+ srna, "view_rotation", PROP_FLOAT, PROP_QUATERNION); /* can't use because it's inverted */
# if 0
RNA_def_property_float_sdna(prop, NULL, "viewquat");
# else
@@ -6569,6 +6565,16 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem asset_import_type_items[] = {
+ {FILE_ASSET_IMPORT_LINK, "LINK", 0, "Link", "Import the assets as linked data-block"},
+ {FILE_ASSET_IMPORT_APPEND,
+ "APPEND",
+ 0,
+ "Append",
+ "Import the assets as copied data-block, with no link to the original asset data-block"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "FileAssetSelectParams", "FileSelectParams");
RNA_def_struct_ui_text(
srna, "Asset Select Parameters", "Settings for the file selection in Asset Browser mode");
@@ -6590,6 +6596,13 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
NULL);
RNA_def_property_ui_text(prop, "Asset Category", "Determine which kind of assets to display");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+
+ prop = RNA_def_property(srna, "import_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, asset_import_type_items);
+ RNA_def_property_ui_text(prop, "Import Type", "Determine how the asset will be imported");
+ /* Asset drag info saved by buttons stores the import type, so the space must redraw when import
+ * type changes. */
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
static void rna_def_filemenu_entry(BlenderRNA *brna)
@@ -7402,6 +7415,131 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
}
+static void rna_def_spreadsheet_column_id(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SpreadsheetColumnID", NULL);
+ RNA_def_struct_sdna(srna, "SpreadsheetColumnID");
+ RNA_def_struct_ui_text(
+ srna, "Spreadsheet Column ID", "Data used to identify a spreadsheet column");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Column Name", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+}
+
+static void rna_def_spreadsheet_column(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem data_type_items[] = {
+ {SPREADSHEET_VALUE_TYPE_INT32, "INT32", ICON_NONE, "Integer", ""},
+ {SPREADSHEET_VALUE_TYPE_FLOAT, "FLOAT", ICON_NONE, "Float", ""},
+ {SPREADSHEET_VALUE_TYPE_BOOL, "BOOLEAN", ICON_NONE, "Boolean", ""},
+ {SPREADSHEET_VALUE_TYPE_INSTANCES, "INSTANCES", ICON_NONE, "Instances", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "SpreadsheetColumn", NULL);
+ RNA_def_struct_sdna(srna, "SpreadsheetColumn");
+ RNA_def_struct_ui_text(
+ srna, "Spreadsheet Column", "Persistent data associated with a spreadsheet column");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "data_type");
+ RNA_def_property_enum_items(prop, data_type_items);
+ RNA_def_property_ui_text(
+ prop, "Data Type", "The data type of the corresponding column visible in the spreadsheet");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ rna_def_spreadsheet_column_id(brna);
+
+ prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SpreadsheetColumnID");
+ RNA_def_property_ui_text(
+ prop, "ID", "Data used to identify the corresponding data from the data source");
+}
+
+static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem rule_operation_items[] = {
+ {SPREADSHEET_ROW_FILTER_EQUAL, "EQUAL", ICON_NONE, "Equal To", ""},
+ {SPREADSHEET_ROW_FILTER_GREATER, "GREATER", ICON_NONE, "Greater Than", ""},
+ {SPREADSHEET_ROW_FILTER_LESS, "LESS", ICON_NONE, "Less Than", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "SpreadsheetRowFilter", NULL);
+ RNA_def_struct_sdna(srna, "SpreadsheetRowFilter");
+ RNA_def_struct_ui_text(srna, "Spreadsheet Row Filter", "");
+
+ prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_ENABLED);
+ RNA_def_property_ui_text(prop, "Enabled", "");
+ RNA_def_property_ui_icon(prop, ICON_CHECKBOX_DEHLT, 1);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_UI_EXPAND);
+ RNA_def_property_ui_text(prop, "Show Expanded", "");
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "column_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Column Name", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rule_operation_items);
+ RNA_def_property_ui_text(prop, "Operation", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_float", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Float Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_float2", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "2D Vector Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_float3", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Vector Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_color", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Color Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_string", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Text Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Threshold", "How close float values need to be to be equal");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_int", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "value_int");
+ RNA_def_property_ui_text(prop, "Integer Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE);
+ RNA_def_property_ui_text(prop, "Boolean Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+}
+
static const EnumPropertyItem spreadsheet_context_type_items[] = {
{SPREADSHEET_CONTEXT_OBJECT, "OBJECT", ICON_NONE, "Object", ""},
{SPREADSHEET_CONTEXT_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
@@ -7536,13 +7674,18 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
- rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_FOOTER));
+ rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_FOOTER));
prop = RNA_def_property(srna, "is_pinned", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_PINNED);
RNA_def_property_ui_text(prop, "Is Pinned", "Context path is pinned");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_ENABLE);
+ RNA_def_property_ui_text(prop, "Use Filter", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
prop = RNA_def_property(srna, "display_context_path_collapsed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED);
RNA_def_property_ui_text(prop, "Display Context Path Collapsed", "");
@@ -7557,6 +7700,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
RNA_def_property_ui_text(
prop, "Show Only Selected", "Only include rows that correspond to selected elements");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE);
@@ -7578,6 +7722,22 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Object Evaluation State", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ rna_def_spreadsheet_column(brna);
+
+ prop = RNA_def_property(srna, "columns", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "columns", NULL);
+ RNA_def_property_struct_type(prop, "SpreadsheetColumn");
+ RNA_def_property_ui_text(prop, "Columns", "Persistent data associated with spreadsheet columns");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ rna_def_spreadsheet_row_filter(brna);
+
+ prop = RNA_def_property(srna, "row_filters", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "row_filters", NULL);
+ RNA_def_property_struct_type(prop, "SpreadsheetRowFilter");
+ RNA_def_property_ui_text(prop, "Row Filters", "Filters to remove rows from the displayed data");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
func = RNA_def_function(
srna, "set_geometry_node_context", "rna_spreadsheet_set_geometry_node_context");
RNA_def_function_ui_description(
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index f128719db19..dc973a9c75c 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -1018,7 +1018,8 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "operator_menu_enum", "rna_uiItemMenuEnumO");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
- api_ui_item_op(func); /* cant use api_ui_item_op_common because property must come right after */
+ /* Can't use #api_ui_item_op_common because property must come right after. */
+ api_ui_item_op(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 6005ec96255..4d45d1d6d63 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -1072,10 +1072,9 @@ static void rna_UserDef_studiolight_solid_lights_begin(CollectionPropertyIterato
rna_iterator_array_begin(iter, sl->light, sizeof(*sl->light), ARRAY_SIZE(sl->light), 0, NULL);
}
-static int rna_UserDef_studiolight_solid_lights_length(PointerRNA *ptr)
+static int rna_UserDef_studiolight_solid_lights_length(PointerRNA *UNUSED(ptr))
{
- StudioLight *sl = (StudioLight *)ptr->data;
- return ARRAY_SIZE(sl->light);
+ return ARRAY_SIZE(((StudioLight *)NULL)->light);
}
/* StudioLight.light_ambient */
diff --git a/source/blender/makesrna/rna_cleanup/rna_cleaner.py b/source/blender/makesrna/rna_cleanup/rna_cleaner.py
index eaeca562e47..61622f281a6 100755
--- a/source/blender/makesrna/rna_cleanup/rna_cleaner.py
+++ b/source/blender/makesrna/rna_cleanup/rna_cleaner.py
@@ -288,7 +288,7 @@ def write_files(basename, props_list, props_length_max):
f_py.write("rna_api = [\n%s]\n" % py)
f_rna.write("rna_api = [\n%s]\n" % rna)
- # write useful py script, wont hurt
+ # write useful py script, won't hurt
f_py.write("\n'''\n")
f_py.write("for p_note, p_changed, p_class, p_from, p_to, p_check, p_type, p_desc in rna_api:\n")
f_py.write(" print(p_to)\n")
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index e1197439c7c..28fe4376d2c 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -891,7 +891,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
for (i = 0; i < curdupface; i++) {
mf = &split_m->mface[i];
- test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
+ BKE_mesh_mface_index_validate(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
}
BLI_edgehash_free(edgehash, NULL);
@@ -1106,7 +1106,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f;
}
- test_index_face(mf, &explode->fdata, u, (orig_v4 ? 4 : 3));
+ BKE_mesh_mface_index_validate(mf, &explode->fdata, u, (orig_v4 ? 4 : 3));
u++;
}
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 5f82cd9ba27..e8677c7ce1a 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -264,13 +264,10 @@ struct NodeWithState {
class GeometryNodesEvaluator;
/**
- * Utility class that locks the state of a node. Having this is a separate class is useful because
- * it allows methods to communicate that they expect the node to be locked.
+ * Utility class that wraps a node whose state is locked. Having this is a separate class is useful
+ * because it allows methods to communicate that they expect the node to be locked.
*/
class LockedNode : NonCopyable, NonMovable {
- private:
- GeometryNodesEvaluator &evaluator_;
-
public:
/**
* This is the node that is currently locked.
@@ -290,13 +287,9 @@ class LockedNode : NonCopyable, NonMovable {
Vector<DOutputSocket> delayed_unused_outputs;
Vector<DNode> delayed_scheduled_nodes;
- LockedNode(GeometryNodesEvaluator &evaluator, const DNode node, NodeState &node_state)
- : evaluator_(evaluator), node(node), node_state(node_state)
+ LockedNode(const DNode node, NodeState &node_state) : node(node), node_state(node_state)
{
- node_state.mutex.lock();
}
-
- ~LockedNode();
};
static const CPPType *get_socket_cpp_type(const DSocket socket)
@@ -352,7 +345,7 @@ class GeometryNodesEvaluator {
* on cache line boundaries. Note, just because a value is allocated in one specific thread,
* does not mean that it will only be used by that thread.
*/
- EnumerableThreadSpecific<LinearAllocator<>> local_allocators_;
+ threading::EnumerableThreadSpecific<LinearAllocator<>> local_allocators_;
/**
* Every node that is reachable from the output gets its own state. Once all states have been
@@ -380,7 +373,7 @@ class GeometryNodesEvaluator {
void execute()
{
- task_pool_ = BLI_task_pool_create(this, TASK_PRIORITY_HIGH, TASK_ISOLATION_OFF);
+ task_pool_ = BLI_task_pool_create(this, TASK_PRIORITY_HIGH);
this->create_states_for_reachable_nodes();
this->forward_group_inputs();
@@ -426,12 +419,13 @@ class GeometryNodesEvaluator {
/* Initialize the more complex parts of the node states in parallel. At this point no new
* node states are added anymore, so it is safe to lookup states from `node_states_` from
* multiple threads. */
- parallel_for(IndexRange(node_states_.size()), 50, [&, this](const IndexRange range) {
- LinearAllocator<> &allocator = this->local_allocators_.local();
- for (const NodeWithState &item : node_states_.as_span().slice(range)) {
- this->initialize_node_state(item.node, *item.state, allocator);
- }
- });
+ threading::parallel_for(
+ IndexRange(node_states_.size()), 50, [&, this](const IndexRange range) {
+ LinearAllocator<> &allocator = this->local_allocators_.local();
+ for (const NodeWithState &item : node_states_.as_span().slice(range)) {
+ this->initialize_node_state(item.node, *item.state, allocator);
+ }
+ });
}
void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator)
@@ -507,11 +501,12 @@ class GeometryNodesEvaluator {
void destruct_node_states()
{
- parallel_for(IndexRange(node_states_.size()), 50, [&, this](const IndexRange range) {
- for (const NodeWithState &item : node_states_.as_span().slice(range)) {
- this->destruct_node_state(item.node, *item.state);
- }
- });
+ threading::parallel_for(
+ IndexRange(node_states_.size()), 50, [&, this](const IndexRange range) {
+ for (const NodeWithState &item : node_states_.as_span().slice(range)) {
+ this->destruct_node_state(item.node, *item.state);
+ }
+ });
}
void destruct_node_state(const DNode node, NodeState &node_state)
@@ -568,9 +563,10 @@ class GeometryNodesEvaluator {
for (const DInputSocket &socket : params_.output_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- LockedNode locked_node{*this, node, node_state};
- /* Setting an input as required will schedule any linked node. */
- this->set_input_required(locked_node, socket);
+ this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ /* Setting an input as required will schedule any linked node. */
+ this->set_input_required(locked_node, socket);
+ });
}
}
@@ -632,30 +628,33 @@ class GeometryNodesEvaluator {
bool node_task_preprocessing(const DNode node, NodeState &node_state)
{
- LockedNode locked_node{*this, node, node_state};
- BLI_assert(node_state.schedule_state == NodeScheduleState::Scheduled);
- node_state.schedule_state = NodeScheduleState::Running;
+ bool do_execute_node = false;
+ this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ BLI_assert(node_state.schedule_state == NodeScheduleState::Scheduled);
+ node_state.schedule_state = NodeScheduleState::Running;
- /* Early return if the node has finished already. */
- if (locked_node.node_state.node_has_finished) {
- return false;
- }
- /* Prepare outputs and check if actually any new outputs have to be computed. */
- if (!this->prepare_node_outputs_for_execution(locked_node)) {
- return false;
- }
- /* Initialize nodes that don't support laziness. This is done after at least one output is
- * required and before we check that all required inputs are provided. This reduces the
- * number of "round-trips" through the task pool by one for most nodes. */
- if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) {
- this->initialize_non_lazy_node(locked_node);
- node_state.non_lazy_node_is_initialized = true;
- }
- /* Prepare inputs and check if all required inputs are provided. */
- if (!this->prepare_node_inputs_for_execution(locked_node)) {
- return false;
- }
- return true;
+ /* Early return if the node has finished already. */
+ if (locked_node.node_state.node_has_finished) {
+ return;
+ }
+ /* Prepare outputs and check if actually any new outputs have to be computed. */
+ if (!this->prepare_node_outputs_for_execution(locked_node)) {
+ return;
+ }
+ /* Initialize nodes that don't support laziness. This is done after at least one output is
+ * required and before we check that all required inputs are provided. This reduces the
+ * number of "round-trips" through the task pool by one for most nodes. */
+ if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) {
+ this->initialize_non_lazy_node(locked_node);
+ node_state.non_lazy_node_is_initialized = true;
+ }
+ /* Prepare inputs and check if all required inputs are provided. */
+ if (!this->prepare_node_inputs_for_execution(locked_node)) {
+ return;
+ }
+ do_execute_node = true;
+ });
+ return do_execute_node;
}
/* A node is finished when it has computed all outputs that may be used. */
@@ -896,18 +895,18 @@ class GeometryNodesEvaluator {
void node_task_postprocessing(const DNode node, NodeState &node_state)
{
- LockedNode locked_node{*this, node, node_state};
-
- const bool node_has_finished = this->finish_node_if_possible(locked_node);
- const bool reschedule_requested = node_state.schedule_state ==
- NodeScheduleState::RunningAndRescheduled;
- node_state.schedule_state = NodeScheduleState::NotScheduled;
- if (reschedule_requested && !node_has_finished) {
- /* Either the node rescheduled itself or another node tried to schedule it while it ran. */
- this->schedule_node(locked_node);
- }
+ this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ const bool node_has_finished = this->finish_node_if_possible(locked_node);
+ const bool reschedule_requested = node_state.schedule_state ==
+ NodeScheduleState::RunningAndRescheduled;
+ node_state.schedule_state = NodeScheduleState::NotScheduled;
+ if (reschedule_requested && !node_has_finished) {
+ /* Either the node rescheduled itself or another node tried to schedule it while it ran. */
+ this->schedule_node(locked_node);
+ }
- this->assert_expected_outputs_have_been_computed(locked_node);
+ this->assert_expected_outputs_have_been_computed(locked_node);
+ });
}
void assert_expected_outputs_have_been_computed(LockedNode &locked_node)
@@ -1042,13 +1041,14 @@ class GeometryNodesEvaluator {
this->load_unlinked_input_value(locked_node, input_socket, input_state, origin_socket);
locked_node.node_state.missing_required_inputs -= 1;
this->schedule_node(locked_node);
- return;
}
- /* The value has not been computed yet, so when it will be forwarded by another node, this
- * node will be triggered. */
- will_be_triggered_by_other_node = true;
+ else {
+ /* The value has not been computed yet, so when it will be forwarded by another node, this
+ * node will be triggered. */
+ will_be_triggered_by_other_node = true;
- locked_node.delayed_required_outputs.append(DOutputSocket(origin_socket));
+ locked_node.delayed_required_outputs.append(DOutputSocket(origin_socket));
+ }
}
/* If this node will be triggered by another node, we don't have to schedule it now. */
if (!will_be_triggered_by_other_node) {
@@ -1095,15 +1095,16 @@ class GeometryNodesEvaluator {
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- LockedNode locked_node{*this, node, node_state};
- if (output_state.output_usage == ValueUsage::Required) {
- /* Output is marked as required already. So the node is scheduled already. */
- return;
- }
- /* The origin node needs to be scheduled so that it provides the requested input
- * eventually. */
- output_state.output_usage = ValueUsage::Required;
- this->schedule_node(locked_node);
+ this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ if (output_state.output_usage == ValueUsage::Required) {
+ /* Output is marked as required already. So the node is scheduled already. */
+ return;
+ }
+ /* The origin node needs to be scheduled so that it provides the requested input
+ * eventually. */
+ output_state.output_usage = ValueUsage::Required;
+ this->schedule_node(locked_node);
+ });
}
void send_output_unused_notification(const DOutputSocket socket)
@@ -1112,14 +1113,15 @@ class GeometryNodesEvaluator {
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- LockedNode locked_node{*this, node, node_state};
- output_state.potential_users -= 1;
- if (output_state.potential_users == 0) {
- /* The output socket has no users anymore. */
- output_state.output_usage = ValueUsage::Unused;
- /* Schedule the origin node in case it wants to set its inputs as unused as well. */
- this->schedule_node(locked_node);
- }
+ this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ output_state.potential_users -= 1;
+ if (output_state.potential_users == 0) {
+ /* The output socket has no users anymore. */
+ output_state.output_usage = ValueUsage::Unused;
+ /* Schedule the origin node in case it wants to set its inputs as unused as well. */
+ this->schedule_node(locked_node);
+ }
+ });
}
void add_node_to_task_pool(const DNode node)
@@ -1247,28 +1249,27 @@ class GeometryNodesEvaluator {
NodeState &node_state = this->get_node_state(node);
InputState &input_state = node_state.inputs[socket->index()];
- /* Lock the node because we want to change its state. */
- LockedNode locked_node{*this, node, node_state};
-
- if (socket->is_multi_input_socket()) {
- /* Add a new value to the multi-input. */
- MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin, value.get()});
- }
- else {
- /* Assign the value to the input. */
- SingleInputValue &single_value = *input_state.value.single;
- BLI_assert(single_value.value == nullptr);
- single_value.value = value.get();
- }
+ this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ if (socket->is_multi_input_socket()) {
+ /* Add a new value to the multi-input. */
+ MultiInputValue &multi_value = *input_state.value.multi;
+ multi_value.items.append({origin, value.get()});
+ }
+ else {
+ /* Assign the value to the input. */
+ SingleInputValue &single_value = *input_state.value.single;
+ BLI_assert(single_value.value == nullptr);
+ single_value.value = value.get();
+ }
- if (input_state.usage == ValueUsage::Required) {
- node_state.missing_required_inputs--;
- if (node_state.missing_required_inputs == 0) {
- /* Schedule node if all the required inputs have been provided. */
- this->schedule_node(locked_node);
+ if (input_state.usage == ValueUsage::Required) {
+ node_state.missing_required_inputs--;
+ if (node_state.missing_required_inputs == 0) {
+ /* Schedule node if all the required inputs have been provided. */
+ this->schedule_node(locked_node);
+ }
}
- }
+ });
}
void load_unlinked_input_value(LockedNode &locked_node,
@@ -1363,44 +1364,33 @@ class GeometryNodesEvaluator {
{
this->log_socket_value(socket, Span<GPointer>(&value, 1));
}
-};
-LockedNode::~LockedNode()
-{
- /* First unlock the current node. */
- node_state.mutex.unlock();
- /* Then send notifications to the other nodes. */
- for (const DOutputSocket &socket : delayed_required_outputs) {
- evaluator_.send_output_required_notification(socket);
- }
- for (const DOutputSocket &socket : delayed_unused_outputs) {
- evaluator_.send_output_unused_notification(socket);
- }
- for (const DNode &node : delayed_scheduled_nodes) {
- evaluator_.add_node_to_task_pool(node);
- }
-}
+ /* In most cases when `NodeState` is accessed, the node has to be locked first to avoid race
+ * conditions. */
+ template<typename Function>
+ void with_locked_node(const DNode node, NodeState &node_state, const Function &function)
+ {
+ LockedNode locked_node{node, node_state};
-/* TODO: Use a map data structure or so to make this faster. */
-static DInputSocket get_input_by_identifier(const DNode node, const StringRef identifier)
-{
- for (const InputSocketRef *socket : node->inputs()) {
- if (socket->identifier() == identifier) {
- return {node.context(), socket};
- }
- }
- return {};
-}
+ node_state.mutex.lock();
+ /* Isolate this thread because we don't want it to start executing another node. This other
+ * node might want to lock the same mutex leading to a deadlock. */
+ threading::isolate_task([&] { function(locked_node); });
+ node_state.mutex.unlock();
-static DOutputSocket get_output_by_identifier(const DNode node, const StringRef identifier)
-{
- for (const OutputSocketRef *socket : node->outputs()) {
- if (socket->identifier() == identifier) {
- return {node.context(), socket};
+ /* Then send notifications to the other nodes after the node state is unlocked. This avoids
+ * locking two nodes at the same time on this thread and helps to prevent deadlocks. */
+ for (const DOutputSocket &socket : locked_node.delayed_required_outputs) {
+ this->send_output_required_notification(socket);
+ }
+ for (const DOutputSocket &socket : locked_node.delayed_unused_outputs) {
+ this->send_output_unused_notification(socket);
+ }
+ for (const DNode &node : locked_node.delayed_scheduled_nodes) {
+ this->add_node_to_task_pool(node);
}
}
- return {};
-}
+};
NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator,
DNode dnode,
@@ -1415,7 +1405,7 @@ NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator,
bool NodeParamsProvider::can_get_input(StringRef identifier) const
{
- const DInputSocket socket = get_input_by_identifier(this->dnode, identifier);
+ const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
InputState &input_state = node_state_.inputs[socket->index()];
@@ -1433,7 +1423,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
bool NodeParamsProvider::can_set_output(StringRef identifier) const
{
- const DOutputSocket socket = get_output_by_identifier(this->dnode, identifier);
+ const DOutputSocket socket = this->dnode.output_by_identifier(identifier);
BLI_assert(socket);
OutputState &output_state = node_state_.outputs[socket->index()];
@@ -1442,7 +1432,7 @@ bool NodeParamsProvider::can_set_output(StringRef identifier) const
GMutablePointer NodeParamsProvider::extract_input(StringRef identifier)
{
- const DInputSocket socket = get_input_by_identifier(this->dnode, identifier);
+ const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
BLI_assert(!socket->is_multi_input_socket());
BLI_assert(this->can_get_input(identifier));
@@ -1456,7 +1446,7 @@ GMutablePointer NodeParamsProvider::extract_input(StringRef identifier)
Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identifier)
{
- const DInputSocket socket = get_input_by_identifier(this->dnode, identifier);
+ const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
BLI_assert(socket->is_multi_input_socket());
BLI_assert(this->can_get_input(identifier));
@@ -1487,7 +1477,7 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
GPointer NodeParamsProvider::get_input(StringRef identifier) const
{
- const DInputSocket socket = get_input_by_identifier(this->dnode, identifier);
+ const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
BLI_assert(!socket->is_multi_input_socket());
BLI_assert(this->can_get_input(identifier));
@@ -1505,7 +1495,7 @@ GMutablePointer NodeParamsProvider::alloc_output_value(const CPPType &type)
void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value)
{
- const DOutputSocket socket = get_output_by_identifier(this->dnode, identifier);
+ const DOutputSocket socket = this->dnode.output_by_identifier(identifier);
BLI_assert(socket);
evaluator_.log_socket_value(socket, value);
@@ -1519,30 +1509,32 @@ void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value)
bool NodeParamsProvider::lazy_require_input(StringRef identifier)
{
BLI_assert(node_supports_laziness(this->dnode));
- const DInputSocket socket = get_input_by_identifier(this->dnode, identifier);
+ const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
InputState &input_state = node_state_.inputs[socket->index()];
if (input_state.was_ready_for_execution) {
return false;
}
- LockedNode locked_node{evaluator_, this->dnode, node_state_};
- evaluator_.set_input_required(locked_node, socket);
+ evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
+ evaluator_.set_input_required(locked_node, socket);
+ });
return true;
}
void NodeParamsProvider::set_input_unused(StringRef identifier)
{
- const DInputSocket socket = get_input_by_identifier(this->dnode, identifier);
+ const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
- LockedNode locked_node{evaluator_, this->dnode, node_state_};
- evaluator_.set_input_unused(locked_node, socket);
+ evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
+ evaluator_.set_input_unused(locked_node, socket);
+ });
}
bool NodeParamsProvider::output_is_required(StringRef identifier) const
{
- const DOutputSocket socket = get_output_by_identifier(this->dnode, identifier);
+ const DOutputSocket socket = this->dnode.output_by_identifier(identifier);
BLI_assert(socket);
OutputState &output_state = node_state_.outputs[socket->index()];
@@ -1555,7 +1547,7 @@ bool NodeParamsProvider::output_is_required(StringRef identifier) const
bool NodeParamsProvider::lazy_output_is_required(StringRef identifier) const
{
BLI_assert(node_supports_laziness(this->dnode));
- const DOutputSocket socket = get_output_by_identifier(this->dnode, identifier);
+ const DOutputSocket socket = this->dnode.output_by_identifier(identifier);
BLI_assert(socket);
OutputState &output_state = node_state_.outputs[socket->index()];
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index f7ac59f9e4b..3de6bb62c8a 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -284,7 +284,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co
gogd.sy /= gogd.ry;
result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys);
- BKE_mesh_copy_settings(result, mesh_orig);
+ BKE_mesh_copy_parameters_for_eval(result, mesh_orig);
gogd.mverts = result->mvert;
gogd.mpolys = result->mpoly;
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 88851f91337..4677a9bc253 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -218,7 +218,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
}
}
- BKE_mesh_copy_settings(result, mesh);
+ BKE_mesh_copy_parameters_for_eval(result, mesh);
BKE_mesh_calc_edges(result, true, false);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index db01dec4d19..39ebc415021 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -263,28 +263,24 @@ static void simple_helper(void *__restrict userdata,
copy_v3_v3_map(dcut_remap, dcut, axis_map);
switch (curr_deform_data->mode) {
case MOD_SIMPLEDEFORM_MODE_TWIST:
- simpleDeform_twist(curr_deform_data->smd_factor,
- curr_deform_data->deform_axis,
- dcut_remap,
- co_remap); /* apply deform */
+ /* Apply deform. */
+ simpleDeform_twist(
+ curr_deform_data->smd_factor, curr_deform_data->deform_axis, dcut_remap, co_remap);
break;
case MOD_SIMPLEDEFORM_MODE_BEND:
- simpleDeform_bend(curr_deform_data->smd_factor,
- curr_deform_data->deform_axis,
- dcut_remap,
- co_remap); /* apply deform */
+ /* Apply deform. */
+ simpleDeform_bend(
+ curr_deform_data->smd_factor, curr_deform_data->deform_axis, dcut_remap, co_remap);
break;
case MOD_SIMPLEDEFORM_MODE_TAPER:
- simpleDeform_taper(curr_deform_data->smd_factor,
- curr_deform_data->deform_axis,
- dcut_remap,
- co_remap); /* apply deform */
+ /* Apply deform. */
+ simpleDeform_taper(
+ curr_deform_data->smd_factor, curr_deform_data->deform_axis, dcut_remap, co_remap);
break;
case MOD_SIMPLEDEFORM_MODE_STRETCH:
- simpleDeform_stretch(curr_deform_data->smd_factor,
- curr_deform_data->deform_axis,
- dcut_remap,
- co_remap); /* apply deform */
+ /* Apply deform. */
+ simpleDeform_stretch(
+ curr_deform_data->smd_factor, curr_deform_data->deform_axis, dcut_remap, co_remap);
break;
default:
return; /* No simple-deform mode? */
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 0be5c164089..09fa7e9c8ac 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -346,7 +346,7 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
/* Some modifiers can work with pre-tessellated curves only. */
if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
- /* Add button (appearing to be ON) and add tip why this cant be changed. */
+ /* Add button (appearing to be ON) and add tip why this can't be changed. */
sub = uiLayoutRow(row, true);
uiBlock *block = uiLayoutGetBlock(sub);
static int apply_on_spline_always_on_hack = eModifierMode_ApplyOnSpline;
diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc
index c0bf07b8eec..72358844838 100644
--- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc
+++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc
@@ -132,7 +132,7 @@ static void panelRegister(ARegionType *region_type)
static Mesh *create_empty_mesh(const Mesh *input_mesh)
{
Mesh *new_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
- BKE_mesh_copy_settings(new_mesh, input_mesh);
+ BKE_mesh_copy_parameters_for_eval(new_mesh, input_mesh);
return new_mesh;
}
@@ -193,7 +193,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return create_empty_mesh(input_mesh);
}
- BKE_mesh_copy_settings(mesh, input_mesh);
+ BKE_mesh_copy_parameters_for_eval(mesh, input_mesh);
if (vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE) {
BKE_mesh_smooth_flag_set(mesh, true);
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a31306d6b08..4ae4dbc2c7f 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -166,7 +166,10 @@ set(SRC
geometry/nodes/node_geo_curve_deform.cc
geometry/nodes/node_geo_curve_length.cc
geometry/nodes/node_geo_curve_to_mesh.cc
+ geometry/nodes/node_geo_curve_to_points.cc
geometry/nodes/node_geo_curve_resample.cc
+ geometry/nodes/node_geo_curve_reverse.cc
+ geometry/nodes/node_geo_curve_subdivide.cc
geometry/nodes/node_geo_delete_geometry.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_input_material.cc
@@ -191,7 +194,9 @@ set(SRC
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_point_translate.cc
geometry/nodes/node_geo_points_to_volume.cc
+ geometry/nodes/node_geo_raycast.cc
geometry/nodes/node_geo_select_by_material.cc
+ geometry/nodes/node_geo_separate_components.cc
geometry/nodes/node_geo_subdivide.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_switch.cc
@@ -243,7 +248,7 @@ set(SRC
shader/nodes/node_shader_map_range.cc
shader/nodes/node_shader_mapping.c
shader/nodes/node_shader_math.cc
- shader/nodes/node_shader_mixRgb.c
+ shader/nodes/node_shader_mixRgb.cc
shader/nodes/node_shader_mix_shader.c
shader/nodes/node_shader_normal.c
shader/nodes/node_shader_normal_map.c
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index 7ff05449c0b..de9e4c8c812 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -95,6 +95,9 @@ class DNode {
DInputSocket input(int index) const;
DOutputSocket output(int index) const;
+
+ DInputSocket input_by_identifier(StringRef identifier) const;
+ DOutputSocket output_by_identifier(StringRef identifier) const;
};
/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
@@ -173,6 +176,7 @@ class DerivedNodeTree {
Span<const NodeTreeRef *> used_node_tree_refs() const;
bool has_link_cycles() const;
+ bool has_undefined_nodes_or_sockets() const;
void foreach_node(FunctionRef<void(DNode)> callback) const;
std::string to_dot() const;
@@ -287,6 +291,16 @@ inline DOutputSocket DNode::output(int index) const
return {context_, &node_ref_->output(index)};
}
+inline DInputSocket DNode::input_by_identifier(StringRef identifier) const
+{
+ return {context_, &node_ref_->input_by_identifier(identifier)};
+}
+
+inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
+{
+ return {context_, &node_ref_->output_by_identifier(identifier)};
+}
+
/* --------------------------------------------------------------------
* DSocket inline methods.
*/
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index d40553801e3..66f7028af88 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -54,7 +54,10 @@ void register_node_type_geo_convex_hull(void);
void register_node_type_geo_curve_deform(void);
void register_node_type_geo_curve_length(void);
void register_node_type_geo_curve_to_mesh(void);
+void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_resample(void);
+void register_node_type_geo_curve_reverse(void);
+void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_input_material(void);
@@ -79,8 +82,10 @@ void register_node_type_geo_point_scale(void);
void register_node_type_geo_point_separate(void);
void register_node_type_geo_point_translate(void);
void register_node_type_geo_points_to_volume(void);
+void register_node_type_geo_raycast(void);
void register_node_type_geo_sample_texture(void);
void register_node_type_geo_select_by_material(void);
+void register_node_type_geo_separate_components(void);
void register_node_type_geo_subdivide(void);
void register_node_type_geo_subdivision_surface(void);
void register_node_type_geo_switch(void);
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 5795617deb0..b028fc28bbc 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -70,6 +70,8 @@ class NodeTreeRef;
class LinkRef;
class InternalLinkRef;
+using SocketIndexByIdentifierMap = Map<std::string, int>;
+
class SocketRef : NonCopyable, NonMovable {
protected:
NodeRef *node_;
@@ -125,6 +127,7 @@ class SocketRef : NonCopyable, NonMovable {
bNodeTree *btree() const;
bool is_available() const;
+ bool is_undefined() const;
void *default_value() const;
template<typename T> T *default_value() const;
@@ -168,6 +171,8 @@ class NodeRef : NonCopyable, NonMovable {
Vector<InputSocketRef *> inputs_;
Vector<OutputSocketRef *> outputs_;
Vector<InternalLinkRef *> internal_links_;
+ SocketIndexByIdentifierMap *input_index_by_identifier_;
+ SocketIndexByIdentifierMap *output_index_by_identifier_;
friend NodeTreeRef;
@@ -181,6 +186,9 @@ class NodeRef : NonCopyable, NonMovable {
const InputSocketRef &input(int index) const;
const OutputSocketRef &output(int index) const;
+ const InputSocketRef &input_by_identifier(StringRef identifier) const;
+ const OutputSocketRef &output_by_identifier(StringRef identifier) const;
+
bNode *bnode() const;
bNodeTree *btree() const;
@@ -197,6 +205,7 @@ class NodeRef : NonCopyable, NonMovable {
bool is_group_output_node() const;
bool is_muted() const;
bool is_frame() const;
+ bool is_undefined() const;
void *storage() const;
template<typename T> T *storage() const;
@@ -244,6 +253,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Vector<OutputSocketRef *> output_sockets_;
Vector<LinkRef *> links_;
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
+ Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_;
public:
NodeTreeRef(bNodeTree *btree);
@@ -260,6 +270,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Span<const LinkRef *> links() const;
bool has_link_cycles() const;
+ bool has_undefined_nodes_or_sockets() const;
bNodeTree *btree() const;
StringRefNull name() const;
@@ -276,6 +287,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
bNodeSocket *bsocket);
void create_linked_socket_caches();
+ void create_socket_identifier_maps();
};
using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>;
@@ -417,6 +429,11 @@ inline bool SocketRef::is_available() const
return (bsocket_->flag & SOCK_UNAVAIL) == 0;
}
+inline bool SocketRef::is_undefined() const
+{
+ return bsocket_->typeinfo == &NodeSocketTypeUndefined;
+}
+
inline void *SocketRef::default_value() const
{
return bsocket_->default_value;
@@ -494,6 +511,18 @@ inline const OutputSocketRef &NodeRef::output(int index) const
return *outputs_[index];
}
+inline const InputSocketRef &NodeRef::input_by_identifier(StringRef identifier) const
+{
+ const int index = input_index_by_identifier_->lookup_as(identifier);
+ return this->input(index);
+}
+
+inline const OutputSocketRef &NodeRef::output_by_identifier(StringRef identifier) const
+{
+ const int index = output_index_by_identifier_->lookup_as(identifier);
+ return this->output(index);
+}
+
inline bNode *NodeRef::bnode() const
{
return bnode_;
@@ -554,6 +583,11 @@ inline bool NodeRef::is_frame() const
return bnode_->type == NODE_FRAME;
}
+inline bool NodeRef::is_undefined() const
+{
+ return bnode_->typeinfo == &NodeTypeUndefined;
+}
+
inline bool NodeRef::is_muted() const
{
return (bnode_->flag & NODE_MUTED) != 0;
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 77340d67fb6..4e39568f688 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -293,7 +293,10 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve
DefNode(GeometryNode, GEO_NODE_CURVE_DEFORM, def_geo_curve_deform, "CURVE_DEFORM", CurveDeform, "Curve Deform", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
@@ -318,7 +321,9 @@ DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE",
DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "")
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
+DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_SELECT_BY_MATERIAL, 0, "SELECT_BY_MATERIAL", SelectByMaterial, "Select by Material", "")
+DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 93cada2982b..46e9d36c09c 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -47,6 +47,7 @@ void update_attribute_input_socket_availabilities(bNode &node,
name_is_available &&
((socket->type == SOCK_STRING && mode_ == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) ||
(socket->type == SOCK_FLOAT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ||
+ (socket->type == SOCK_INT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_INTEGER) ||
(socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) ||
(socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR));
nodeSetSocketAvailability(socket, socket_is_available);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
index d1b71d6f2ba..9b6824fdb5c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
@@ -78,7 +78,7 @@ static void align_rotations_auto_pivot(const VArray<float3> &vectors,
const float3 local_main_axis,
const MutableSpan<float3> rotations)
{
- parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
for (const int i : range) {
const float3 vector = vectors[i];
if (is_zero_v3(vector)) {
@@ -129,7 +129,7 @@ static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
return;
}
- parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
for (const int i : range) {
const float3 vector = vectors[i];
if (is_zero_v3(vector)) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index 5293dd8c876..c5740395dfb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -95,7 +95,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
MutableSpan<ColorGeometry4f> results = attribute_result.as_span();
ColorBand *color_ramp = &node_storage->color_ramp;
- parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
index 599c9e58e52..06a4327a6c5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
@@ -144,7 +144,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, float(0.0f));
MutableSpan<float> results = attribute_result.as_span<float>();
- parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
for (const int i : range) {
results[i] = BKE_curvemapping_evaluateF(cumap, 3, attribute_in[i]);
}
@@ -156,7 +156,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
GVArray_Typed<float3> attribute_in = component.attribute_get_for_read<float3>(
input_name, result_domain, float3(0.0f));
MutableSpan<float3> results = attribute_result.as_span<float3>();
- parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_curvemapping_evaluate3F(cumap, results[i], attribute_in[i]);
}
@@ -169,7 +169,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
component.attribute_get_for_read<ColorGeometry4f>(
input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
- parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
index 40fe675bd6c..00f38fb0c6b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
@@ -209,7 +209,7 @@ static void map_range_float(const VArray<float> &attribute_input,
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
- parallel_for(span.index_range(), 2048, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
}
@@ -218,7 +218,7 @@ static void map_range_float(const VArray<float> &attribute_input,
}
case NODE_MAP_RANGE_STEPPED: {
const float steps = params.get_input<float>("Steps");
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
}
@@ -226,7 +226,7 @@ static void map_range_float(const VArray<float> &attribute_input,
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
}
@@ -234,7 +234,7 @@ static void map_range_float(const VArray<float> &attribute_input,
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
}
@@ -249,7 +249,7 @@ static void map_range_float(const VArray<float> &attribute_input,
const float clamp_min = min_to < max_to ? min_to : max_to;
const float clamp_max = min_to < max_to ? max_to : min_to;
- parallel_for(results.index_range(), 2048, [&](IndexRange range) {
+ threading::parallel_for(results.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
results[i] = std::clamp(results[i], clamp_min, clamp_max);
}
@@ -273,7 +273,7 @@ static void map_range_float3(const VArray<float3> &attribute_input,
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
@@ -284,7 +284,7 @@ static void map_range_float3(const VArray<float3> &attribute_input,
}
case NODE_MAP_RANGE_STEPPED: {
const float3 steps = params.get_input<float3>("Steps_001");
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i].x = map_stepped(
span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
@@ -297,7 +297,7 @@ static void map_range_float3(const VArray<float3> &attribute_input,
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
results[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
@@ -307,7 +307,7 @@ static void map_range_float3(const VArray<float3> &attribute_input,
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
- parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
results[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index ce0ca31cc2b..9309863f4e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -159,7 +159,7 @@ static void do_math_operation(const VArray<float> &span_a,
{
bool success = try_dispatch_float_math_fl_fl_fl_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(span_result.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(span_result.size()), 512, [&](IndexRange range) {
for (const int i : range) {
span_result[i] = math_function(span_a[i], span_b[i], span_c[i]);
}
@@ -176,7 +176,7 @@ static void do_math_operation(const VArray<float> &span_a,
{
bool success = try_dispatch_float_math_fl_fl_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(span_result.size()), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(span_result.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
span_result[i] = math_function(span_a[i], span_b[i]);
}
@@ -192,7 +192,7 @@ static void do_math_operation(const VArray<float> &span_input,
{
bool success = try_dispatch_float_math_fl_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(span_result.size()), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(span_result.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
span_result[i] = math_function(span_input[i]);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
index a6bd6c0ee32..931b7758a57 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
@@ -88,7 +88,7 @@ static void do_mix_operation_float(const int blend_mode,
VMutableArray<float> &results)
{
const int size = results.size();
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float factor = factors[i];
float3 a{inputs_a[i]};
@@ -107,7 +107,7 @@ static void do_mix_operation_float3(const int blend_mode,
VMutableArray<float3> &results)
{
const int size = results.size();
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float factor = factors[i];
float3 a = inputs_a[i];
@@ -125,7 +125,7 @@ static void do_mix_operation_color4f(const int blend_mode,
VMutableArray<ColorGeometry4f> &results)
{
const int size = results.size();
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float factor = factors[i];
ColorGeometry4f a = inputs_a[i];
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index 9c22b7fa87f..b7863d38fc2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -71,7 +71,7 @@ static void proximity_calc(MutableSpan<float> distance_span,
const bool store_locations)
{
IndexRange range = positions.index_range();
- parallel_for(range, 512, [&](IndexRange range) {
+ threading::parallel_for(range, 512, [&](IndexRange range) {
BVHTreeNearest nearest_from_mesh;
BVHTreeNearest nearest_from_pointcloud;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index 286411b7d28..eeb77abd624 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -126,7 +126,7 @@ static void randomize_attribute(MutableSpan<T> span,
/* The operations could be templated too, but it doesn't make the code much shorter. */
switch (operation) {
case GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE:
- parallel_for(span.index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
span[i] = random_value;
@@ -134,7 +134,7 @@ static void randomize_attribute(MutableSpan<T> span,
});
break;
case GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD:
- parallel_for(span.index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
span[i] = span[i] + random_value;
@@ -142,7 +142,7 @@ static void randomize_attribute(MutableSpan<T> span,
});
break;
case GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT:
- parallel_for(span.index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
span[i] = span[i] - random_value;
@@ -150,7 +150,7 @@ static void randomize_attribute(MutableSpan<T> span,
});
break;
case GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY:
- parallel_for(span.index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
span[i] = span[i] * random_value;
@@ -170,7 +170,7 @@ static void randomize_attribute_bool(MutableSpan<bool> span,
{
BLI_assert(operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE);
UNUSED_VARS_NDEBUG(operation);
- parallel_for(span.index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
const bool random_value = BLI_hash_int_2d_to_float(ids[i], seed) > 0.5f;
span[i] = random_value;
@@ -190,7 +190,7 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
BLI_assert(hashes.size() == hash_attribute->size());
const CPPType &cpp_type = hash_attribute->type();
GVArray_GSpan items{*hash_attribute};
- parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
hashes[i] = cpp_type.hash(items[i]);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
index d6b1ad3e9e0..e0a3f5ad334 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -90,7 +90,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
mapping_name, result_domain, {0, 0, 0});
MutableSpan<ColorGeometry4f> colors = attribute_out.as_span();
- parallel_for(IndexRange(mapping_attribute.size()), 128, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(mapping_attribute.size()), 128, [&](IndexRange range) {
for (const int i : range) {
TexResult texture_result = {0};
const float3 position = mapping_attribute[i];
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
index 4b677dc5c82..d1114713672 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
@@ -102,14 +102,6 @@ static void get_result_domain_and_data_type(const GeometrySet &src_geometry,
}
}
-static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
-{
- /* This only updates a cache and can be considered to be logically const. */
- const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
- const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
- return {looptris, looptris_len};
-}
-
static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
const VArray<float3> &positions,
const MutableSpan<int> r_indices,
@@ -212,7 +204,7 @@ static void get_closest_mesh_polygons(const Mesh &mesh,
Array<int> looptri_indices(positions.size());
get_closest_mesh_looptris(mesh, positions, looptri_indices, r_distances_sq, r_positions);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+ Span<MLoopTri> looptris = bke::mesh_surface_sample::get_mesh_looptris(mesh);
for (const int i : positions.index_range()) {
const MLoopTri &looptri = looptris[looptri_indices[i]];
r_poly_indices[i] = looptri.poly;
@@ -262,32 +254,6 @@ static void get_closest_mesh_corners(const Mesh &mesh,
}
}
-static void get_barycentric_coords(const Mesh &mesh,
- const Span<int> looptri_indices,
- const Span<float3> positions,
- const MutableSpan<float3> r_bary_coords)
-{
- BLI_assert(r_bary_coords.size() == positions.size());
- BLI_assert(r_bary_coords.size() == looptri_indices.size());
-
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : r_bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
-
- const int v0_index = mesh.mloop[looptri.tri[0]].v;
- const int v1_index = mesh.mloop[looptri.tri[1]].v;
- const int v2_index = mesh.mloop[looptri.tri[2]].v;
-
- interp_weights_tri_v3(r_bary_coords[i],
- mesh.mvert[v0_index].co,
- mesh.mvert[v1_index].co,
- mesh.mvert[v2_index].co,
- positions[i]);
- }
-}
-
static void transfer_attribute_nearest_face_interpolated(const GeometrySet &src_geometry,
GeometryComponent &dst_component,
const VArray<float3> &dst_positions,
@@ -308,8 +274,11 @@ static void transfer_attribute_nearest_face_interpolated(const GeometrySet &src_
if (mesh->totpoly == 0) {
return;
}
+
ReadAttributeLookup src_attribute = component->attribute_try_get_for_read(src_name, data_type);
- if (!src_attribute) {
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ dst_name, dst_domain, data_type);
+ if (!src_attribute || !dst_attribute) {
return;
}
@@ -318,45 +287,10 @@ static void transfer_attribute_nearest_face_interpolated(const GeometrySet &src_
Array<float3> positions(tot_samples);
get_closest_mesh_looptris(*mesh, dst_positions, looptri_indices, {}, positions);
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- dst_name, dst_domain, data_type);
- if (!dst_attribute) {
- return;
- }
- GMutableSpan dst_span = dst_attribute.as_span();
- Array<float3> bary_coords;
+ bke::mesh_surface_sample::MeshAttributeInterpolator interp(mesh, positions, looptri_indices);
+ interp.sample_attribute(
+ src_attribute, dst_attribute, bke::mesh_surface_sample::eAttributeMapMode::INTERPOLATED);
- /* Compute barycentric coordinates only when they are needed. */
- if (src_attribute.domain != ATTR_DOMAIN_FACE) {
- bary_coords.reinitialize(tot_samples);
- get_barycentric_coords(*mesh, looptri_indices, positions, bary_coords);
- }
- /* Interpolate the source attribute on the surface. */
- switch (src_attribute.domain) {
- case ATTR_DOMAIN_POINT: {
- bke::mesh_surface_sample::sample_point_attribute(
- *mesh, looptri_indices, bary_coords, *src_attribute.varray, dst_span);
- break;
- }
- case ATTR_DOMAIN_FACE: {
- bke::mesh_surface_sample::sample_face_attribute(
- *mesh, looptri_indices, *src_attribute.varray, dst_span);
- break;
- }
- case ATTR_DOMAIN_CORNER: {
- bke::mesh_surface_sample::sample_corner_attribute(
- *mesh, looptri_indices, bary_coords, *src_attribute.varray, dst_span);
- break;
- }
- case ATTR_DOMAIN_EDGE: {
- /* Not yet supported. */
- break;
- }
- default: {
- BLI_assert_unreachable();
- break;
- }
- }
dst_attribute.save();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
index b04e04d1cb7..e2cf6e8b480 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
@@ -186,7 +186,7 @@ static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 a = span_a[i];
const float3 b = span_b[i];
@@ -218,7 +218,7 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 a = span_a[i];
const float3 b = span_b[i];
@@ -251,7 +251,7 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 a = span_a[i];
const float3 b = span_b[i];
@@ -282,7 +282,7 @@ static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 a = span_a[i];
const float3 b = span_b[i];
@@ -312,7 +312,7 @@ static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 a = span_a[i];
const float b = span_b[i];
@@ -340,7 +340,7 @@ static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 in = span_a[i];
const float3 out = math_function(in);
@@ -367,7 +367,7 @@ static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a,
bool success = try_dispatch_float_math_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- parallel_for(IndexRange(size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float3 in = span_a[i];
const float out = math_function(in);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc
index 4d568ab5c3a..da753dfc11b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc
@@ -154,7 +154,7 @@ static void do_vector_rotate_around_axis(const VArray<float3> &vector,
VArray_Span<float3> span_axis{axis};
VArray_Span<float> span_angle{angle};
- parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
float angle = (invert) ? -span_angle[i] : span_angle[i];
results[i] = vector_rotate_around_axis(span_vector[i], span_center[i], span_axis[i], angle);
@@ -173,7 +173,7 @@ static void do_vector_rotate_around_fixed_axis(const VArray<float3> &vector,
VArray_Span<float3> span_center{center};
VArray_Span<float> span_angle{angle};
- parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
float angle = (invert) ? -span_angle[i] : span_angle[i];
results[i] = vector_rotate_around_axis(span_vector[i], span_center[i], axis, angle);
@@ -191,7 +191,7 @@ static void do_vector_rotate_euler(const VArray<float3> &vector,
VArray_Span<float3> span_center{center};
VArray_Span<float3> span_rotation{rotation};
- parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i] = vector_rotate_euler(span_vector[i], span_center[i], span_rotation[i], invert);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc
index 9b485284b35..dde7191fb69 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc
@@ -220,7 +220,7 @@ static void execute_on_component(const GeoNodeExecParams &params,
const Bounds bounds = position_bounds(positions);
const Bounds parameter_bounds = input.use_bounds ? bounds : dummy_parameter_bounds(deform_axis);
- parallel_for(positions.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(positions.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const float parameter = process_parameter(
positions[i], axis_index, is_negative, input, parameter_bounds);
@@ -267,7 +267,7 @@ static void geo_node_curve_deform_exec(GeoNodeExecParams params)
spline.evaluated_positions(),
spline.evaluated_tangents(),
spline.evaluated_normals(),
- spline.interpolate_to_evaluated_points(spline.radii()),
+ spline.interpolate_to_evaluated(spline.radii()),
total_length,
params.extract_input<bool>("Stretch"),
params.extract_input<bool>("Use Bounds")};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index e879ec624c0..fc65d1754e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -94,16 +94,16 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
Array<float> uniform_samples = input_spline.sample_uniform_index_factors(count);
- input_spline.sample_based_on_index_factors<float3>(
+ input_spline.sample_with_index_factors<float3>(
input_spline.evaluated_positions(), uniform_samples, output_spline->positions());
- input_spline.sample_based_on_index_factors<float>(
- input_spline.interpolate_to_evaluated_points(input_spline.radii()),
+ input_spline.sample_with_index_factors<float>(
+ input_spline.interpolate_to_evaluated(input_spline.radii()),
uniform_samples,
output_spline->radii());
- input_spline.sample_based_on_index_factors<float>(
- input_spline.interpolate_to_evaluated_points(input_spline.tilts()),
+ input_spline.sample_with_index_factors<float>(
+ input_spline.interpolate_to_evaluated(input_spline.tilts()),
uniform_samples,
output_spline->tilts());
@@ -123,8 +123,8 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
return false;
}
- input_spline.sample_based_on_index_factors(
- *input_spline.interpolate_to_evaluated_points(*input_attribute),
+ input_spline.sample_with_index_factors(
+ *input_spline.interpolate_to_evaluated(*input_attribute),
uniform_samples,
*output_attribute);
@@ -138,19 +138,28 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
const SampleModeParam &mode_param)
{
- std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+ Span<SplinePtr> input_splines = input_curve.splines();
- for (const SplinePtr &spline : input_curve.splines()) {
- if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_COUNT) {
- BLI_assert(mode_param.count);
- output_curve->add_spline(resample_spline(*spline, *mode_param.count));
- }
- else if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
- BLI_assert(mode_param.length);
- const float length = spline->length();
- const int count = std::max(int(length / *mode_param.length), 1);
- output_curve->add_spline(resample_spline(*spline, count));
- }
+ std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+ output_curve->resize(input_splines.size());
+ MutableSpan<SplinePtr> output_splines = output_curve->splines();
+
+ if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_COUNT) {
+ threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ BLI_assert(mode_param.count);
+ output_splines[i] = resample_spline(*input_splines[i], *mode_param.count);
+ }
+ });
+ }
+ else if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
+ threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ const float length = input_splines[i]->length();
+ const int count = std::max(int(length / *mode_param.length), 1);
+ output_splines[i] = resample_spline(*input_splines[i], count);
+ }
+ });
}
output_curve->attributes = input_curve.attributes;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
new file mode 100644
index 00000000000..e92d22a6064
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -0,0 +1,132 @@
+/*
+ * 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 "BLI_task.hh"
+
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_reverse_in[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_reverse_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+/**
+ * Reverse the data in a MutableSpan object.
+ */
+template<typename T> static void reverse_data(MutableSpan<T> r_data)
+{
+ const int size = r_data.size();
+ for (const int i : IndexRange(size / 2)) {
+ std::swap(r_data[size - 1 - i], r_data[i]);
+ }
+}
+
+/**
+ * Reverse and Swap the data between 2 MutableSpans.
+ */
+template<typename T> static void reverse_data(MutableSpan<T> left, MutableSpan<T> right)
+{
+ BLI_assert(left.size() == right.size());
+ const int size = left.size();
+
+ for (const int i : IndexRange(size / 2 + size % 2)) {
+ std::swap(left[i], right[size - 1 - i]);
+ std::swap(right[i], left[size - 1 - i]);
+ }
+}
+
+static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ if (!geometry_set.has_curve()) {
+ params.set_output("Curve", geometry_set);
+ return;
+ }
+
+ /* Retrieve data for write access so we can avoid new allocations for the reversed data. */
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
+ selection_name, ATTR_DOMAIN_CURVE, true);
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ if (!selection[i]) {
+ continue;
+ }
+
+ reverse_data<float3>(splines[i]->positions());
+ reverse_data<float>(splines[i]->radii());
+ reverse_data<float>(splines[i]->tilts());
+
+ splines[i]->attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ std::optional<blender::fn::GMutableSpan> output_attribute =
+ splines[i]->attributes.get_for_write(name);
+ if (!output_attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ reverse_data(output_attribute->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ /* Deal with extra info on derived types. */
+ if (BezierSpline *spline = dynamic_cast<BezierSpline *>(splines[i].get())) {
+ reverse_data<BezierSpline::HandleType>(spline->handle_types_left());
+ reverse_data<BezierSpline::HandleType>(spline->handle_types_right());
+ reverse_data<float3>(spline->handle_positions_left(), spline->handle_positions_right());
+ }
+ else if (NURBSpline *spline = dynamic_cast<NURBSpline *>(splines[i].get())) {
+ reverse_data<float>(spline->weights());
+ }
+ /* Nothing to do for poly splines. */
+
+ splines[i]->mark_cache_invalid();
+ }
+ });
+
+ params.set_output("Curve", geometry_set);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_reverse()
+{
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_reverse_in, geo_node_curve_reverse_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
new file mode 100644
index 00000000000..3de2604cd0a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -0,0 +1,407 @@
+/*
+ * 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 "BLI_task.hh"
+#include "BLI_timeit.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+using blender::fn::GVArray_For_GSpan;
+using blender::fn::GVArray_For_Span;
+using blender::fn::GVArray_Typed;
+
+static bNodeSocketTemplate geo_node_curve_subdivide_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_STRING, N_("Cuts")},
+ {SOCK_INT, N_("Cuts"), 1, 0, 0, 0, 0, 1000},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_subdivide_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE);
+}
+
+static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
+ sizeof(NodeGeometryCurveSubdivide), __func__);
+
+ data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
+ node->storage = data;
+}
+
+namespace blender::nodes {
+
+static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
+
+ update_attribute_input_socket_availabilities(
+ *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type);
+}
+
+static Array<int> get_subdivided_offsets(const Spline &spline,
+ const VArray<int> &cuts,
+ const int spline_offset)
+{
+ Array<int> offsets(spline.segments_size() + 1);
+ int offset = 0;
+ for (const int i : IndexRange(spline.segments_size())) {
+ offsets[i] = offset;
+ offset = offset + std::max(cuts[spline_offset + i], 0) + 1;
+ }
+ offsets.last() = offset;
+ return offsets;
+}
+
+template<typename T>
+static void subdivide_attribute(Span<T> src,
+ const Span<int> offsets,
+ const bool is_cyclic,
+ MutableSpan<T> dst)
+{
+ const int src_size = src.size();
+ threading::parallel_for(IndexRange(src_size - 1), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const int cuts = offsets[i + 1] - offsets[i];
+ dst[offsets[i]] = src[i];
+ const float factor_delta = 1.0f / (cuts + 1.0f);
+ for (const int cut : IndexRange(cuts)) {
+ const float factor = (cut + 1) * factor_delta;
+ dst[offsets[i] + cut] = attribute_math::mix2(factor, src[i], src[i + 1]);
+ }
+ }
+ });
+
+ if (is_cyclic) {
+ const int i = src_size - 1;
+ const int cuts = offsets[i + 1] - offsets[i];
+ dst[offsets[i]] = src.last();
+ const float factor_delta = 1.0f / (cuts + 1.0f);
+ for (const int cut : IndexRange(cuts)) {
+ const float factor = (cut + 1) * factor_delta;
+ dst[offsets[i] + cut] = attribute_math::mix2(factor, src.last(), src.first());
+ }
+ }
+ else {
+ dst.last() = src.last();
+ }
+}
+
+/**
+ * De Casteljau Bezier subdivision.
+ *
+ * <pre>
+ * handle_prev handle_next
+ * O----------------O
+ * / \
+ * / x---O---x \
+ * / new_* \
+ * / \
+ * O O
+ * point_prev point_next
+ * </pre>
+ */
+static void calculate_new_bezier_point(const float3 &point_prev,
+ float3 &handle_prev,
+ float3 &new_left_handle,
+ float3 &new_position,
+ float3 &new_right_handle,
+ float3 &handle_next,
+ const float3 &point_next,
+ const float parameter)
+{
+ const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter);
+
+ handle_prev = float3::interpolate(point_prev, handle_prev, parameter);
+ handle_next = float3::interpolate(handle_next, point_next, parameter);
+ new_left_handle = float3::interpolate(handle_prev, center_point, parameter);
+ new_right_handle = float3::interpolate(center_point, handle_next, parameter);
+ new_position = float3::interpolate(new_left_handle, new_right_handle, parameter);
+}
+
+/**
+ * In order to generate a Bezier spline with the same shape as the input spline, apply the
+ * De Casteljau algorithm iteratively for the provided number of cuts, constantly updating the
+ * previous result point's right handle and the left handle at the end of the segment.
+ *
+ * \note Non-vector segments in the result spline are given free handles. This could possibly be
+ * improved with another pass that sets handles to aligned where possible, but currently that does
+ * not provide much benefit for the increased complexity.
+ */
+static void subdivide_bezier_segment(const BezierSpline &src,
+ const int index,
+ const int offset,
+ const int result_size,
+ Span<float3> src_positions,
+ Span<float3> src_handles_left,
+ Span<float3> src_handles_right,
+ MutableSpan<float3> dst_positions,
+ MutableSpan<float3> dst_handles_left,
+ MutableSpan<float3> dst_handles_right,
+ MutableSpan<BezierSpline::HandleType> dst_type_left,
+ MutableSpan<BezierSpline::HandleType> dst_type_right)
+{
+ const bool is_last_cyclic_segment = index == (src.size() - 1);
+ const int next_index = is_last_cyclic_segment ? 0 : index + 1;
+ if (src.segment_is_vector(index)) {
+ if (is_last_cyclic_segment) {
+ dst_type_left.first() = BezierSpline::HandleType::Vector;
+ }
+ dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector);
+ dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector);
+
+ dst_positions[offset] = src_positions[index];
+ const float factor_delta = 1.0f / result_size;
+ for (const int cut : IndexRange(result_size)) {
+ const float factor = cut * factor_delta;
+ dst_positions[offset + cut] = attribute_math::mix2(
+ factor, src_positions[index], src_positions[next_index]);
+ }
+ }
+ else {
+ if (is_last_cyclic_segment) {
+ dst_type_left.first() = BezierSpline::HandleType::Free;
+ }
+ dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Free);
+ dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free);
+
+ const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
+ dst_positions[offset] = src_positions[index];
+ dst_handles_right[offset] = src_handles_right[index];
+ dst_handles_left[i_segment_last] = src_handles_left[next_index];
+
+ for (const int cut : IndexRange(result_size - 1)) {
+ const float parameter = 1.0f / (result_size - cut);
+ calculate_new_bezier_point(dst_positions[offset + cut],
+ dst_handles_right[offset + cut],
+ dst_handles_left[offset + cut + 1],
+ dst_positions[offset + cut + 1],
+ dst_handles_right[offset + cut + 1],
+ dst_handles_left[i_segment_last],
+ src_positions[next_index],
+ parameter);
+ }
+ }
+}
+
+static void subdivide_bezier_spline(const BezierSpline &src,
+ const Span<int> offsets,
+ BezierSpline &dst)
+{
+ Span<float3> src_positions = src.positions();
+ Span<float3> src_handles_left = src.handle_positions_left();
+ Span<float3> src_handles_right = src.handle_positions_right();
+ MutableSpan<float3> dst_positions = dst.positions();
+ MutableSpan<float3> dst_handles_left = dst.handle_positions_left();
+ MutableSpan<float3> dst_handles_right = dst.handle_positions_right();
+ MutableSpan<BezierSpline::HandleType> dst_type_left = dst.handle_types_left();
+ MutableSpan<BezierSpline::HandleType> dst_type_right = dst.handle_types_right();
+
+ threading::parallel_for(IndexRange(src.size() - 1), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ subdivide_bezier_segment(src,
+ i,
+ offsets[i],
+ offsets[i + 1] - offsets[i],
+ src_positions,
+ src_handles_left,
+ src_handles_right,
+ dst_positions,
+ dst_handles_left,
+ dst_handles_right,
+ dst_type_left,
+ dst_type_right);
+ }
+ });
+
+ if (src.is_cyclic()) {
+ const int i_last = src.size() - 1;
+ subdivide_bezier_segment(src,
+ i_last,
+ offsets[i_last],
+ offsets.last() - offsets[i_last],
+ src_positions,
+ src_handles_left,
+ src_handles_right,
+ dst_positions,
+ dst_handles_left,
+ dst_handles_right,
+ dst_type_left,
+ dst_type_right);
+ }
+ else {
+ dst_positions.last() = src_positions.last();
+ }
+}
+
+static void subdivide_builtin_attributes(const Spline &src_spline,
+ const Span<int> offsets,
+ Spline &dst_spline)
+{
+ const bool is_cyclic = src_spline.is_cyclic();
+ subdivide_attribute<float>(src_spline.radii(), offsets, is_cyclic, dst_spline.radii());
+ subdivide_attribute<float>(src_spline.tilts(), offsets, is_cyclic, dst_spline.tilts());
+ switch (src_spline.type()) {
+ case Spline::Type::Poly: {
+ const PolySpline &src = static_cast<const PolySpline &>(src_spline);
+ PolySpline &dst = static_cast<PolySpline &>(dst_spline);
+ subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
+ break;
+ }
+ case Spline::Type::Bezier: {
+ const BezierSpline &src = static_cast<const BezierSpline &>(src_spline);
+ BezierSpline &dst = static_cast<BezierSpline &>(dst_spline);
+ subdivide_bezier_spline(src, offsets, dst);
+ dst.mark_cache_invalid();
+ break;
+ }
+ case Spline::Type::NURBS: {
+ const NURBSpline &src = static_cast<const NURBSpline &>(src_spline);
+ NURBSpline &dst = static_cast<NURBSpline &>(dst_spline);
+ subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
+ subdivide_attribute<float>(src.weights(), offsets, is_cyclic, dst.weights());
+ break;
+ }
+ }
+}
+
+static void subdivide_dynamic_attributes(const Spline &src_spline,
+ const Span<int> offsets,
+ Spline &dst_spline)
+{
+ const bool is_cyclic = src_spline.is_cyclic();
+ src_spline.attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = src_spline.attributes.get_for_read(name);
+ BLI_assert(src);
+
+ if (!dst_spline.attributes.create(name, meta_data.data_type)) {
+ /* Since the source spline of the same type had the attribute, adding it should work. */
+ BLI_assert_unreachable();
+ }
+
+ std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(name);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(dst->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ subdivide_attribute<T>(src->typed<T>(), offsets, is_cyclic, dst->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+static SplinePtr subdivide_spline(const Spline &spline,
+ const VArray<int> &cuts,
+ const int spline_offset)
+{
+ /* Since we expect to access each value many times, it should be worth it to make sure the
+ * attribute is a real span (especially considering the note below). Using the offset at each
+ * point facilitates subdividing in parallel later. */
+ Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
+ const int result_size = offsets.last() + int(!spline.is_cyclic());
+ SplinePtr new_spline = spline.copy_only_settings();
+ new_spline->resize(result_size);
+ subdivide_builtin_attributes(spline, offsets, *new_spline);
+ subdivide_dynamic_attributes(spline, offsets, *new_spline);
+ return new_spline;
+}
+
+/**
+ * \note Passing the virtual array for the entire spline is possibly quite inefficient here when
+ * the attribute was on the point domain and stored separately for each spline already, and it
+ * prevents some other optimizations like skipping splines with a single attribute value of < 1.
+ * However, it allows the node to access builtin attribute easily, so it the makes most sense this
+ * way until the attribute API is refactored.
+ */
+static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
+ const VArray<int> &cuts)
+{
+ const Array<int> control_point_offsets = input_curve.control_point_offsets();
+ const Span<SplinePtr> input_splines = input_curve.splines();
+
+ std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+ output_curve->resize(input_splines.size());
+ output_curve->attributes = input_curve.attributes;
+ MutableSpan<SplinePtr> output_splines = output_curve->splines();
+
+ threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ output_splines[i] = subdivide_spline(*input_splines[i], cuts, control_point_offsets[i]);
+ }
+ });
+
+ return output_curve;
+}
+
+static void geo_node_subdivide_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ if (!geometry_set.has_curve()) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
+ GVArray_Typed<int> cuts = params.get_input_attribute<int>(
+ "Cuts", component, ATTR_DOMAIN_POINT, 0);
+ if (cuts->is_single() && cuts->get_internal_single() < 1) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts);
+
+ params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_subdivide()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_subdivide_in, geo_node_curve_subdivide_out);
+ ntype.draw_buttons = geo_node_curve_subdivide_layout;
+ node_type_storage(&ntype,
+ "NodeGeometryCurveSubdivide",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ node_type_init(&ntype, geo_node_curve_subdivide_init);
+ node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update);
+ ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index b6f04352929..c0d817385e2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -16,7 +16,7 @@
#include "BLI_array.hh"
#include "BLI_float4x4.hh"
-#include "BLI_timeit.hh"
+#include "BLI_task.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -47,8 +47,8 @@ static void vert_extrude_to_mesh_data(const Spline &spline,
const float3 profile_vert,
MutableSpan<MVert> r_verts,
MutableSpan<MEdge> r_edges,
- int &vert_offset,
- int &edge_offset)
+ int vert_offset,
+ int edge_offset)
{
Span<float3> positions = spline.evaluated_positions();
@@ -85,10 +85,10 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
MutableSpan<MEdge> r_edges,
MutableSpan<MLoop> r_loops,
MutableSpan<MPoly> r_polys,
- int &vert_offset,
- int &edge_offset,
- int &loop_offset,
- int &poly_offset)
+ int vert_offset,
+ int edge_offset,
+ int loop_offset,
+ int poly_offset)
{
const int spline_vert_len = spline.evaluated_points_size();
const int spline_edge_len = spline.evaluated_edges_size();
@@ -181,7 +181,7 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
Span<float3> normals = spline.evaluated_normals();
Span<float3> profile_positions = profile_spline.evaluated_positions();
- GVArray_Typed<float> radii = spline.interpolate_to_evaluated_points(spline.radii());
+ GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii());
for (const int i_ring : IndexRange(spline_vert_len)) {
float4x4 point_matrix = float4x4::from_normalized_axis_data(
positions[i_ring], normals[i_ring], tangents[i_ring]);
@@ -207,63 +207,114 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
}
}
-static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &profile_curve)
+static inline int spline_extrude_vert_size(const Spline &curve, const Spline &profile)
{
- int profile_vert_total = 0;
- int profile_edge_total = 0;
- for (const SplinePtr &profile_spline : profile_curve.splines()) {
- profile_vert_total += profile_spline->evaluated_points_size();
- profile_edge_total += profile_spline->evaluated_edges_size();
- }
+ return curve.evaluated_points_size() * profile.evaluated_points_size();
+}
- int vert_total = 0;
- int edge_total = 0;
- int poly_total = 0;
- for (const SplinePtr &spline : curve.splines()) {
- const int spline_vert_len = spline->evaluated_points_size();
- const int spline_edge_len = spline->evaluated_edges_size();
- vert_total += spline_vert_len * profile_vert_total;
- poly_total += spline_edge_len * profile_edge_total;
-
- /* Add the ring edges, with one ring for every curve vertex, and the edge loops
- * that run along the length of the curve, starting on the first profile. */
- edge_total += profile_edge_total * spline_vert_len + profile_vert_total * spline_edge_len;
- }
- const int corner_total = poly_total * 4;
+static inline int spline_extrude_edge_size(const Spline &curve, const Spline &profile)
+{
+ /* Add the ring edges, with one ring for every curve vertex, and the edge loops
+ * that run along the length of the curve, starting on the first profile. */
+ return curve.evaluated_points_size() * profile.evaluated_edges_size() +
+ curve.evaluated_edges_size() * profile.evaluated_points_size();
+}
- if (vert_total == 0) {
- return nullptr;
- }
+static inline int spline_extrude_loop_size(const Spline &curve, const Spline &profile)
+{
+ return curve.evaluated_edges_size() * profile.evaluated_edges_size() * 4;
+}
- Mesh *mesh = BKE_mesh_new_nomain(vert_total, edge_total, 0, corner_total, poly_total);
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
- mesh->flag |= ME_AUTOSMOOTH;
- mesh->smoothresh = DEG2RADF(180.0f);
+static inline int spline_extrude_poly_size(const Spline &curve, const Spline &profile)
+{
+ return curve.evaluated_edges_size() * profile.evaluated_edges_size();
+}
+struct ResultOffsets {
+ Array<int> vert;
+ Array<int> edge;
+ Array<int> loop;
+ Array<int> poly;
+};
+static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<SplinePtr> curves)
+{
+ const int total = profiles.size() * curves.size();
+ Array<int> vert(total + 1);
+ Array<int> edge(total + 1);
+ Array<int> loop(total + 1);
+ Array<int> poly(total + 1);
+
+ int mesh_index = 0;
int vert_offset = 0;
int edge_offset = 0;
int loop_offset = 0;
int poly_offset = 0;
- for (const SplinePtr &spline : curve.splines()) {
- for (const SplinePtr &profile_spline : profile_curve.splines()) {
- spline_extrude_to_mesh_data(*spline,
- *profile_spline,
- verts,
- edges,
- loops,
- polys,
- vert_offset,
- edge_offset,
- loop_offset,
- poly_offset);
+ for (const int i_spline : curves.index_range()) {
+ for (const int i_profile : profiles.index_range()) {
+ vert[mesh_index] = vert_offset;
+ edge[mesh_index] = edge_offset;
+ loop[mesh_index] = loop_offset;
+ poly[mesh_index] = poly_offset;
+ vert_offset += spline_extrude_vert_size(*curves[i_spline], *profiles[i_profile]);
+ edge_offset += spline_extrude_edge_size(*curves[i_spline], *profiles[i_profile]);
+ loop_offset += spline_extrude_loop_size(*curves[i_spline], *profiles[i_profile]);
+ poly_offset += spline_extrude_poly_size(*curves[i_spline], *profiles[i_profile]);
+ mesh_index++;
}
}
+ vert.last() = vert_offset;
+ edge.last() = edge_offset;
+ loop.last() = loop_offset;
+ poly.last() = poly_offset;
+
+ return {std::move(vert), std::move(edge), std::move(loop), std::move(poly)};
+}
+
+/**
+ * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
+ * Although it would be a sensible decision to use the better topology information available while
+ * generating the mesh to also generate the normals, that work may wasted if the output mesh is
+ * changed anyway in a way that affects the normals. So currently this code uses the safer /
+ * simpler solution of not calculating normals.
+ */
+static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &profile)
+{
+ Span<SplinePtr> profiles = profile.splines();
+ Span<SplinePtr> curves = curve.splines();
+
+ const ResultOffsets offsets = calculate_result_offsets(profiles, curves);
+ if (offsets.vert.last() == 0) {
+ return nullptr;
+ }
- BKE_mesh_calc_normals(mesh);
+ Mesh *mesh = BKE_mesh_new_nomain(
+ offsets.vert.last(), offsets.edge.last(), 0, offsets.loop.last(), offsets.poly.last());
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ mesh->flag |= ME_AUTOSMOOTH;
+ mesh->smoothresh = DEG2RADF(180.0f);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+
+ threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) {
+ for (const int i_spline : curves_range) {
+ const int spline_start_index = i_spline * profiles.size();
+ threading::parallel_for(profiles.index_range(), 128, [&](IndexRange profiles_range) {
+ for (const int i_profile : profiles_range) {
+ const int i_mesh = spline_start_index + i_profile;
+ spline_extrude_to_mesh_data(*curves[i_spline],
+ *profiles[i_profile],
+ {mesh->mvert, mesh->totvert},
+ {mesh->medge, mesh->totedge},
+ {mesh->mloop, mesh->totloop},
+ {mesh->mpoly, mesh->totpoly},
+ offsets.vert[i_mesh],
+ offsets.edge[i_mesh],
+ offsets.loop[i_mesh],
+ offsets.poly[i_mesh]);
+ }
+ });
+ }
+ });
return mesh;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
new file mode 100644
index 00000000000..2725c625913
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -0,0 +1,390 @@
+/*
+ * 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 "BLI_array.hh"
+#include "BLI_task.hh"
+#include "BLI_timeit.hh"
+
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_to_points_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_INT, N_("Count"), 10, 0, 0, 0, 2, 100000},
+ {SOCK_FLOAT, N_("Length"), 0.1f, 0.0f, 0.0f, 0.0f, 0.001f, FLT_MAX, PROP_DISTANCE},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_to_points_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
+ sizeof(NodeGeometryCurveToPoints), __func__);
+
+ data->mode = GEO_NODE_CURVE_SAMPLE_COUNT;
+ node->storage = data;
+}
+
+static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+
+ bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *length_socket = count_socket->next;
+
+ nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_SAMPLE_COUNT);
+ nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
+}
+
+namespace blender::nodes {
+
+/**
+ * Evaluate splines in parallel to speed up the rest of the node's execution.
+ */
+static void evaluate_splines(Span<SplinePtr> splines)
+{
+ threading::parallel_for_each(splines, [](const SplinePtr &spline) {
+ /* These functions fill the corresponding caches on each spline. */
+ spline->evaluated_positions();
+ spline->evaluated_tangents();
+ spline->evaluated_normals();
+ spline->evaluated_lengths();
+ });
+}
+
+static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
+ const GeometryNodeCurveSampleMode mode,
+ const CurveEval &curve,
+ const Span<SplinePtr> splines)
+{
+ const int size = curve.splines().size();
+ switch (mode) {
+ case GEO_NODE_CURVE_SAMPLE_COUNT: {
+ const int count = params.extract_input<int>("Count");
+ if (count < 1) {
+ return {0};
+ }
+ Array<int> offsets(size + 1);
+ for (const int i : offsets.index_range()) {
+ offsets[i] = count * i;
+ }
+ return offsets;
+ }
+ case GEO_NODE_CURVE_SAMPLE_LENGTH: {
+ /* Don't allow asymptotic count increase for low resolution values. */
+ const float resolution = std::max(params.extract_input<float>("Length"), 0.0001f);
+ Array<int> offsets(size + 1);
+ int offset = 0;
+ for (const int i : IndexRange(size)) {
+ offsets[i] = offset;
+ offset += splines[i]->length() / resolution;
+ }
+ offsets.last() = offset;
+ return offsets;
+ }
+ case GEO_NODE_CURVE_SAMPLE_EVALUATED: {
+ return curve.evaluated_point_offsets();
+ }
+ }
+ BLI_assert_unreachable();
+ return {0};
+}
+
+/**
+ * \note This doesn't store a map for spline domain attributes.
+ */
+struct ResultAttributes {
+ int result_size;
+ MutableSpan<float3> positions;
+ MutableSpan<float> radii;
+ MutableSpan<float> tilts;
+
+ Map<std::string, GMutableSpan> point_attributes;
+
+ MutableSpan<float3> tangents;
+ MutableSpan<float3> normals;
+ MutableSpan<float3> rotations;
+};
+
+static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const StringRef name,
+ const CustomDataType data_type)
+{
+ points.attribute_try_create(name, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
+ WriteAttributeLookup attribute = points.attribute_try_get_for_write(name);
+ BLI_assert(attribute);
+ return attribute.varray->get_internal_span();
+}
+
+template<typename T>
+static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const StringRef name)
+{
+ GMutableSpan attribute = create_attribute_and_retrieve_span(
+ points, name, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
+ return attribute.typed<T>();
+}
+
+/**
+ * Create references for all result point cloud attributes to simplify accessing them later on.
+ */
+static ResultAttributes create_point_attributes(PointCloudComponent &points,
+ const CurveEval &curve)
+{
+ ResultAttributes attributes;
+
+ attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
+ attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
+ attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
+
+ /* Because of the invariants of the curve component, we use the attributes of the
+ * first spline as a representative for the attribute meta data all splines. */
+ curve.splines().first()->attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ attributes.point_attributes.add_new(
+ name, create_attribute_and_retrieve_span(points, name, meta_data.data_type));
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
+ attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
+ attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
+
+ return attributes;
+}
+
+/**
+ * TODO: For non-poly splines, this has double copies that could be avoided as part
+ * of a general look at optimizing uses of #Spline::interpolate_to_evaluated.
+ */
+static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
+ Span<int> offsets,
+ ResultAttributes &data)
+{
+ threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+
+ data.positions.slice(offset, size).copy_from(spline.evaluated_positions());
+ spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size));
+ spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size));
+
+ for (const Map<std::string, GMutableSpan>::Item &item : data.point_attributes.items()) {
+ const StringRef name = item.key;
+ GMutableSpan point_span = item.value;
+
+ BLI_assert(spline.attributes.get_for_read(name));
+ GSpan spline_span = *spline.attributes.get_for_read(name);
+
+ spline.interpolate_to_evaluated(spline_span)
+ ->materialize(point_span.slice(offset, size).data());
+ }
+
+ data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents());
+ data.normals.slice(offset, size).copy_from(spline.evaluated_normals());
+ }
+ });
+}
+
+static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
+ Span<int> offsets,
+ ResultAttributes &data)
+{
+ threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+ if (size == 0) {
+ continue;
+ }
+
+ const Array<float> uniform_samples = spline.sample_uniform_index_factors(size);
+
+ spline.sample_with_index_factors<float3>(
+ spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size));
+
+ spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()),
+ uniform_samples,
+ data.radii.slice(offset, size));
+
+ spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.tilts()),
+ uniform_samples,
+ data.tilts.slice(offset, size));
+
+ for (const Map<std::string, GMutableSpan>::Item &item : data.point_attributes.items()) {
+ const StringRef name = item.key;
+ GMutableSpan point_span = item.value;
+
+ BLI_assert(spline.attributes.get_for_read(name));
+ GSpan spline_span = *spline.attributes.get_for_read(name);
+
+ spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span),
+ uniform_samples,
+ point_span.slice(offset, size));
+ }
+
+ spline.sample_with_index_factors<float3>(
+ spline.evaluated_tangents(), uniform_samples, data.tangents.slice(offset, size));
+ for (float3 &tangent : data.tangents) {
+ tangent.normalize();
+ }
+
+ spline.sample_with_index_factors<float3>(
+ spline.evaluated_normals(), uniform_samples, data.normals.slice(offset, size));
+ for (float3 &normals : data.normals) {
+ normals.normalize();
+ }
+ }
+ });
+}
+
+/**
+ * \note Use attributes from the curve component rather than the attribute data directly on the
+ * attribute storage to allow reading the virtual spline attributes like "cyclic" and "resolution".
+ */
+static void copy_spline_domain_attributes(const CurveComponent &curve_component,
+ Span<int> offsets,
+ PointCloudComponent &points)
+{
+ curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_CURVE) {
+ return true;
+ }
+ GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
+ name, ATTR_DOMAIN_CURVE, meta_data.data_type);
+ const CPPType &type = spline_attribute->type();
+
+ OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
+ name, ATTR_DOMAIN_POINT, meta_data.data_type);
+ GMutableSpan result = result_attribute.as_span();
+
+ for (const int i : IndexRange(spline_attribute->size())) {
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+ if (size != 0) {
+ BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
+ spline_attribute->get(i, buffer);
+ type.fill_initialized(buffer, result[offset], size);
+ }
+ }
+
+ result_attribute.save();
+ return true;
+ });
+}
+
+static void create_default_rotation_attribute(ResultAttributes &data)
+{
+ threading::parallel_for(IndexRange(data.result_size), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ data.rotations[i] = float4x4::from_normalized_axis_data(
+ {0, 0, 0}, data.normals[i], data.tangents[i])
+ .to_euler();
+ }
+ });
+}
+
+static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
+{
+ NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage;
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ if (!geometry_set.has_curve()) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const CurveEval &curve = *curve_component.get_for_read();
+ const Span<SplinePtr> splines = curve.splines();
+ curve.assert_valid_point_attributes();
+
+ evaluate_splines(splines);
+
+ const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines);
+ const int total_size = offsets.last();
+ if (total_size == 0) {
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ GeometrySet result = GeometrySet::create_with_pointcloud(BKE_pointcloud_new_nomain(total_size));
+ PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>();
+
+ ResultAttributes new_attributes = create_point_attributes(point_component, curve);
+
+ switch (mode) {
+ case GEO_NODE_CURVE_SAMPLE_COUNT:
+ case GEO_NODE_CURVE_SAMPLE_LENGTH:
+ copy_uniform_sample_point_attributes(splines, offsets, new_attributes);
+ break;
+ case GEO_NODE_CURVE_SAMPLE_EVALUATED:
+ copy_evaluated_point_attributes(splines, offsets, new_attributes);
+ break;
+ }
+
+ copy_spline_domain_attributes(curve_component, offsets, point_component);
+ create_default_rotation_attribute(new_attributes);
+
+ /* The default radius is way too large for points, divide by 10. */
+ for (float &radius : new_attributes.radii) {
+ radius *= 0.1f;
+ }
+
+ params.set_output("Geometry", std::move(result));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_to_points()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_to_points_in, geo_node_curve_to_points_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec;
+ ntype.draw_buttons = geo_node_curve_to_points_layout;
+ node_type_storage(
+ &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
+ node_type_init(&ntype, geo_node_curve_to_points_init);
+ node_type_update(&ntype, geo_node_curve_to_points_update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 910adc467d6..b1da2dcd3c4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -120,7 +120,7 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src,
static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
{
- SplinePtr new_spline = spline.copy_settings();
+ SplinePtr new_spline = spline.copy_only_settings();
new_spline->resize(mask.size());
spline_copy_builtin_attributes(spline, *new_spline, mask);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index adfd924f185..bc758b59987 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -23,8 +23,12 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "NOD_type_conversions.hh"
+
#include "node_geometry_util.hh"
+using blender::fn::GVArray_For_GSpan;
+
static bNodeSocketTemplate geo_node_join_geometry_in[] = {
{SOCK_GEOMETRY,
N_("Geometry"),
@@ -79,7 +83,7 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent
const Mesh *first_input_mesh = src_components[0]->get_for_read();
Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- BKE_mesh_copy_settings(new_mesh, first_input_mesh);
+ BKE_mesh_copy_parameters_for_eval(new_mesh, first_input_mesh);
for (const int i : IndexRange(materials.size())) {
Material *material = materials[i];
@@ -157,35 +161,30 @@ static Array<const GeometryComponent *> to_base_components(Span<const Component
return components;
}
-static Set<std::string> find_all_attribute_names(Span<const GeometryComponent *> components)
+static Map<std::string, AttributeMetaData> get_final_attribute_info(
+ Span<const GeometryComponent *> components, Span<StringRef> ignored_attributes)
{
- Set<std::string> attribute_names;
- for (const GeometryComponent *component : components) {
- Set<std::string> names = component->attribute_names();
- for (const std::string &name : names) {
- attribute_names.add(name);
- }
- }
- return attribute_names;
-}
+ Map<std::string, AttributeMetaData> info;
-static void determine_final_data_type_and_domain(Span<const GeometryComponent *> components,
- StringRef attribute_name,
- CustomDataType *r_type,
- AttributeDomain *r_domain)
-{
- Vector<CustomDataType> data_types;
- Vector<AttributeDomain> domains;
for (const GeometryComponent *component : components) {
- ReadAttributeLookup attribute = component->attribute_try_get_for_read(attribute_name);
- if (attribute) {
- data_types.append(bke::cpp_type_to_custom_data_type(attribute.varray->type()));
- domains.append(attribute.domain);
- }
+ component->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
+ if (ignored_attributes.contains(name)) {
+ return true;
+ }
+ info.add_or_modify(
+ name,
+ [&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
+ [&](AttributeMetaData *meta_data_final) {
+ meta_data_final->data_type = blender::bke::attribute_data_type_highest_complexity(
+ {meta_data_final->data_type, meta_data.data_type});
+ meta_data_final->domain = blender::bke::attribute_domain_highest_priority(
+ {meta_data_final->domain, meta_data.domain});
+ });
+ return true;
+ });
}
- *r_type = bke::attribute_data_type_highest_complexity(data_types);
- *r_domain = bke::attribute_domain_highest_priority(domains);
+ return info;
}
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
@@ -219,23 +218,20 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
GeometryComponent &result,
Span<StringRef> ignored_attributes = {})
{
- Set<std::string> attribute_names = find_all_attribute_names(src_components);
- for (StringRef name : ignored_attributes) {
- attribute_names.remove(name);
- }
+ const Map<std::string, AttributeMetaData> info = get_final_attribute_info(src_components,
+ ignored_attributes);
- for (const std::string &attribute_name : attribute_names) {
- CustomDataType data_type;
- AttributeDomain domain;
- determine_final_data_type_and_domain(src_components, attribute_name, &data_type, &domain);
+ for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
+ const StringRef name = item.key;
+ const AttributeMetaData &meta_data = item.value;
OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
- attribute_name, domain, data_type);
+ name, meta_data.domain, meta_data.data_type);
if (!write_attribute) {
continue;
}
GMutableSpan dst_span = write_attribute.as_span();
- fill_new_attribute(src_components, attribute_name, data_type, domain, dst_span);
+ fill_new_attribute(src_components, name, meta_data.data_type, meta_data.domain, dst_span);
write_attribute.save();
}
}
@@ -306,6 +302,127 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
UNUSED_VARS(src_components, dst_component);
}
+/**
+ * \note This takes advantage of the fact that creating attributes on joined curves never
+ * changes a point attribute into a spline attribute; it is always the other way around.
+ */
+static void ensure_control_point_attribute(const StringRef name,
+ const CustomDataType data_type,
+ Span<CurveComponent *> src_components,
+ CurveEval &result)
+{
+ MutableSpan<SplinePtr> splines = result.splines();
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ /* In order to fill point attributes with spline domain attribute values where necessary, keep
+ * track of the curve each spline came from while iterating over the splines in the result. */
+ int src_component_index = 0;
+ int spline_index_in_component = 0;
+ const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
+
+ for (SplinePtr &spline : splines) {
+ std::optional<GSpan> attribute = spline->attributes.get_for_read(name);
+
+ if (attribute) {
+ if (attribute->type() != type) {
+ /* In this case, the attribute exists, but it has the wrong type. So create a buffer
+ * for the converted values, do the conversion, and then replace the attribute. */
+ void *converted_buffer = MEM_mallocN_aligned(
+ spline->size() * type.size(), type.alignment(), __func__);
+
+ const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions();
+ conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type)
+ ->materialize(converted_buffer);
+
+ spline->attributes.remove(name);
+ spline->attributes.create_by_move(name, data_type, converted_buffer);
+ }
+ }
+ else {
+ spline->attributes.create(name, data_type);
+
+ if (current_curve->attributes.get_for_read(name)) {
+ /* In this case the attribute did not exist, but there is a spline domain attribute
+ * we can retrieve a value from, as a spline to point domain conversion. So fill the
+ * new attribute with the value for this spline. */
+ GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read(
+ name, data_type, nullptr);
+
+ BLI_assert(spline->attributes.get_for_read(name));
+ std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(name);
+
+ BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
+ current_curve_attribute->get(spline_index_in_component, buffer);
+ type.fill_initialized(buffer, new_attribute->data(), new_attribute->size());
+ }
+ }
+
+ /* Move to the next spline and maybe the next input component. */
+ spline_index_in_component++;
+ if (spline != splines.last() && spline_index_in_component >= current_curve->splines().size()) {
+ src_component_index++;
+ spline_index_in_component = 0;
+
+ current_curve = src_components[src_component_index]->get_for_read();
+ }
+ }
+}
+
+/**
+ * Fill data for an attribute on the new curve based on all source curves.
+ */
+static void ensure_spline_attribute(const StringRef name,
+ const CustomDataType data_type,
+ Span<CurveComponent *> src_components,
+ CurveEval &result)
+{
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ result.attributes.create(name, data_type);
+ GMutableSpan result_attribute = *result.attributes.get_for_write(name);
+
+ int offset = 0;
+ for (const CurveComponent *component : src_components) {
+ const CurveEval &curve = *component->get_for_read();
+ const int size = curve.splines().size();
+ if (size == 0) {
+ continue;
+ }
+ GVArrayPtr read_attribute = curve.attributes.get_for_read(name, data_type, nullptr);
+ GVArray_GSpan src_span{*read_attribute};
+
+ const void *src_buffer = src_span.data();
+ type.copy_to_initialized_n(src_buffer, result_attribute[offset], size);
+
+ offset += size;
+ }
+}
+
+/**
+ * Special handling for copying spline attributes. This is necessary because we move the splines
+ * out of the source components instead of copying them, meaning we can no longer access point
+ * domain attributes on the source components.
+ *
+ * \warning Splines have been moved out of the source components at this point, so it
+ * is important to only read curve-level data (spline domain attributes) from them.
+ */
+static void join_curve_attributes(const Map<std::string, AttributeMetaData> &info,
+ Span<CurveComponent *> src_components,
+ CurveEval &result)
+{
+ for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
+ const StringRef name = item.key;
+ const AttributeMetaData meta_data = item.value;
+
+ if (meta_data.domain == ATTR_DOMAIN_CURVE) {
+ ensure_spline_attribute(name, meta_data.data_type, src_components, result);
+ }
+ else {
+ ensure_control_point_attribute(name, meta_data.data_type, src_components, result);
+ }
+ }
+}
+
static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, GeometrySet &result)
{
Vector<CurveComponent *> src_components;
@@ -328,6 +445,11 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
return;
}
+ /* Retrieve attribute info before moving the splines out of the input components. */
+ const Map<std::string, AttributeMetaData> info = get_final_attribute_info(
+ {(const GeometryComponent **)src_components.data(), src_components.size()},
+ {"position", "radius", "tilt", "cyclic", "resolution"});
+
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
CurveEval *dst_curve = new CurveEval();
for (CurveComponent *component : src_components) {
@@ -336,14 +458,9 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
dst_curve->add_spline(std::move(spline));
}
}
-
- /* For now, remove all custom attributes, since they might have different types,
- * or an attribute might not exist on all splines. */
dst_curve->attributes.reallocate(dst_curve->splines().size());
- CustomData_reset(&dst_curve->attributes.data);
- for (SplinePtr &spline : dst_curve->splines()) {
- CustomData_reset(&spline->attributes.data);
- }
+
+ join_curve_attributes(info, src_components, *dst_curve);
dst_component.replace(dst_curve);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index 9651301cb34..3a93bc22b7e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -43,6 +43,7 @@ Mesh *create_cube_mesh(const float size)
const BMeshCreateParams bmcp = {true};
const BMAllocTemplate allocsize = {8, 12, 24, 6};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+ BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, nullptr);
BMO_op_callf(bm,
BMO_FLAG_DEFAULTS,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index a3a1b72006c..22195b9e8db 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -26,7 +26,7 @@
static bNodeSocketTemplate geo_node_mesh_primitive_ico_sphere_in[] = {
{SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
- {SOCK_INT, N_("Subdivisions"), 1, 0, 0, 0, 0, 7},
+ {SOCK_INT, N_("Subdivisions"), 1, 0, 0, 0, 1, 7},
{-1, ""},
};
@@ -44,6 +44,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
const BMeshCreateParams bmcp = {true};
const BMAllocTemplate allocsize = {0, 0, 0, 0};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+ BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, nullptr);
BMO_op_callf(bm,
BMO_FLAG_DEFAULTS,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 0fb7910c904..637003a46c7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -62,7 +62,7 @@ static void copy_attributes_to_points(CurveEval &curve,
if (source_attribute_names.contains_as("tilt")) {
const GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
"tilt", ATTR_DOMAIN_POINT, 0.0f);
- parallel_for(splines.index_range(), 256, [&](IndexRange range) {
+ threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
copy_attribute_to_points<float>(
*tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
@@ -73,7 +73,7 @@ static void copy_attributes_to_points(CurveEval &curve,
if (source_attribute_names.contains_as("radius")) {
const GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
"radius", ATTR_DOMAIN_POINT, 1.0f);
- parallel_for(splines.index_range(), 256, [&](IndexRange range) {
+ threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
copy_attribute_to_points<float>(
*radius_attribute, point_to_vert_maps[i], splines[i]->radii());
@@ -97,7 +97,7 @@ static void copy_attributes_to_points(CurveEval &curve,
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type());
- parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
/* Create attribute on the spline points. */
splines[i]->attributes.create(name, data_type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index e52ab1b2127..b119b7b31e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -189,7 +189,7 @@ static void add_instances_from_component(InstancesComponent &instances,
* (anything except for collection mode with "Whole Collection" turned off). */
if (possible_handles.size() == 1) {
const int handle = possible_handles.first();
- parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
for (const int i : range) {
handles[i] = handle;
transforms[i] = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]);
@@ -200,7 +200,7 @@ static void add_instances_from_component(InstancesComponent &instances,
else {
const int seed = params.get_input<int>("Seed");
Array<uint32_t> ids = get_geometry_element_ids_as_uints(src_geometry, ATTR_DOMAIN_POINT);
- parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
for (const int i : range) {
const int index = BLI_hash_int_2d(ids[i], seed) % possible_handles.size();
const int handle = possible_handles[index];
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
new file mode 100644
index 00000000000..bfd6027e0fc
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -0,0 +1,321 @@
+/*
+ * 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 "DNA_mesh_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_sample.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_raycast_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_GEOMETRY, N_("Target Geometry")},
+ {SOCK_STRING, N_("Ray Direction")},
+ {SOCK_VECTOR, N_("Ray Direction"), 0.0, 0.0, 1.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_STRING, N_("Ray Length")},
+ {SOCK_FLOAT, N_("Ray Length"), 100.0, 0.0, 0.0, 0.0, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_STRING, N_("Target Attribute")},
+ {SOCK_STRING, N_("Is Hit")},
+ {SOCK_STRING, N_("Hit Position")},
+ {SOCK_STRING, N_("Hit Normal")},
+ {SOCK_STRING, N_("Hit Distance")},
+ {SOCK_STRING, N_("Hit Attribute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_raycast_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
+ uiItemR(layout, ptr, "input_type_ray_direction", 0, IFACE_("Ray Direction"), ICON_NONE);
+ uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE);
+}
+
+static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
+ __func__);
+ data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
+ data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
+ node->storage = data;
+}
+
+static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage;
+ blender::nodes::update_attribute_input_socket_availabilities(
+ *node,
+ "Ray Direction",
+ (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction);
+ blender::nodes::update_attribute_input_socket_availabilities(
+ *node, "Ray Length", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length);
+}
+
+namespace blender::nodes {
+
+static void raycast_to_mesh(const Mesh *mesh,
+ const VArray<float3> &ray_origins,
+ const VArray<float3> &ray_directions,
+ const VArray<float> &ray_lengths,
+ const MutableSpan<bool> r_hit,
+ const MutableSpan<int> r_hit_indices,
+ const MutableSpan<float3> r_hit_positions,
+ const MutableSpan<float3> r_hit_normals,
+ const MutableSpan<float> r_hit_distances)
+{
+ BLI_assert(ray_origins.size() == ray_directions.size());
+ BLI_assert(ray_origins.size() == ray_lengths.size());
+ BLI_assert(ray_origins.size() == r_hit.size() || r_hit.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_indices.size() || r_hit_indices.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_positions.size() || r_hit_positions.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_normals.size() || r_hit_normals.is_empty());
+ BLI_assert(ray_origins.size() == r_hit_distances.size() || r_hit_distances.is_empty());
+
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, const_cast<Mesh *>(mesh), BVHTREE_FROM_LOOPTRI, 4);
+
+ if (tree_data.tree != nullptr) {
+ for (const int i : ray_origins.index_range()) {
+ const float ray_length = ray_lengths[i];
+ const float3 ray_origin = ray_origins[i];
+ const float3 ray_direction = ray_directions[i].normalized();
+
+ BVHTreeRayHit hit;
+ hit.index = -1;
+ hit.dist = ray_length;
+ if (BLI_bvhtree_ray_cast(tree_data.tree,
+ ray_origin,
+ ray_direction,
+ 0.0f,
+ &hit,
+ tree_data.raycast_callback,
+ &tree_data) != -1) {
+ if (!r_hit.is_empty()) {
+ r_hit[i] = hit.index >= 0;
+ }
+ if (!r_hit_indices.is_empty()) {
+ /* Index should always be a valid looptri index, use 0 when hit failed. */
+ r_hit_indices[i] = max_ii(hit.index, 0);
+ }
+ if (!r_hit_positions.is_empty()) {
+ r_hit_positions[i] = hit.co;
+ }
+ if (!r_hit_normals.is_empty()) {
+ r_hit_normals[i] = hit.no;
+ }
+ if (!r_hit_distances.is_empty()) {
+ r_hit_distances[i] = hit.dist;
+ }
+ }
+ else {
+ if (!r_hit.is_empty()) {
+ r_hit[i] = false;
+ }
+ if (!r_hit_indices.is_empty()) {
+ r_hit_indices[i] = 0;
+ }
+ if (!r_hit_positions.is_empty()) {
+ r_hit_positions[i] = float3(0.0f, 0.0f, 0.0f);
+ }
+ if (!r_hit_normals.is_empty()) {
+ r_hit_normals[i] = float3(0.0f, 0.0f, 0.0f);
+ }
+ if (!r_hit_distances.is_empty()) {
+ r_hit_distances[i] = ray_length;
+ }
+ }
+ }
+
+ free_bvhtree_from_mesh(&tree_data);
+ }
+}
+
+static bke::mesh_surface_sample::eAttributeMapMode get_map_mode(
+ GeometryNodeRaycastMapMode map_mode)
+{
+ switch (map_mode) {
+ case GEO_NODE_RAYCAST_INTERPOLATED:
+ return bke::mesh_surface_sample::eAttributeMapMode::INTERPOLATED;
+ default:
+ case GEO_NODE_RAYCAST_NEAREST:
+ return bke::mesh_surface_sample::eAttributeMapMode::NEAREST;
+ }
+}
+
+static void raycast_from_points(const GeoNodeExecParams &params,
+ const GeometrySet &src_geometry,
+ GeometryComponent &dst_component,
+ const StringRef hit_name,
+ const StringRef hit_position_name,
+ const StringRef hit_normal_name,
+ const StringRef hit_distance_name,
+ const Span<std::string> hit_attribute_names,
+ const Span<std::string> hit_attribute_output_names)
+{
+ BLI_assert(hit_attribute_names.size() == hit_attribute_output_names.size());
+
+ const MeshComponent *src_mesh_component = src_geometry.get_component_for_read<MeshComponent>();
+ if (src_mesh_component == nullptr) {
+ return;
+ }
+ const Mesh *src_mesh = src_mesh_component->get_for_read();
+ if (src_mesh == nullptr) {
+ return;
+ }
+ if (src_mesh->totpoly == 0) {
+ return;
+ }
+
+ const NodeGeometryRaycast &storage = *(const NodeGeometryRaycast *)params.node().storage;
+ bke::mesh_surface_sample::eAttributeMapMode map_mode = get_map_mode(
+ (GeometryNodeRaycastMapMode)storage.mapping);
+ const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+
+ GVArray_Typed<float3> ray_origins = dst_component.attribute_get_for_read<float3>(
+ "position", result_domain, {0, 0, 0});
+ GVArray_Typed<float3> ray_directions = params.get_input_attribute<float3>(
+ "Ray Direction", dst_component, result_domain, {0, 0, 0});
+ GVArray_Typed<float> ray_lengths = params.get_input_attribute<float>(
+ "Ray Length", dst_component, result_domain, 0);
+
+ OutputAttribute_Typed<bool> hit_attribute =
+ dst_component.attribute_try_get_for_output_only<bool>(hit_name, result_domain);
+ OutputAttribute_Typed<float3> hit_position_attribute =
+ dst_component.attribute_try_get_for_output_only<float3>(hit_position_name, result_domain);
+ OutputAttribute_Typed<float3> hit_normal_attribute =
+ dst_component.attribute_try_get_for_output_only<float3>(hit_normal_name, result_domain);
+ OutputAttribute_Typed<float> hit_distance_attribute =
+ dst_component.attribute_try_get_for_output_only<float>(hit_distance_name, result_domain);
+
+ /* Positions and looptri indices are always needed for interpolation,
+ * so create temporary arrays if no output attribute is given.
+ */
+ Array<int> hit_indices;
+ Array<float3> hit_positions_internal;
+ if (!hit_attribute_names.is_empty()) {
+ hit_indices.reinitialize(ray_origins->size());
+
+ if (!hit_position_attribute) {
+ hit_positions_internal.reinitialize(ray_origins->size());
+ }
+ }
+ const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>();
+ const MutableSpan<float3> hit_positions = hit_position_attribute ?
+ hit_position_attribute.as_span() :
+ hit_positions_internal;
+ const MutableSpan<float3> hit_normals = hit_normal_attribute ? hit_normal_attribute.as_span() :
+ MutableSpan<float3>();
+ const MutableSpan<float> hit_distances = hit_distance_attribute ?
+ hit_distance_attribute.as_span() :
+ MutableSpan<float>();
+
+ raycast_to_mesh(src_mesh,
+ ray_origins,
+ ray_directions,
+ ray_lengths,
+ is_hit,
+ hit_indices,
+ hit_positions,
+ hit_normals,
+ hit_distances);
+
+ hit_attribute.save();
+ hit_position_attribute.save();
+ hit_normal_attribute.save();
+ hit_distance_attribute.save();
+
+ /* Custom interpolated attributes */
+ bke::mesh_surface_sample::MeshAttributeInterpolator interp(src_mesh, hit_positions, hit_indices);
+ for (const int i : hit_attribute_names.index_range()) {
+ const std::optional<AttributeMetaData> meta_data = src_mesh_component->attribute_get_meta_data(
+ hit_attribute_names[i]);
+ if (meta_data) {
+ ReadAttributeLookup hit_attribute = src_mesh_component->attribute_try_get_for_read(
+ hit_attribute_names[i]);
+ OutputAttribute hit_attribute_output = dst_component.attribute_try_get_for_output_only(
+ hit_attribute_output_names[i], result_domain, meta_data->data_type);
+
+ interp.sample_attribute(hit_attribute, hit_attribute_output, map_mode);
+
+ hit_attribute_output.save();
+ }
+ }
+}
+
+static void geo_node_raycast_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet cast_geometry_set = params.extract_input<GeometrySet>("Target Geometry");
+
+ const std::string hit_name = params.extract_input<std::string>("Is Hit");
+ const std::string hit_position_name = params.extract_input<std::string>("Hit Position");
+ const std::string hit_normal_name = params.extract_input<std::string>("Hit Normal");
+ const std::string hit_distance_name = params.extract_input<std::string>("Hit Distance");
+
+ const Array<std::string> hit_attribute_names = {
+ params.extract_input<std::string>("Target Attribute")};
+ const Array<std::string> hit_attribute_output_names = {
+ params.extract_input<std::string>("Hit Attribute")};
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ cast_geometry_set = bke::geometry_set_realize_instances(cast_geometry_set);
+
+ static const Array<GeometryComponentType> SupportedTypes = {
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+ for (GeometryComponentType geo_type : SupportedTypes) {
+ if (geometry_set.has(geo_type)) {
+ raycast_from_points(params,
+ cast_geometry_set,
+ geometry_set.get_component_for_write(geo_type),
+ hit_name,
+ hit_position_name,
+ hit_normal_name,
+ hit_distance_name,
+ hit_attribute_names,
+ hit_attribute_output_names);
+ }
+ }
+
+ params.set_output("Geometry", geometry_set);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_raycast()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_raycast_in, geo_node_raycast_out);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, geo_node_raycast_init);
+ node_type_update(&ntype, geo_node_raycast_update);
+ node_type_storage(
+ &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec;
+ ntype.draw_buttons = geo_node_raycast_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc
index 9bc963eec43..ee114741a77 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc
@@ -60,7 +60,7 @@ static void select_mesh_by_material(const Mesh &mesh,
material_indices.append(i);
}
}
- parallel_for(r_selection.index_range(), 1024, [&](IndexRange range) {
+ threading::parallel_for(r_selection.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
r_selection[i] = material_indices.contains(mesh.mpoly[i].mat_nr);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
new file mode 100644
index 00000000000..bdc3e56783c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_join_geometry_in[]{
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_join_geometry_out[]{
+ {SOCK_GEOMETRY, N_("Mesh")},
+ {SOCK_GEOMETRY, N_("Point Cloud")},
+ {SOCK_GEOMETRY, N_("Curve")},
+ {SOCK_GEOMETRY, N_("Volume")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void geo_node_separate_components_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ /* Note that it will be possible to skip realizing instances here when instancing
+ * geometry directly is supported by creating corresponding geometry instances. */
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ GeometrySet meshes;
+ GeometrySet point_clouds;
+ GeometrySet volumes;
+ GeometrySet curves;
+
+ if (geometry_set.has<MeshComponent>()) {
+ meshes.add(*geometry_set.get_component_for_read<MeshComponent>());
+ }
+ if (geometry_set.has<PointCloudComponent>()) {
+ point_clouds.add(*geometry_set.get_component_for_read<PointCloudComponent>());
+ }
+ if (geometry_set.has<CurveComponent>()) {
+ curves.add(*geometry_set.get_component_for_read<CurveComponent>());
+ }
+ if (geometry_set.has<VolumeComponent>()) {
+ volumes.add(*geometry_set.get_component_for_read<VolumeComponent>());
+ }
+
+ params.set_output("Mesh", meshes);
+ params.set_output("Point Cloud", point_clouds);
+ params.set_output("Curve", curves);
+ params.set_output("Volume", volumes);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_separate_components()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_join_geometry_in, geo_node_join_geometry_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index cfa790780f2..9a3eb574bcd 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -84,6 +84,16 @@ bool DerivedNodeTree::has_link_cycles() const
return false;
}
+bool DerivedNodeTree::has_undefined_nodes_or_sockets() const
+{
+ for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
+ if (tree_ref->has_undefined_nodes_or_sockets()) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 188d198e159..17a13f2d1b0 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -97,6 +97,12 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
+ if (found_socket->type == SOCK_INT) {
+ const int value = this->get_input<int>(found_socket->identifier);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
+ }
if (found_socket->type == SOCK_VECTOR) {
const float3 value = this->get_input<float3>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 8699736e543..154ee716153 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <mutex>
+
#include "NOD_node_tree_ref.hh"
#include "BLI_dot_export.hh"
@@ -105,6 +107,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
}
}
+ this->create_socket_identifier_maps();
this->create_linked_socket_caches();
for (NodeRef *node : nodes_by_id_) {
@@ -316,6 +319,89 @@ void OutputSocketRef::foreach_logical_target(
}
}
+namespace {
+struct SocketByIdentifierMap {
+ SocketIndexByIdentifierMap *map = nullptr;
+ std::unique_ptr<SocketIndexByIdentifierMap> owned_map;
+};
+} // namespace
+
+static std::unique_ptr<SocketIndexByIdentifierMap> create_identifier_map(const ListBase &sockets)
+{
+ std::unique_ptr<SocketIndexByIdentifierMap> map = std::make_unique<SocketIndexByIdentifierMap>();
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sockets, index) {
+ map->add_new(socket->identifier, index);
+ }
+ return map;
+}
+
+/* This function is not threadsafe. */
+static SocketByIdentifierMap get_or_create_identifier_map(
+ const bNode &node, const ListBase &sockets, const bNodeSocketTemplate *sockets_template)
+{
+ SocketByIdentifierMap map;
+ if (sockets_template == nullptr) {
+ if (BLI_listbase_is_empty(&sockets)) {
+ static SocketIndexByIdentifierMap empty_map;
+ map.map = &empty_map;
+ }
+ else if (node.type == NODE_REROUTE) {
+ if (&node.inputs == &sockets) {
+ static SocketIndexByIdentifierMap reroute_input_map = [] {
+ SocketIndexByIdentifierMap map;
+ map.add_new("Input", 0);
+ return map;
+ }();
+ map.map = &reroute_input_map;
+ }
+ else {
+ static SocketIndexByIdentifierMap reroute_output_map = [] {
+ SocketIndexByIdentifierMap map;
+ map.add_new("Output", 0);
+ return map;
+ }();
+ map.map = &reroute_output_map;
+ }
+ }
+ else {
+ /* The node has a dynamic amount of sockets. Therefore we need to create a new map. */
+ map.owned_map = create_identifier_map(sockets);
+ map.map = &*map.owned_map;
+ }
+ }
+ else {
+ /* Cache only one map for nodes that have the same sockets. */
+ static Map<const bNodeSocketTemplate *, std::unique_ptr<SocketIndexByIdentifierMap>> maps;
+ map.map = &*maps.lookup_or_add_cb(sockets_template,
+ [&]() { return create_identifier_map(sockets); });
+ }
+ return map;
+}
+
+void NodeTreeRef::create_socket_identifier_maps()
+{
+ /* `get_or_create_identifier_map` is not threadsafe, therefore we have to hold a lock here. */
+ static std::mutex mutex;
+ std::lock_guard lock{mutex};
+
+ for (NodeRef *node : nodes_by_id_) {
+ bNode &bnode = *node->bnode_;
+ SocketByIdentifierMap inputs_map = get_or_create_identifier_map(
+ bnode, bnode.inputs, bnode.typeinfo->inputs);
+ SocketByIdentifierMap outputs_map = get_or_create_identifier_map(
+ bnode, bnode.outputs, bnode.typeinfo->outputs);
+ node->input_index_by_identifier_ = inputs_map.map;
+ node->output_index_by_identifier_ = outputs_map.map;
+ if (inputs_map.owned_map) {
+ owned_identifier_maps_.append(std::move(inputs_map.owned_map));
+ }
+ if (outputs_map.owned_map) {
+ owned_identifier_maps_.append(std::move(outputs_map.owned_map));
+ }
+ }
+}
+
static bool has_link_cycles_recursive(const NodeRef &node,
MutableSpan<bool> visited,
MutableSpan<bool> is_in_stack)
@@ -358,6 +444,21 @@ bool NodeTreeRef::has_link_cycles() const
return false;
}
+bool NodeTreeRef::has_undefined_nodes_or_sockets() const
+{
+ for (const NodeRef *node : nodes_by_id_) {
+ if (node->is_undefined()) {
+ return true;
+ }
+ }
+ for (const SocketRef *socket : sockets_by_id_) {
+ if (socket->is_undefined()) {
+ return true;
+ }
+ }
+ return true;
+}
+
std::string NodeTreeRef::to_dot() const
{
dot::DirectedGraph digraph;
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
index 090c6216224..6baaa17f956 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
@@ -61,35 +61,60 @@ static void node_shader_exec_mix_rgb(void *UNUSED(data),
copy_v3_v3(out[0]->vec, col);
}
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case MA_RAMP_BLEND:
+ return "mix_blend";
+ case MA_RAMP_ADD:
+ return "mix_add";
+ case MA_RAMP_MULT:
+ return "mix_mult";
+ case MA_RAMP_SUB:
+ return "mix_sub";
+ case MA_RAMP_SCREEN:
+ return "mix_screen";
+ case MA_RAMP_DIV:
+ return "mix_div";
+ case MA_RAMP_DIFF:
+ return "mix_diff";
+ case MA_RAMP_DARK:
+ return "mix_dark";
+ case MA_RAMP_LIGHT:
+ return "mix_light";
+ case MA_RAMP_OVERLAY:
+ return "mix_overlay";
+ case MA_RAMP_DODGE:
+ return "mix_dodge";
+ case MA_RAMP_BURN:
+ return "mix_burn";
+ case MA_RAMP_HUE:
+ return "mix_hue";
+ case MA_RAMP_SAT:
+ return "mix_sat";
+ case MA_RAMP_VAL:
+ return "mix_val";
+ case MA_RAMP_COLOR:
+ return "mix_color";
+ case MA_RAMP_SOFT:
+ return "mix_soft";
+ case MA_RAMP_LINEAR:
+ return "mix_linear";
+ }
+
+ return nullptr;
+}
+
static int gpu_shader_mix_rgb(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- static const char *names[] = {
- "mix_blend",
- "mix_add",
- "mix_mult",
- "mix_sub",
- "mix_screen",
- "mix_div",
- "mix_diff",
- "mix_dark",
- "mix_light",
- "mix_overlay",
- "mix_dodge",
- "mix_burn",
- "mix_hue",
- "mix_sat",
- "mix_val",
- "mix_color",
- "mix_soft",
- "mix_linear",
- };
+ const char *name = gpu_shader_get_name(node->custom1);
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- int ret = GPU_stack_link(mat, node, names[node->custom1], in, out);
+ if (name != nullptr) {
+ int ret = GPU_stack_link(mat, node, name, in, out);
if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
const float min[3] = {0.0f, 0.0f, 0.0f};
const float max[3] = {1.0f, 1.0f, 1.0f};
@@ -109,7 +134,7 @@ void register_node_type_sh_mix_rgb(void)
sh_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_mix_rgb_in, sh_node_mix_rgb_out);
node_type_label(&ntype, node_blend_label);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_mix_rgb);
+ node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
node_type_gpu(&ntype, gpu_shader_mix_rgb);
nodeRegisterType(&ntype);
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 906f8ab702f..9cafb700430 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -147,10 +147,10 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args,
}
{
- extern void EDBM_update_generic(
+ extern void EDBM_update_extern(
struct Mesh * me, const bool do_tessface, const bool is_destructive);
- EDBM_update_generic(me, do_loop_triangles, is_destructive);
+ EDBM_update_extern(me, do_loop_triangles, is_destructive);
}
Py_RETURN_NONE;
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 638975f8fba..323661e7ca9 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1181,7 +1181,7 @@ PyDoc_STRVAR(
"\n"
" Custom-data layers are only copied from ``mesh`` on initialization.\n"
" Further calls will copy custom-data to matching layers, layers missing on the target "
- "mesh wont be added.\n");
+ "mesh won't be added.\n");
static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
static const char *kwlist[] = {"mesh", "face_normals", "use_shape_key", "shape_key_index", NULL};
@@ -2500,7 +2500,7 @@ PyDoc_STRVAR(
"\n"
" Running this on sequences besides :class:`BMesh.verts`, :class:`BMesh.edges`, "
":class:`BMesh.faces`\n"
- " works but wont result in each element having a valid index, instead its order in the "
+ " works but won't result in each element having a valid index, instead its order in the "
"sequence will be set.\n");
static PyObject *bpy_bmelemseq_index_update(BPy_BMElemSeq *self)
{
@@ -3020,8 +3020,8 @@ static struct PyMethodDef bpy_bmfaceseq_methods[] = {
static struct PyMethodDef bpy_bmloopseq_methods[] = {
/* odd function, initializes index values */
- /* no: index_update() function since we cant iterate over loops */
- /* no: sort() function since we cant iterate over loops */
+ /* no: index_update() function since we can't iterate over loops */
+ /* no: sort() function since we can't iterate over loops */
{NULL, NULL, 0, NULL},
};
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 9b6ca7fcec5..cebc72d99d1 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -91,7 +91,7 @@ static PyObject *idprop_py_from_idp_double(const IDProperty *prop)
static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *parent)
{
BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
- group->id = id;
+ group->owner_id = id;
group->prop = prop;
group->parent = parent; /* can be NULL */
return (PyObject *)group;
@@ -105,7 +105,7 @@ static PyObject *idprop_py_from_idp_id(IDProperty *prop)
static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
{
BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
- array->id = id;
+ array->owner_id = id;
array->prop = prop;
return (PyObject *)array;
}
@@ -152,7 +152,7 @@ static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
{
return PyUnicode_FromFormat("<bpy id prop: owner=\"%s\", name=\"%s\", address=%p>",
- self->id ? self->id->name : "<NONE>",
+ self->owner_id ? self->owner_id->name : "<NONE>",
self->prop->name,
self->prop);
}
@@ -326,7 +326,7 @@ static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
return NULL;
}
- return BPy_IDGroup_WrapData(self->id, idprop, self->prop);
+ return BPy_IDGroup_WrapData(self->owner_id, idprop, self->prop);
}
/* returns NULL on success, error string on failure */
@@ -946,7 +946,7 @@ static PyObject *BPy_Group_IterValues_next(BPy_IDGroup_Iter *self)
}
IDProperty *cur = self->cur;
self->cur = self->reversed ? self->cur->prev : self->cur->next;
- return BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop);
+ return BPy_IDGroup_WrapData(self->group->owner_id, cur, self->group->prop);
}
PyErr_SetNone(PyExc_StopIteration);
return NULL;
@@ -964,7 +964,7 @@ static PyObject *BPy_Group_IterItems_next(BPy_IDGroup_Iter *self)
PyObject *ret = PyTuple_New(2);
PyTuple_SET_ITEMS(ret,
PyUnicode_FromString(cur->name),
- BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
+ BPy_IDGroup_WrapData(self->group->owner_id, cur, self->group->prop));
return ret;
}
PyErr_SetNone(PyExc_StopIteration);
@@ -1514,7 +1514,7 @@ static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
idprop = IDP_GetPropertyFromGroup(self->prop, key);
if (idprop) {
- PyObject *pyobj = BPy_IDGroup_WrapData(self->id, idprop, self->prop);
+ PyObject *pyobj = BPy_IDGroup_WrapData(self->owner_id, idprop, self->prop);
if (pyobj) {
return pyobj;
}
diff --git a/source/blender/python/generic/idprop_py_api.h b/source/blender/python/generic/idprop_py_api.h
index 1e8e26a3b6d..f53c45b07c2 100644
--- a/source/blender/python/generic/idprop_py_api.h
+++ b/source/blender/python/generic/idprop_py_api.h
@@ -56,14 +56,14 @@ extern PyTypeObject BPy_IDGroup_IterItems_Type;
typedef struct BPy_IDProperty {
PyObject_VAR_HEAD
- struct ID *id; /* can be NULL */
+ struct ID *owner_id; /* can be NULL */
struct IDProperty *prop; /* must be second member */
struct IDProperty *parent;
} BPy_IDProperty;
typedef struct BPy_IDArray {
PyObject_VAR_HEAD
- struct ID *id; /* can be NULL */
+ struct ID *owner_id; /* can be NULL */
struct IDProperty *prop; /* must be second member */
} BPy_IDArray;
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
index 53e22314ec4..793b980295c 100644
--- a/source/blender/python/generic/imbuf_py_api.c
+++ b/source/blender/python/generic/imbuf_py_api.c
@@ -495,15 +495,16 @@ static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *
return Py_ImBuf_CreatePyObject(ibuf);
}
-PyDoc_STRVAR(M_imbuf_write_doc,
- ".. function:: write(image, filepath)\n"
- "\n"
- " Write an image.\n"
- "\n"
- " :arg image: the image to write.\n"
- " :type image: :class:`ImBuf`\n"
- " :arg filepath: the filepath of the image.\n"
- " :type filepath: string\n");
+PyDoc_STRVAR(
+ M_imbuf_write_doc,
+ ".. function:: write(image, filepath=image.filepath)\n"
+ "\n"
+ " Write an image.\n"
+ "\n"
+ " :arg image: the image to write.\n"
+ " :type image: :class:`ImBuf`\n"
+ " :arg filepath: Optional filepath of the image (fallback to the images file path).\n"
+ " :type filepath: string\n");
static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
Py_ImBuf *py_imb;
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 9824d5f17c4..127380feec1 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -523,7 +523,7 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
/**
* Similar to #PyErr_Format(),
*
- * Implementation - we cant actually prepend the existing exception,
+ * Implementation - we can't actually prepend the existing exception,
* because it could have _any_ arguments given to it, so instead we get its
* ``__str__`` output and raise our own exception including it.
*/
@@ -846,7 +846,7 @@ PyObject *PyC_DefaultNameSpace(const char *filename)
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if (filename) {
/* __file__ mainly for nice UI'ness
- * note: this wont map to a real file when executing text-blocks and buttons. */
+ * note: this won't map to a real file when executing text-blocks and buttons. */
PyModule_AddObject(mod_main, "__file__", PyC_UnicodeFromByte(filename));
}
PyModule_AddObject(mod_main, "__builtins__", builtins);
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index dc9b8b52821..30a61067c9e 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -403,7 +403,7 @@ void BPy_init_modules(struct bContext *C)
Py_DECREF(py_modpath);
}
else {
- printf("bpy: couldn't find 'scripts/modules', blender probably wont start.\n");
+ printf("bpy: couldn't find 'scripts/modules', blender probably won't start.\n");
}
/* stand alone utility modules not related to blender directly */
IDProp_Init_Types(); /* not actually a submodule, just types */
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 4de6063098b..a89d97bb40c 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -298,15 +298,6 @@ static int bpy_app_global_flag_set__only_disable(PyObject *UNUSED(self),
return bpy_app_global_flag_set(NULL, value, closure);
}
-PyDoc_STRVAR(bpy_app_binary_path_python_doc,
- "String, the path to the python executable (read-only). "
- "Deprecated! Use ``sys.executable`` instead.");
-static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure))
-{
- PyErr_Warn(PyExc_RuntimeWarning, "Use 'sys.executable' instead of 'binary_path_python'!");
- return Py_INCREF_RET(PySys_GetObject("executable"));
-}
-
PyDoc_STRVAR(bpy_app_debug_value_doc,
"Short, number which can be set to non-zero values for testing purposes");
static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(closure))
@@ -441,12 +432,6 @@ static PyGetSetDef bpy_app_getsets[] = {
bpy_app_global_flag_doc,
(void *)G_FLAG_USERPREF_NO_SAVE_ON_EXIT},
- {"binary_path_python",
- bpy_app_binary_path_python_get,
- NULL,
- bpy_app_binary_path_python_doc,
- NULL},
-
{"debug_value",
bpy_app_debug_value_get,
bpy_app_debug_value_set,
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index f95e655d0c6..8796877e9aa 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -154,8 +154,8 @@ void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
fprintf(stderr, "ERROR: Python context internal state bug. this should not happen!\n");
}
else if (py_call_level == 0) {
- /* XXX - Calling classes currently wont store the context :\,
- * cant set NULL because of this. but this is very flakey still. */
+ /* XXX - Calling classes currently won't store the context :\,
+ * can't set NULL because of this. but this is very flakey still. */
#if 0
BPY_context_set(NULL);
#endif
@@ -825,7 +825,7 @@ static void dealloc_obj_dealloc(PyObject *self)
{
bpy_module_delay_init(((dealloc_obj *)self)->mod);
- /* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */
+ /* Note, for subclassed PyObjects we can't just call PyObject_DEL() directly or it will crash */
dealloc_obj_Type.tp_free(self);
}
@@ -838,7 +838,7 @@ PyMODINIT_FUNC PyInit_bpy(void)
/* Problem:
* 1) this init function is expected to have a private member defined - 'md_def'
* but this is only set for C defined modules (not py packages)
- * so we cant return 'bpy_package_py' as is.
+ * so we can't return 'bpy_package_py' as is.
*
* 2) there is a 'bpy' C module for python to load which is basically all of blender,
* and there is scripts/bpy/__init__.py,
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 7a688b8c77d..5f97e11b412 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -258,7 +258,8 @@ static PyObject *bpy_lib_enter(BPy_Library *self)
BKE_reports_init(&reports, RPT_STORE);
- self->blo_handle = BLO_blendhandle_from_file(self->abspath, &reports);
+ self->blo_handle = BLO_blendhandle_from_file(self->abspath,
+ &(BlendFileReadReport){.reports = &reports});
if (self->blo_handle == NULL) {
if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) {
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 4a5e2552598..055dd624ea8 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -87,7 +87,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
bContext *C = BPY_context_get();
if (C == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
+ PyErr_SetString(PyExc_RuntimeError, "Context is None, can't poll any operators");
return NULL;
}
@@ -174,7 +174,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
bContext *C = BPY_context_get();
if (C == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
+ PyErr_SetString(PyExc_RuntimeError, "Context is None, can't poll any operators");
return NULL;
}
@@ -367,7 +367,7 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
if (C == NULL) {
PyErr_SetString(PyExc_RuntimeError,
- "Context is None, cant get the string representation of this object.");
+ "Context is None, can't get the string representation of this object.");
return NULL;
}
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 6ad80f9160b..0d451a8dd7f 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -210,7 +210,7 @@ static const EnumPropertyItem property_subtype_array_items[] = {
/**
* Store #PyObject data for a dynamically defined property.
* Currently this is only used to store call-back functions.
- * Properties that don't use custom-callbacks wont allocate this struct.
+ * Properties that don't use custom callbacks won't allocate this struct.
*
* Memory/Reference Management
* ---------------------------
@@ -2264,7 +2264,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
} \
(void)0
-/* terse macros for error checks shared between all funcs cant use function
+/* terse macros for error checks shared between all funcs can't use function
* calls because of static strings passed to pyrna_set_to_enum_bitfield */
#define BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items) \
if (UNLIKELY(id_len >= MAX_IDPROP_NAME)) { \
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index fb1cb823964..89fe907e57b 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1647,7 +1647,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr,
break;
}
- item = PyDict_GetItemString(kw, arg_name); /* Wont set an error. */
+ item = PyDict_GetItemString(kw, arg_name); /* Won't set an error. */
if (item == NULL) {
if (all_args) {
@@ -6224,7 +6224,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
err = -1;
break;
}
- /* PyDict_GetItemString wont raise an error. */
+ /* PyDict_GetItemString won't raise an error. */
continue;
}
@@ -7835,7 +7835,7 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e
BPy_StructRNA *py_srna = NULL;
StructRNA *srna;
- /* Unfortunately PyObject_GetAttrString wont look up this types tp_dict first :/ */
+ /* Unfortunately PyObject_GetAttrString won't look up this types tp_dict first :/ */
if (PyType_Check(self)) {
py_srna = (BPy_StructRNA *)PyDict_GetItem(((PyTypeObject *)self)->tp_dict,
bpy_intern_str_bl_rna);
@@ -8029,7 +8029,7 @@ static int pyrna_deferred_register_class_from_type_hints(StructRNA *srna, PyType
}
}
else {
- /* Should never happen, an error wont have been raised, so raise one. */
+ /* Should never happen, an error won't have been raised, so raise one. */
PyErr_Format(PyExc_TypeError,
"typing.get_type_hints returned: %.200s, expected dict\n",
Py_TYPE(annotations_dict)->tp_name);
@@ -8437,7 +8437,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
else if (py_srna == NULL) {
py_class_instance = NULL;
}
- else if (py_srna == Py_None) { /* Probably wont ever happen, but possible. */
+ else if (py_srna == Py_None) { /* Probably won't ever happen, but possible. */
Py_DECREF(py_srna);
py_class_instance = NULL;
}
@@ -8667,7 +8667,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
if (err != 0) {
ReportList *reports;
- /* Alert the user, else they wont know unless they see the console. */
+ /* Alert the user, else they won't know unless they see the console. */
if ((!is_staticmethod) && (!is_classmethod) && (ptr->data) &&
(RNA_struct_is_a(ptr->type, &RNA_Operator)) &&
(is_valid_wm == (CTX_wm_manager(C) != NULL))) {
@@ -8675,7 +8675,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
reports = op->reports;
}
else {
- /* Wont alert users, but they can view in 'info' space. */
+ /* Won't alert users, but they can view in 'info' space. */
reports = CTX_wm_reports(C);
}
diff --git a/source/blender/python/intern/bpy_rna_operator.c b/source/blender/python/intern/bpy_rna_operator.c
index 6e0db3eca49..490d9aa5212 100644
--- a/source/blender/python/intern/bpy_rna_operator.c
+++ b/source/blender/python/intern/bpy_rna_operator.c
@@ -31,6 +31,8 @@
#include "BPY_extern.h"
#include "bpy_capi_utils.h"
+#include "bpy_rna_operator.h" /* Own include. */
+
/* -------------------------------------------------------------------- */
/** \name Operator `poll_message_set` Method
* \{ */
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 1766c7dea66..c6d801aa733 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -2300,7 +2300,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
dot = dot_vn_vn(self->vec, self->vec, self->size);
if (!dot) {
- /* cant sqrt zero */
+ /* can't sqrt zero */
return 0;
}
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index 7352ac7b12e..6b2861bbefd 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -65,6 +65,7 @@ extern "C" {
#define RE_USE_STEREO_VIEWPORT 256
#define RE_USE_GPU_CONTEXT 512
#define RE_USE_CUSTOM_FREESTYLE 1024
+#define RE_USE_NO_IMAGE_SAVE 2048
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 7af6d3e234f..011bdb056d8 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -466,7 +466,16 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
triangles = MEM_callocN(sizeof(TriTessFace) * tottri, __func__);
- BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+ const float(*precomputed_normals)[3] = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ const bool calculate_normal = precomputed_normals ? false : true;
+
+ if (precomputed_normals != NULL) {
+ BKE_mesh_recalc_looptri_with_normals(
+ me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri, precomputed_normals);
+ }
+ else {
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+ }
if (tangent) {
BKE_mesh_ensure_normals_for_display(me_eval);
@@ -479,9 +488,6 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
loop_normals = CustomData_get_layer(&me_eval->ldata, CD_NORMAL);
}
- const float *precomputed_normals = CustomData_get_layer(&me->pdata, CD_NORMAL);
- const bool calculate_normal = precomputed_normals ? false : true;
-
for (i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
@@ -511,7 +517,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
copy_v3_v3(triangles[i].normal, no);
}
else {
- copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]);
+ copy_v3_v3(triangles[i].normal, precomputed_normals[lt->poly]);
}
}
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index a39214b609d..20f868ca86f 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -2215,35 +2215,42 @@ static int do_write_image_or_movie(Render *re,
RenderResult rres;
double render_time;
bool ok = true;
+ RenderEngineType *re_type = RE_engines_find(re->r.engine);
- RE_AcquireResultImageViews(re, &rres);
+ /* Only disable file writing if postprocessing is also disabled. */
+ const bool do_write_file = !(re_type->flag & RE_USE_NO_IMAGE_SAVE) ||
+ (re_type->flag & RE_USE_POSTPROCESS);
- /* write movie or image */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- RE_WriteRenderViewsMovie(
- re->reports, &rres, scene, &re->r, mh, re->movie_ctx_arr, totvideos, false);
- }
- else {
- if (name_override) {
- BLI_strncpy(name, name_override, sizeof(name));
+ if (do_write_file) {
+ RE_AcquireResultImageViews(re, &rres);
+
+ /* write movie or image */
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ RE_WriteRenderViewsMovie(
+ re->reports, &rres, scene, &re->r, mh, re->movie_ctx_arr, totvideos, false);
}
else {
- BKE_image_path_from_imformat(name,
- scene->r.pic,
- BKE_main_blendfile_path(bmain),
- scene->r.cfra,
- &scene->r.im_format,
- (scene->r.scemode & R_EXTENSION) != 0,
- true,
- NULL);
+ if (name_override) {
+ BLI_strncpy(name, name_override, sizeof(name));
+ }
+ else {
+ BKE_image_path_from_imformat(name,
+ scene->r.pic,
+ BKE_main_blendfile_path(bmain),
+ scene->r.cfra,
+ &scene->r.im_format,
+ (scene->r.scemode & R_EXTENSION) != 0,
+ true,
+ NULL);
+ }
+
+ /* write images as individual images or stereo */
+ ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name);
}
- /* write images as individual images or stereo */
- ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name);
+ RE_ReleaseResultImageViews(re, &rres);
}
- RE_ReleaseResultImageViews(re, &rres);
-
render_time = re->i.lastframetime;
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -2257,8 +2264,10 @@ static int do_write_image_or_movie(Render *re,
* Not sure it's actually even used anyway, we could as well pass NULL? */
render_callback_exec_null(re, G_MAIN, BKE_CB_EVT_RENDER_STATS);
- BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time);
- printf(" (Saving: %s)\n", name);
+ if (do_write_file) {
+ BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time);
+ printf(" (Saving: %s)\n", name);
+ }
fputc('\n', stdout);
fflush(stdout);
@@ -2330,9 +2339,15 @@ void RE_RenderAnim(Render *re,
return;
}
+ RenderEngineType *re_type = RE_engines_find(re->r.engine);
+
+ /* Only disable file writing if postprocessing is also disabled. */
+ const bool do_write_file = !(re_type->flag & RE_USE_NO_IMAGE_SAVE) ||
+ (re_type->flag & RE_USE_POSTPROCESS);
+
render_init_depsgraph(re);
- if (is_movie) {
+ if (is_movie && do_write_file) {
size_t width, height;
int i;
bool is_error = false;
@@ -2415,7 +2430,7 @@ void RE_RenderAnim(Render *re,
nfra += tfra;
/* Touch/NoOverwrite options are only valid for image's */
- if (is_movie == false) {
+ if (is_movie == false && do_write_file) {
if (rd.mode & (R_NO_OVERWRITE | R_TOUCH)) {
BKE_image_path_from_imformat(name,
rd.pic,
@@ -2508,7 +2523,7 @@ void RE_RenderAnim(Render *re,
if (G.is_break == true) {
/* remove touched file */
- if (is_movie == false) {
+ if (is_movie == false && do_write_file) {
if ((rd.mode & R_TOUCH)) {
if (!is_multiview_name) {
if ((BLI_file_size(name) == 0)) {
@@ -2548,7 +2563,7 @@ void RE_RenderAnim(Render *re,
}
/* end movie */
- if (is_movie) {
+ if (is_movie && do_write_file) {
re_movie_free_all(re, mh, totvideos);
}
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index 2b402b4750f..9340cfbf03d 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -79,6 +79,7 @@ set(SRC
intern/render.h
intern/sequencer.c
intern/sequencer.h
+ intern/sequence_lookup.c
intern/sound.c
intern/strip_add.c
intern/strip_edit.c
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index 2711e0a7ee3..6d043dffe72 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -58,6 +58,8 @@ bool SEQ_edit_remove_gaps(struct Scene *scene,
struct ListBase *seqbase,
const int initial_frame,
const bool remove_all_gaps);
+void SEQ_edit_sequence_name_set(struct Scene *scene, struct Sequence *seq, const char *new_name);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index ad0815892f7..fd4181a5a54 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -33,6 +33,7 @@ struct Editing;
struct Scene;
struct Sequence;
struct SequencerToolSettings;
+struct SequenceLookup;
/* RNA enums, just to be more readable */
enum {
@@ -79,6 +80,16 @@ void SEQ_sequence_base_dupli_recursive(const struct Scene *scene_src,
int dupe_flag,
const int flag);
+/* Defined in sequence_lookup.c */
+
+typedef enum eSequenceLookupTag {
+ SEQ_LOOKUP_TAG_INVALID = (1 << 0),
+} eSequenceLookupTag;
+
+struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key);
+void SEQ_sequence_lookup_free(const struct Scene *scene);
+void SEQ_sequence_lookup_tag(const struct Scene *scene, eSequenceLookupTag tag);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index 67d3a2e5960..593a8fe7bf2 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -46,6 +46,7 @@ void SEQ_time_update_sequence(struct Scene *scene, struct Sequence *seq);
void SEQ_time_update_sequence_bounds(struct Scene *scene, struct Sequence *seq);
int SEQ_time_cmp_time_startdisp(const void *a, const void *b);
bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, const int timeline_frame);
+void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index d587bd0f1a1..837a2de5742 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -30,6 +30,7 @@ extern "C" {
struct ListBase;
struct Scene;
struct Sequence;
+struct SeqCollection;
int SEQ_transform_get_left_handle_frame(struct Sequence *seq);
int SEQ_transform_get_right_handle_frame(struct Sequence *seq);
@@ -48,7 +49,8 @@ bool SEQ_transform_seqbase_shuffle_ex(struct ListBase *seqbasep,
bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
-bool SEQ_transform_seqbase_shuffle_time(struct ListBase *seqbasep,
+bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
+ struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
const bool use_sync_markers);
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index a4dc80d75db..432e8fdd0c0 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -36,7 +36,9 @@ struct Sequence;
struct StripElem;
void SEQ_sort(struct ListBase *seqbase);
-void SEQ_sequence_base_unique_name_recursive(struct ListBase *seqbasep, struct Sequence *seq);
+void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
+ struct ListBase *seqbasep,
+ struct Sequence *seq);
const char *SEQ_sequence_give_name(struct Sequence *seq);
struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset);
const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame);
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 73a9569fcd5..16adc392b3b 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -37,6 +37,7 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_rect.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
@@ -272,11 +273,11 @@ static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibl
/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself.
* Order of applying these conditions is important. */
-static bool must_render_strip(const Sequence *seq, SeqCollection *strips_under_playhead)
+static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_timeline_frame)
{
bool seq_have_effect_in_stack = false;
Sequence *seq_iter;
- SEQ_ITERATOR_FOREACH (seq_iter, strips_under_playhead) {
+ SEQ_ITERATOR_FOREACH (seq_iter, strips_at_timeline_frame) {
/* Strips is below another strip with replace blending are not rendered. */
if (seq_iter->blend_mode == SEQ_BLEND_REPLACE && seq->machine < seq_iter->machine) {
return false;
@@ -334,7 +335,7 @@ static void collection_filter_rendered_strips(SeqCollection *collection)
Sequence *seq;
/* Remove sound strips and muted strips from collection, because these are not rendered.
- * Function must_render_strip() don't have to check for these strips anymore. */
+ * Function #must_render_strip() don't have to check for these strips anymore. */
SEQ_ITERATOR_FOREACH (seq, collection) {
if (seq->type == SEQ_TYPE_SOUND_RAM || (seq->flag & SEQ_MUTE) != 0) {
SEQ_collection_remove_strip(seq, collection);
@@ -470,29 +471,6 @@ static bool seq_input_have_to_preprocess(const SeqRenderData *context,
return false;
}
-typedef struct ImageTransformThreadInitData {
- ImBuf *ibuf_source;
- ImBuf *ibuf_out;
- Sequence *seq;
- float preview_scale_factor;
- bool is_proxy_image;
- bool for_render;
-} ImageTransformThreadInitData;
-
-typedef struct ImageTransformThreadData {
- ImBuf *ibuf_source;
- ImBuf *ibuf_out;
- Sequence *seq;
- /* image_scale_factor is used to scale proxies to correct preview size. */
- float image_scale_factor;
- /* Preview scale factor is needed to correct translation to match preview size. */
- float preview_scale_factor;
- float crop_scale_factor;
- bool for_render;
- int start_line;
- int tot_line;
-} ImageTransformThreadData;
-
/**
* Effect, mask and scene in strip input strips are rendered in preview resolution.
* They are already down-scaled. #input_preprocess() does not expect this to happen.
@@ -512,49 +490,21 @@ static bool seq_need_scale_to_render_size(const Sequence *seq, bool is_proxy_ima
return false;
}
-static void sequencer_image_crop_transform_init(void *handle_v,
- int start_line,
- int tot_line,
- void *init_data_v)
-{
- ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v;
- const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v;
-
- handle->ibuf_source = init_data->ibuf_source;
- handle->ibuf_out = init_data->ibuf_out;
- handle->seq = init_data->seq;
-
- handle->preview_scale_factor = init_data->preview_scale_factor;
- if (seq_need_scale_to_render_size(init_data->seq, init_data->is_proxy_image)) {
- handle->image_scale_factor = 1.0f;
- }
- else {
- handle->image_scale_factor = handle->preview_scale_factor;
- }
-
- /* Proxy image is smaller, so crop values must be corrected by proxy scale factor.
- * Proxy scale factor always matches preview_scale_factor. */
- handle->crop_scale_factor = seq_need_scale_to_render_size(init_data->seq,
- init_data->is_proxy_image) ?
- init_data->preview_scale_factor :
- 1.0f;
-
- handle->for_render = init_data->for_render;
- handle->start_line = start_line;
- handle->tot_line = tot_line;
-}
-
-static void sequencer_image_crop_transform_matrix(const ImageTransformThreadData *data,
+static void sequencer_image_crop_transform_matrix(const Sequence *seq,
+ const ImBuf *in,
+ const ImBuf *out,
+ const float image_scale_factor,
+ const float preview_scale_factor,
float r_transform_matrix[3][3])
{
- const StripTransform *transform = data->seq->strip->transform;
- const float scale_x = transform->scale_x * data->image_scale_factor;
- const float scale_y = transform->scale_y * data->image_scale_factor;
- const float image_center_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2;
- const float image_center_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2;
- const float translate_x = transform->xofs * data->preview_scale_factor + image_center_offs_x;
- const float translate_y = transform->yofs * data->preview_scale_factor + image_center_offs_y;
- const float pivot[2] = {data->ibuf_source->x / 2, data->ibuf_source->y / 2};
+ const StripTransform *transform = seq->strip->transform;
+ const float scale_x = transform->scale_x * image_scale_factor;
+ const float scale_y = transform->scale_y * image_scale_factor;
+ const float image_center_offs_x = (out->x - in->x) / 2;
+ const float image_center_offs_y = (out->y - in->y) / 2;
+ const float translate_x = transform->xofs * preview_scale_factor + image_center_offs_x;
+ const float translate_y = transform->yofs * preview_scale_factor + image_center_offs_y;
+ const float pivot[2] = {in->x / 2, in->y / 2};
loc_rot_size_to_mat3(r_transform_matrix,
(const float[]){translate_x, translate_y},
transform->rotation,
@@ -563,108 +513,44 @@ static void sequencer_image_crop_transform_matrix(const ImageTransformThreadData
invert_m3(r_transform_matrix);
}
-static void sequencer_image_crop_transform_start_uv(const ImageTransformThreadData *data,
- const float transform_matrix[3][3],
- float r_start_uv[2])
+static void sequencer_image_crop_init(const Sequence *seq,
+ const ImBuf *in,
+ float crop_scale_factor,
+ rctf *r_crop)
{
- float orig[2];
- orig[0] = 0.0f;
- orig[1] = data->start_line;
- mul_v2_m3v2(r_start_uv, transform_matrix, orig);
-}
+ const StripCrop *c = seq->strip->crop;
+ const int left = c->left * crop_scale_factor;
+ const int right = c->right * crop_scale_factor;
+ const int top = c->top * crop_scale_factor;
+ const int bottom = c->bottom * crop_scale_factor;
-static void sequencer_image_crop_transform_uv_min(const float transform_matrix[3][3],
- float r_uv_min[2])
-{
- float orig[2];
- orig[0] = 0.0f;
- orig[1] = 0.0f;
- mul_v2_m3v2(r_uv_min, transform_matrix, orig);
+ BLI_rctf_init(r_crop, left, in->x - right, bottom, in->y - top);
}
-static void sequencer_image_crop_transform_delta_x(const ImageTransformThreadData *data,
- const float transform_matrix[3][3],
- const float uv_min[2],
- float r_add_x[2])
+static void sequencer_preprocess_transform_crop(
+ ImBuf *in, ImBuf *out, const SeqRenderData *context, Sequence *seq, const bool is_proxy_image)
{
- float uv_max_x[2];
- uv_max_x[0] = data->ibuf_out->x;
- uv_max_x[1] = 0.0f;
- mul_v2_m3v2(r_add_x, transform_matrix, uv_max_x);
- sub_v2_v2(r_add_x, uv_min);
- mul_v2_fl(r_add_x, 1.0f / data->ibuf_out->x);
-}
+ const Scene *scene = context->scene;
+ const float preview_scale_factor = context->preview_render_size == SEQ_RENDER_SIZE_SCENE ?
+ (float)scene->r.size / 100 :
+ SEQ_rendersize_to_scale_factor(
+ context->preview_render_size);
+ const bool do_scale_to_render_size = seq_need_scale_to_render_size(seq, is_proxy_image);
+ const float image_scale_factor = do_scale_to_render_size ? 1.0f : preview_scale_factor;
-static void sequencer_image_crop_transform_delta_y(const ImageTransformThreadData *data,
- const float transform_matrix[3][3],
- const float uv_min[2],
- float r_add_y[2])
-{
- float uv_max_y[2];
- uv_max_y[0] = 0.0f;
- uv_max_y[1] = data->ibuf_out->y;
- mul_v2_m3v2(r_add_y, transform_matrix, uv_max_y);
- sub_v2_v2(r_add_y, uv_min);
- mul_v2_fl(r_add_y, 1.0f / data->ibuf_out->y);
-}
-
-static void sequencer_image_crop_transform_interpolation_coefs(
- const ImageTransformThreadData *data, float r_start_uv[2], float r_add_x[2], float r_add_y[2])
-{
float transform_matrix[3][3];
- sequencer_image_crop_transform_matrix(data, transform_matrix);
- sequencer_image_crop_transform_start_uv(data, transform_matrix, r_start_uv);
- float uv_min[2];
- sequencer_image_crop_transform_uv_min(transform_matrix, uv_min);
- sequencer_image_crop_transform_delta_x(data, transform_matrix, uv_min, r_add_x);
- sequencer_image_crop_transform_delta_y(data, transform_matrix, uv_min, r_add_y);
-}
+ sequencer_image_crop_transform_matrix(
+ seq, in, out, image_scale_factor, preview_scale_factor, transform_matrix);
-static void *sequencer_image_crop_transform_do_thread(void *data_v)
-{
- const ImageTransformThreadData *data = data_v;
-
- float last_uv[2];
- float add_x[2];
- float add_y[2];
- sequencer_image_crop_transform_interpolation_coefs(data_v, last_uv, add_x, add_y);
-
- /* Image crop is done by offsetting image boundary limits. */
- const StripCrop *c = data->seq->strip->crop;
- const int left = c->left * data->crop_scale_factor;
- const int right = c->right * data->crop_scale_factor;
- const int top = c->top * data->crop_scale_factor;
- const int bottom = c->bottom * data->crop_scale_factor;
-
- const float source_pixel_range_max[2] = {data->ibuf_source->x - right,
- data->ibuf_source->y - top};
- const float source_pixel_range_min[2] = {left, bottom};
-
- const int width = data->ibuf_out->x;
-
- float uv[2];
- for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) {
- copy_v2_v2(uv, last_uv);
- add_v2_v2(last_uv, add_y);
- for (int xi = 0; xi < width; xi++) {
- if (source_pixel_range_min[0] >= uv[0] || uv[0] >= source_pixel_range_max[0] ||
- source_pixel_range_min[1] >= uv[1] || uv[1] >= source_pixel_range_max[1]) {
- add_v2_v2(uv, add_x);
- continue;
- }
-
- if (data->for_render) {
- bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
- }
- else {
- nearest_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
- }
-
- add_v2_v2(uv, add_x);
- }
- }
+ /* Proxy image is smaller, so crop values must be corrected by proxy scale factor.
+ * Proxy scale factor always matches preview_scale_factor. */
+ rctf source_crop;
+ const float crop_scale_factor = do_scale_to_render_size ? preview_scale_factor : 1.0f;
+ sequencer_image_crop_init(seq, in, crop_scale_factor, &source_crop);
- return NULL;
+ const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR :
+ IMB_FILTER_NEAREST;
+ IMB_transform(in, out, transform_matrix, &source_crop, filter);
}
static void multibuf(ImBuf *ibuf, const float fmul)
@@ -726,27 +612,8 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
const int y = context->recty;
preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
- ImageTransformThreadInitData init_data = {NULL};
- init_data.ibuf_source = ibuf;
- init_data.ibuf_out = preprocessed_ibuf;
- init_data.seq = seq;
- init_data.is_proxy_image = is_proxy_image;
-
- /* Get scale factor if preview resolution doesn't match project resolution. */
- if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
- init_data.preview_scale_factor = (float)scene->r.size / 100;
- }
- else {
- init_data.preview_scale_factor = SEQ_rendersize_to_scale_factor(
- context->preview_render_size);
- }
+ sequencer_preprocess_transform_crop(ibuf, preprocessed_ibuf, context, seq, is_proxy_image);
- init_data.for_render = context->for_render;
- IMB_processor_apply_threaded(context->recty,
- sizeof(ImageTransformThreadData),
- &init_data,
- sequencer_image_crop_transform_init,
- sequencer_image_crop_transform_do_thread);
seq_imbuf_assign_spaces(scene, preprocessed_ibuf);
IMB_metadata_copy(preprocessed_ibuf, ibuf);
IMB_freeImBuf(ibuf);
diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c
new file mode 100644
index 00000000000..72567dc394e
--- /dev/null
+++ b/source/blender/sequencer/intern/sequence_lookup.c
@@ -0,0 +1,161 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#include "SEQ_sequencer.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "SEQ_iterator.h"
+
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+#include "BLI_sys_types.h"
+#include "BLI_threads.h"
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+static ThreadMutex lookup_lock = BLI_MUTEX_INITIALIZER;
+
+typedef struct SequenceLookup {
+ GHash *by_name;
+ eSequenceLookupTag tag;
+} SequenceLookup;
+
+static void seq_sequence_lookup_init(struct SequenceLookup *lookup)
+{
+ lookup->by_name = BLI_ghash_str_new(__func__);
+ lookup->tag |= SEQ_LOOKUP_TAG_INVALID;
+}
+
+static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup)
+{
+ SeqCollection *all_strips = SEQ_query_all_strips_recursive(&scene->ed->seqbase);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, all_strips) {
+ BLI_ghash_insert(lookup->by_name, seq->name + 2, seq);
+ }
+ SEQ_collection_free(all_strips);
+ lookup->tag &= ~SEQ_LOOKUP_TAG_INVALID;
+}
+
+static SequenceLookup *seq_sequence_lookup_new(void)
+{
+ SequenceLookup *lookup = MEM_callocN(sizeof(SequenceLookup), __func__);
+ seq_sequence_lookup_init(lookup);
+ return lookup;
+}
+
+static void seq_sequence_lookup_free(struct SequenceLookup **lookup)
+{
+ if (*lookup == NULL) {
+ return;
+ }
+
+ BLI_ghash_free((*lookup)->by_name, NULL, NULL);
+ (*lookup)->by_name = NULL;
+ MEM_freeN(*lookup);
+ *lookup = NULL;
+}
+
+static void seq_sequence_lookup_rebuild(const struct Scene *scene, struct SequenceLookup **lookup)
+{
+ seq_sequence_lookup_free(lookup);
+ *lookup = seq_sequence_lookup_new();
+ seq_sequence_lookup_build(scene, *lookup);
+}
+
+static bool seq_sequence_lookup_is_valid(struct SequenceLookup *lookup)
+{
+ return (lookup->tag & SEQ_LOOKUP_TAG_INVALID) == 0;
+}
+
+static void seq_sequence_lookup_update_if_needed(const struct Scene *scene,
+ struct SequenceLookup **lookup)
+{
+ if (!scene->ed) {
+ return;
+ }
+ if (*lookup && seq_sequence_lookup_is_valid(*lookup)) {
+ return;
+ }
+
+ seq_sequence_lookup_rebuild(scene, lookup);
+}
+
+/**
+ * Free lookup hash data.
+ *
+ * \param scene: scene that owns lookup hash
+ */
+void SEQ_sequence_lookup_free(const Scene *scene)
+{
+ BLI_assert(scene->ed);
+ BLI_mutex_lock(&lookup_lock);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ seq_sequence_lookup_free(&lookup);
+ BLI_mutex_unlock(&lookup_lock);
+}
+
+/**
+ * Find a sequence with a given name.
+ * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
+ * rebuilt.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param key: Sequence name without SQ prefix (seq->name + 2)
+ *
+ * \return pointer to Sequence
+ */
+Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
+{
+ BLI_assert(scene->ed);
+ BLI_mutex_lock(&lookup_lock);
+ seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ Sequence *seq = BLI_ghash_lookup(lookup->by_name, key);
+ BLI_mutex_unlock(&lookup_lock);
+ return seq;
+}
+
+/**
+ * Find a sequence with a given name.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param tag: tag to set
+ */
+void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag)
+{
+ if (!scene->ed) {
+ return;
+ }
+
+ BLI_mutex_lock(&lookup_lock);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ if (lookup != NULL) {
+ lookup->tag |= tag;
+ }
+ BLI_mutex_unlock(&lookup_lock);
+}
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index d0bc41062a1..8cd67195c30 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -271,6 +271,7 @@ void SEQ_editing_free(Scene *scene, const bool do_id_user)
SEQ_ALL_END;
BLI_freelistN(&ed->metastack);
+ SEQ_sequence_lookup_free(scene);
MEM_freeN(ed);
scene->ed = NULL;
@@ -514,7 +515,7 @@ static Sequence *seq_dupli(const Scene *scene_src,
if (scene_src == scene_dst) {
if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) {
- SEQ_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn);
+ SEQ_sequence_base_unique_name_recursive(scene_dst, &scene_dst->ed->seqbase, seqn);
}
}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 9e5afb45f2a..142991eeacf 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -56,6 +56,7 @@
#include "IMB_metadata.h"
#include "SEQ_add.h"
+#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -98,33 +99,32 @@ void SEQ_add_load_data_init(SeqLoadData *load_data,
static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq)
{
- SEQ_sequence_base_unique_name_recursive(seqbase, seq);
+ SEQ_sequence_base_unique_name_recursive(scene, seqbase, seq);
SEQ_time_update_sequence_bounds(scene, seq);
SEQ_sort(seqbase);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
-static void seq_add_set_name(Sequence *seq, SeqLoadData *load_data)
+static void seq_add_set_name(Scene *scene, Sequence *seq, SeqLoadData *load_data)
{
if (load_data->name[0] != '\0') {
- BLI_strncpy(seq->name + 2, load_data->name, sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, load_data->name);
}
else {
if (seq->type == SEQ_TYPE_SCENE) {
- BLI_strncpy(seq->name + 2, load_data->scene->id.name + 2, sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, load_data->scene->id.name + 2);
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
- BLI_strncpy(seq->name + 2, load_data->clip->id.name + 2, sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, load_data->clip->id.name + 2);
}
else if (seq->type == SEQ_TYPE_MASK) {
- BLI_strncpy(seq->name + 2, load_data->mask->id.name + 2, sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, load_data->mask->id.name + 2);
}
else if ((seq->type & SEQ_TYPE_EFFECT) != 0) {
- BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, SEQ_sequence_give_name(seq));
}
else { /* Image, sound and movie. */
- BLI_strncpy_utf8(seq->name + 2, load_data->name, sizeof(seq->name) - 2);
- BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
+ SEQ_edit_sequence_name_set(scene, seq, load_data->name);
}
}
}
@@ -163,7 +163,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
seq->scene = load_data->scene;
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
@@ -184,7 +184,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
seq->clip = load_data->clip;
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
@@ -205,7 +205,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
seq->mask = load_data->mask;
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
@@ -249,7 +249,7 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
}
SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
@@ -364,7 +364,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
/* Set Last active directory. */
BLI_strncpy(scene->ed->act_imagedir, seq->strip->dir, sizeof(scene->ed->act_imagedir));
seq_add_set_view_transform(scene, seq, load_data);
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
@@ -409,7 +409,7 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
Strip *strip = seq->strip;
/* We only need 1 element to store the filename. */
- StripElem *se = strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
+ StripElem *se = strip->stripdata = MEM_callocN(sizeof(StripElem), "stripelem");
BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
if (seq != NULL && seq->sound != NULL) {
@@ -426,7 +426,7 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
/* Set Last active directory. */
BLI_strncpy(scene->ed->act_sounddir, strip->dir, FILE_MAXDIR);
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
@@ -458,7 +458,7 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_META);
/* Set name. */
- seq_add_set_name(seqm, load_data);
+ seq_add_set_name(scene, seqm, load_data);
/* Set frames start and length. */
seqm->start = load_data->start_frame;
@@ -590,7 +590,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
seq_add_set_view_transform(scene, seq, load_data);
- seq_add_set_name(seq, load_data);
+ seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
MEM_freeN(anim_arr);
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 4de6ec3583c..3e6eb74fcb3 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -30,6 +30,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
+#include "BLI_string_utf8.h"
#include "BLT_translation.h"
@@ -202,6 +203,7 @@ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
}
BLI_remlink(seqbase, seq);
SEQ_sequence_free(scene, seq, true);
+ SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
}
}
}
@@ -468,3 +470,10 @@ bool SEQ_edit_remove_gaps(Scene *scene,
}
return true;
}
+
+void SEQ_edit_sequence_name_set(Scene *scene, Sequence *seq, const char *new_name)
+{
+ BLI_strncpy_utf8(seq->name + 2, new_name, MAX_NAME - 2);
+ BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
+ SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
+}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index b8b6f62c7aa..ecec317ed25 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -184,7 +184,7 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
seq_update_sound_bounds_recursive(scene, seq_meta);
}
-static void seq_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
+void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
{
seq_time_update_meta_strip(scene, seq_meta);
@@ -223,7 +223,7 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
seq->start = seq->startdisp = seq->seq1->startdisp;
seq->enddisp = seq->seq1->enddisp;
}
- /* we cant help if strips don't overlap, it wont give useful results.
+ /* we can't help if strips don't overlap, it won't give useful results.
* but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
if (seq->enddisp < seq->startdisp) {
/* simple start/end swap */
@@ -250,7 +250,7 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
Editing *ed = SEQ_editing_get(scene, false);
MetaStack *ms = SEQ_meta_stack_active_get(ed);
if (ms != NULL) {
- seq_time_update_meta_strip_range(scene, ms->parseq);
+ SEQ_time_update_meta_strip_range(scene, ms->parseq);
}
SEQ_time_update_sequence_bounds(scene, seq);
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index a02d8a1428e..20cbe933b2f 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -34,6 +34,7 @@
#include "BKE_sound.h"
#include "SEQ_effects.h"
+#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@@ -134,7 +135,7 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
/**
* Use to impose limits when dragging/extending - so impossible situations don't happen.
- * Cant use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
+ * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
*/
void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
{
@@ -233,14 +234,22 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
SEQ_offset_animdata(evil_scene, seq, delta);
seq->start += delta;
+ /* Meta strips requires special handling: their content is to be translated, and then frame range
+ * of the meta is to be updated for the updated content. */
if (seq->type == SEQ_TYPE_META) {
Sequence *seq_child;
for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
SEQ_transform_translate_sequence(evil_scene, seq_child, delta);
}
+ /* Ensure that meta bounds are updated, but this function prevents resets seq->start and
+ * start/end point in timeline. */
+ SEQ_time_update_meta_strip_range(evil_scene, seq);
+ /* Move meta start/end points. */
+ SEQ_transform_set_left_handle_frame(seq, seq->startdisp + delta);
+ SEQ_transform_set_right_handle_frame(seq, seq->enddisp + delta);
}
- SEQ_time_update_sequence_bounds(evil_scene, seq);
+ SEQ_time_update_sequence(evil_scene, seq);
}
/* return 0 if there weren't enough space */
@@ -294,73 +303,69 @@ bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *ev
return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1);
}
-static int shuffle_seq_time_offset_test(ListBase *seqbasep, char dir)
+static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
+ ListBase *seqbasep,
+ char dir)
{
int offset = 0;
- Sequence *seq, *seq_other;
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- for (seq_other = seqbasep->first; seq_other; seq_other = seq_other->next) {
- if (!seq_other->tmp && seq_overlap(seq, seq_other)) {
- if (dir == 'L') {
- offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
- }
- else {
- offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
- }
- }
+ Sequence *seq;
+
+ SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
+ LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
+ if (!seq_overlap(seq, seq_other)) {
+ continue;
+ }
+ if (dir == 'L') {
+ offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
+ }
+ else {
+ offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
}
}
}
return offset;
}
-static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir)
+static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle,
+ ListBase *seqbasep,
+ Scene *scene,
+ char dir)
{
int ofs = 0;
int tot_ofs = 0;
Sequence *seq;
- while ((ofs = shuffle_seq_time_offset_test(seqbasep, dir))) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- /* seq_test_overlap only tests display values */
- seq->startdisp += ofs;
- seq->enddisp += ofs;
- }
+ while ((ofs = shuffle_seq_time_offset_test(strips_to_shuffle, seqbasep, dir))) {
+ SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
+ /* seq_test_overlap only tests display values */
+ seq->startdisp += ofs;
+ seq->enddisp += ofs;
}
tot_ofs += ofs;
}
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */
- }
+ SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
+ SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */
}
return tot_ofs;
}
-bool SEQ_transform_seqbase_shuffle_time(ListBase *seqbasep,
+bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
+ ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
const bool use_sync_markers)
{
- /* note: seq->tmp is used to tag strips to move */
-
- Sequence *seq;
-
- int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
- int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
+ int offset_l = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'L');
+ int offset_r = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'R');
int offset = (-offset_l < offset_r) ? offset_l : offset_r;
if (offset) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- SEQ_transform_translate_sequence(evil_scene, seq, offset);
- seq->flag &= ~SEQ_OVERLAP;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
+ SEQ_transform_translate_sequence(evil_scene, seq, offset);
+ seq->flag &= ~SEQ_OVERLAP;
}
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 9aeb2961751..a287466dfb2 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -39,6 +39,7 @@
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "SEQ_edit.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_select.h"
@@ -140,7 +141,9 @@ static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
return 1;
}
-void SEQ_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
+void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
+ ListBase *seqbasep,
+ Sequence *seq)
{
SeqUniqueInfo sui;
char *dot;
@@ -167,7 +170,7 @@ void SEQ_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
SEQ_seqbase_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui);
}
- BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
+ SEQ_edit_sequence_name_set(scene, seq, sui.name_dest);
}
static const char *give_seqname_by_type(int type)
@@ -629,7 +632,7 @@ void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
char name[SEQ_NAME_MAXSTR];
BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
- SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+ SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
SEQ_dupe_animdata(scene, name, seq->name + 2);
if (seq->type == SEQ_TYPE_META) {
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index edd5b555e2f..f3c4cb93e7d 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -190,6 +190,7 @@ struct wmWindow *WM_window_open(struct bContext *C,
int sizex,
int sizey,
int space_type,
+ bool toplevel,
bool dialog,
bool temp,
WindowAlignment alignment);
@@ -205,6 +206,13 @@ void WM_autosave_init(struct wmWindowManager *wm);
bool WM_recover_last_session(struct bContext *C, struct ReportList *reports);
void WM_file_tag_modified(void);
+struct ID *WM_file_link_datablock(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct View3D *v3d,
+ const char *filepath,
+ const short id_code,
+ const char *id_name);
struct ID *WM_file_append_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -991,9 +999,9 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
unsigned int count_interaction_paths,
const char **interaction_paths);
-bool WM_xr_active_action_set_set(
- wmXrData *xr, const char *action_set_name); /* If action_set_name is NULL, then
- * all action sets will be treated as active. */
+/* If action_set_name is NULL, then all action sets will be treated as active. */
+bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
+
bool WM_xr_controller_pose_action_set(wmXrData *xr,
const char *action_set_name,
const char *action_name);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 168b775d16d..0b26f3c54ae 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -920,6 +920,7 @@ typedef struct wmDragAsset {
/* Always freed. */
const char *path;
int id_type;
+ int import_type; /* eFileAssetImportType */
} wmDragAsset;
typedef struct wmDrag {
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
index fd7f9c2de7c..db18ceb0e7f 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -341,7 +341,7 @@ typedef struct wmGizmoType {
const char *idname; /* MAX_NAME */
/** Set to 'sizeof(wmGizmo)' or larger for instances of this type,
- * use so we can cant to other types without the hassle of a custom-data pointer. */
+ * use so we can cast to other types without the hassle of a custom-data pointer. */
uint struct_size;
/** Initialize struct (calloc'd 'struct_size' region). */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index 7cb1a0bdf4b..63e833d73c3 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -312,9 +312,10 @@ void WM_gizmo_do_msg_notify_tag_refresh(bContext *UNUSED(C),
ARegion *region = msg_val->owner;
wmGizmoMap *gzmap = msg_val->user_data;
- ED_region_tag_redraw(
- region); /* Could possibly avoid a full redraw and only tag for editor overlays
- * redraw in some cases, see #ED_region_tag_redraw_editor_overlays(). */
+ /* Could possibly avoid a full redraw and only tag for editor overlays
+ * redraw in some cases, see #ED_region_tag_redraw_editor_overlays(). */
+ ED_region_tag_redraw(region);
+
WM_gizmomap_tag_refresh(gzmap);
}
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index b7a16b6c5ee..e899cbb22b9 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "MEM_guardedalloc.h"
@@ -153,7 +154,7 @@ wmDrag *WM_event_start_drag(
switch (type) {
case WM_DRAG_PATH:
BLI_strncpy(drag->path, poin, FILE_MAX);
- /* As the path is being copied, free it immediately as `drag` wont "own" the data. */
+ /* As the path is being copied, free it immediately as `drag` won't "own" the data. */
if (flags & WM_DRAG_FREE_DATA) {
MEM_freeN(poin);
}
@@ -377,9 +378,17 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
{
- /* Append only for now, wmDragAsset could have a `link` bool. */
- return WM_file_append_datablock(
- G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name);
+ switch ((eFileAssetImportType)asset_drag->import_type) {
+ case FILE_ASSET_IMPORT_LINK:
+ return WM_file_link_datablock(
+ G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name);
+ case FILE_ASSET_IMPORT_APPEND:
+ return WM_file_append_datablock(
+ G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name);
+ }
+
+ BLI_assert_unreachable();
+ return NULL;
}
/**
@@ -509,7 +518,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
rect->ymin = rect->ymax = cursory;
}
- /* Should we support multi-line drag draws? Maybe not, more types mixed wont work well. */
+ /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */
GPU_blend(GPU_BLEND_ALPHA);
LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
const uchar text_col[] = {255, 255, 255, 255};
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index a6588c40f0f..750b4e5e60d 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -380,8 +380,7 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
*/
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
if (is_after_open_file) {
- DEG_graph_relations_update(depsgraph);
- DEG_graph_on_visible_update(bmain, depsgraph, true);
+ DEG_graph_tag_on_visible_update(depsgraph, true);
}
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);
@@ -520,7 +519,7 @@ void wm_event_do_notifiers(bContext *C)
if (clear_info_stats) {
/* Only do once since adding notifiers is slow when there are many. */
ViewLayer *view_layer = CTX_data_view_layer(C);
- ED_info_stats_clear(view_layer);
+ ED_info_stats_clear(wm, view_layer);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index d0ee7075516..d165f8c37d5 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -52,12 +52,15 @@
#include "BLI_blenlib.h"
#include "BLI_fileops_types.h"
#include "BLI_linklist.h"
+#include "BLI_math.h"
#include "BLI_system.h"
#include "BLI_threads.h"
#include "BLI_timer.h"
#include "BLI_utildefines.h"
#include BLI_SYSTEM_PID_H
+#include "PIL_time.h"
+
#include "BLT_translation.h"
#include "BLF_api.h"
@@ -733,6 +736,97 @@ static void wm_file_read_post(bContext *C,
/** \name Read Main Blend-File API
* \{ */
+static void file_read_reports_finalize(BlendFileReadReport *bf_reports)
+{
+ double duration_whole_minutes, duration_whole_seconds;
+ double duration_libraries_minutes, duration_libraries_seconds;
+ double duration_lib_override_minutes, duration_lib_override_seconds;
+ double duration_lib_override_resync_minutes, duration_lib_override_resync_seconds;
+ double duration_lib_override_recursive_resync_minutes,
+ duration_lib_override_recursive_resync_seconds;
+
+ BLI_math_time_seconds_decompose(bf_reports->duration.whole,
+ NULL,
+ NULL,
+ &duration_whole_minutes,
+ &duration_whole_seconds,
+ NULL);
+ BLI_math_time_seconds_decompose(bf_reports->duration.libraries,
+ NULL,
+ NULL,
+ &duration_libraries_minutes,
+ &duration_libraries_seconds,
+ NULL);
+ BLI_math_time_seconds_decompose(bf_reports->duration.lib_overrides,
+ NULL,
+ NULL,
+ &duration_lib_override_minutes,
+ &duration_lib_override_seconds,
+ NULL);
+ BLI_math_time_seconds_decompose(bf_reports->duration.lib_overrides_resync,
+ NULL,
+ NULL,
+ &duration_lib_override_resync_minutes,
+ &duration_lib_override_resync_seconds,
+ NULL);
+ BLI_math_time_seconds_decompose(bf_reports->duration.lib_overrides_recursive_resync,
+ NULL,
+ NULL,
+ &duration_lib_override_recursive_resync_minutes,
+ &duration_lib_override_recursive_resync_seconds,
+ NULL);
+
+ CLOG_INFO(
+ &LOG, 0, "Blender file read in %.0fm%.2fs", duration_whole_minutes, duration_whole_seconds);
+ CLOG_INFO(&LOG,
+ 0,
+ " * Loading libraries: %.0fm%.2fs",
+ duration_libraries_minutes,
+ duration_libraries_seconds);
+ CLOG_INFO(&LOG,
+ 0,
+ " * Applying overrides: %.0fm%.2fs",
+ duration_lib_override_minutes,
+ duration_lib_override_seconds);
+ CLOG_INFO(&LOG,
+ 0,
+ " * Resyncing overrides: %.0fm%.2fs (%d root overrides), including recursive "
+ "resyncs: %.0fm%.2fs)",
+ duration_lib_override_resync_minutes,
+ duration_lib_override_resync_seconds,
+ bf_reports->count.resynced_lib_overrides,
+ duration_lib_override_recursive_resync_minutes,
+ duration_lib_override_recursive_resync_seconds);
+ if (bf_reports->resynced_lib_overrides_libraries_count != 0) {
+ for (LinkNode *node_lib = bf_reports->resynced_lib_overrides_libraries; node_lib != NULL;
+ node_lib = node_lib->next) {
+ Library *library = node_lib->link;
+ BKE_reportf(
+ bf_reports->reports, RPT_INFO, "Library %s needs overrides resync.", library->filepath);
+ }
+ }
+ if (bf_reports->count.missing_libraries != 0 || bf_reports->count.missing_linked_id != 0) {
+ BKE_reportf(bf_reports->reports,
+ RPT_WARNING,
+ "%d libraries and %d linked data-blocks are missing, please check the "
+ "Info and Outliner editors for details",
+ bf_reports->count.missing_libraries,
+ bf_reports->count.missing_linked_id);
+ }
+ if (bf_reports->resynced_lib_overrides_libraries_count != 0) {
+ BKE_reportf(bf_reports->reports,
+ RPT_WARNING,
+ "%d libraries have overrides needing resync (auto resynced in %.0fm%.2fs), "
+ "please check the Info editor for details",
+ bf_reports->resynced_lib_overrides_libraries_count,
+ duration_lib_override_recursive_resync_minutes,
+ duration_lib_override_recursive_resync_seconds);
+ }
+
+ BLI_linklist_free(bf_reports->resynced_lib_overrides_libraries, NULL);
+ bf_reports->resynced_lib_overrides_libraries = NULL;
+}
+
bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
{
/* assume automated tasks with background, don't write recent file list */
@@ -763,7 +857,9 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
.skip_flags = BLO_READ_SKIP_USERDEF,
};
- struct BlendFileData *bfd = BKE_blendfile_read(filepath, &params, reports);
+ BlendFileReadReport bf_reports = {.reports = reports,
+ .duration.whole = PIL_check_seconds_timer()};
+ struct BlendFileData *bfd = BKE_blendfile_read(filepath, &params, &bf_reports);
if (bfd != NULL) {
wm_file_read_pre(C, use_data, use_userdef);
@@ -773,10 +869,10 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
wm_window_match_init(C, &wmbase);
/* This flag is initialized by the operator but overwritten on read.
- * need to re-enable it here else drivers + registered scripts wont work. */
+ * need to re-enable it here else drivers and registered scripts won't work. */
const int G_f_orig = G.f;
- BKE_blendfile_read_setup(C, bfd, &params, reports);
+ BKE_blendfile_read_setup(C, bfd, &params, &bf_reports);
if (G.f != G_f_orig) {
const int flags_keep = G_FLAG_ALL_RUNTIME;
@@ -807,6 +903,9 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
wm_file_read_post(C, false, false, use_data, use_userdef, false);
+ bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole;
+ file_read_reports_finalize(&bf_reports);
+
success = true;
}
}
@@ -911,7 +1010,10 @@ void wm_homefile_read(bContext *C,
const char *app_template_override,
bool *r_is_factory_startup)
{
- Main *bmain = G_MAIN; /* Context does not always have valid main pointer here... */
+#if 0 /* UNUSED, keep as this may be needed later & the comment below isn't self evident. */
+ /* Context does not always have valid main pointer here. */
+ Main *bmain = G_MAIN;
+#endif
ListBase wmbase;
bool success = false;
@@ -1084,10 +1186,15 @@ void wm_homefile_read(bContext *C,
.skip_flags = skip_flags | BLO_READ_SKIP_USERDEF,
};
- struct BlendFileData *bfd = BKE_blendfile_read(filepath_startup, &params, NULL);
+ struct BlendFileData *bfd = BKE_blendfile_read(
+ filepath_startup, &params, &(BlendFileReadReport){NULL});
if (bfd != NULL) {
- BKE_blendfile_read_setup_ex(
- C, bfd, &params, NULL, update_defaults && use_data, app_template);
+ BKE_blendfile_read_setup_ex(C,
+ bfd,
+ &params,
+ &(BlendFileReadReport){NULL},
+ update_defaults && use_data,
+ app_template);
success = true;
}
}
@@ -1117,7 +1224,7 @@ void wm_homefile_read(bContext *C,
struct BlendFileData *bfd = BKE_blendfile_read_from_memory(
datatoc_startup_blend, datatoc_startup_blend_size, &params, NULL);
if (bfd != NULL) {
- BKE_blendfile_read_setup_ex(C, bfd, &params, NULL, true, NULL);
+ BKE_blendfile_read_setup_ex(C, bfd, &params, &(BlendFileReadReport){NULL}, true, NULL);
success = true;
}
@@ -1170,7 +1277,7 @@ void wm_homefile_read(bContext *C,
BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
}
- bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(C);
if (use_userdef) {
/* check userdef before open window, keymaps etc */
@@ -1580,7 +1687,7 @@ static bool wm_file_write(bContext *C,
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
- /* run this function after because the file cant be written before the blend is */
+ /* run this function after because the file can't be written before the blend is */
if (ibuf_thumb) {
IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
@@ -1775,7 +1882,7 @@ void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
if (!RNA_property_is_set(op->ptr, prop)) {
/* use G_FLAG_SCRIPT_AUTOEXEC rather than the userpref because this means if
* the flag has been disabled from the command line, then opening
- * from the menu wont enable this setting. */
+ * from the menu won't enable this setting. */
bool value = use_prefs ? ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) :
((G.f & G_FLAG_SCRIPT_AUTOEXEC) != 0);
@@ -1833,7 +1940,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
&(const struct BlendFileWriteParams){
/* Make all paths absolute when saving the startup file.
* On load the `G.relbase_valid` will be false so the paths
- * wont have a base for resolving the relative paths. */
+ * won't have a base for resolving the relative paths. */
.remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
/* Don't apply any path changes to the current blend file. */
.use_save_as_copy = true,
@@ -2482,12 +2589,11 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
{
struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
uiLayout *layout = op->layout;
- uiLayout *col = op->layout;
const char *autoexec_text;
uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
- col = uiLayoutColumn(layout, false);
+ uiLayout *col = uiLayoutColumn(layout, false);
if (file_info->is_untrusted) {
autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
uiLayoutSetActive(col, false);
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 840debad01b..f938c507818 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -244,7 +244,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
bh = BLO_blendhandle_from_memory(datatoc_startup_blend, datatoc_startup_blend_size);
}
else {
- bh = BLO_blendhandle_from_file(libname, reports);
+ bh = BLO_blendhandle_from_file(libname, &(BlendFileReadReport){.reports = reports});
}
if (bh == NULL) {
@@ -521,7 +521,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
wm_link_append_data_free(lapp_data);
- /* important we unset, otherwise these object wont
+ /* important we unset, otherwise these object won't
* link into other scenes from this blend file */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
@@ -642,23 +642,23 @@ void WM_OT_append(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Append Single Data-Block & Return it
+/** \name Link/Append Single Data-Block & Return it
*
- * Used for appending workspace from startup files.
* \{ */
-ID *WM_file_append_datablock(Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- View3D *v3d,
- const char *filepath,
- const short id_code,
- const char *id_name)
+static ID *wm_file_link_datablock_ex(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ View3D *v3d,
+ const char *filepath,
+ const short id_code,
+ const char *id_name,
+ bool clear_pre_existing_flag)
{
/* Tag everything so we can make local only the new datablock. */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
- /* Define working data, with just the one item we want to append. */
+ /* Define working data, with just the one item we want to link. */
WMLinkAppendData *lapp_data = wm_link_append_data_new(0);
wm_link_append_data_library_add(lapp_data, filepath);
@@ -672,6 +672,36 @@ ID *WM_file_append_datablock(Main *bmain,
ID *id = item->new_id;
wm_link_append_data_free(lapp_data);
+ if (clear_pre_existing_flag) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ }
+
+ return id;
+}
+
+ID *WM_file_link_datablock(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ View3D *v3d,
+ const char *filepath,
+ const short id_code,
+ const char *id_name)
+{
+ return wm_file_link_datablock_ex(
+ bmain, scene, view_layer, v3d, filepath, id_code, id_name, true);
+}
+
+ID *WM_file_append_datablock(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ View3D *v3d,
+ const char *filepath,
+ const short id_code,
+ const char *id_name)
+{
+ ID *id = wm_file_link_datablock_ex(
+ bmain, scene, view_layer, v3d, filepath, id_code, id_name, false);
+
/* Make datablock local. */
BKE_library_make_local(bmain, NULL, NULL, true, false);
@@ -978,7 +1008,7 @@ static void lib_relocate_do(Main *bmain,
BKE_main_lib_objects_recalc_all(bmain);
IMB_colormanagement_check_file_config(bmain);
- /* important we unset, otherwise these object wont
+ /* important we unset, otherwise these object won't
* link into other scenes from this blend file */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 15f0978f87d..48ab76317b5 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -272,7 +272,7 @@ void WM_init(bContext *C, int argc, const char **argv)
* for scripts that do background processing with preview icons. */
BKE_icons_init(BIFICONID_LAST);
- /* reports cant be initialized before the wm,
+ /* reports can't be initialized before the wm,
* but keep before file reading, since that may report errors */
wm_init_reports(C);
@@ -331,7 +331,7 @@ void WM_init(bContext *C, int argc, const char **argv)
* startup.blend because it may contain PyDrivers. It also needs to be after
* initializing space types and other internal data.
*
- * However cant redo this at the moment. Solution is to load python
+ * However can't redo this at the moment. Solution is to load python
* before wm_homefile_read() or make py-drivers check if python is running.
* Will try fix when the crash can be repeated. - campbell. */
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 0a157e63b09..69b3660038d 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -1787,7 +1787,7 @@ void WM_keyconfig_update(wmWindowManager *wm)
}
if (wm_keymap_update_flag & WM_KEYMAP_UPDATE_OPERATORTYPE) {
- /* an operatortype has been removed, this wont happen often
+ /* an operatortype has been removed, this won't happen often
* but when it does we have to check _every_ keymap item */
ListBase *keymaps_lb[] = {
&U.user_keymaps,
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index f33db7d50b5..1f3574f9032 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -343,7 +343,7 @@ static int wm_macro_exec(bContext *C, wmOperator *op)
}
}
else {
- CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname);
+ CLOG_WARN(WM_LOG_OPERATORS, "'%s' can't exec macro", opm->type->idname);
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 9175eb2dbf7..32b0ca66a33 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1346,7 +1346,7 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
wmOperator *op;
{
/* Execute will free the operator.
- * In this case, wm_operator_ui_popup_cancel wont run. */
+ * In this case, wm_operator_ui_popup_cancel won't run. */
wmOpPopUp *data = arg1;
op = data->op;
MEM_freeN(data);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index cdd5ea12df8..ae5a2c81582 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -550,7 +550,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm,
}
int scr_w, scr_h;
- wm_get_screensize(&scr_w, &scr_h);
+ wm_get_desktopsize(&scr_w, &scr_h);
int posy = (scr_h - win->posy - win->sizey);
/* Clear drawable so we can set the new window. */
@@ -756,6 +756,7 @@ static bool wm_window_update_size_position(wmWindow *win)
/**
* \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \param toplevel: Not a child owned by other windows. A peer of main window.
* \param dialog: whether this should be made as a dialog-style window
* \param temp: whether this is considered a short-lived window
* \param alignment: how this window is positioned relative to its parent
@@ -768,6 +769,7 @@ wmWindow *WM_window_open(bContext *C,
int sizex,
int sizey,
int space_type,
+ bool toplevel,
bool dialog,
bool temp,
WindowAlignment alignment)
@@ -822,7 +824,7 @@ wmWindow *WM_window_open(bContext *C,
/* add new window? */
if (win == NULL) {
- win = wm_window_new(bmain, wm, win_prev, dialog);
+ win = wm_window_new(bmain, wm, toplevel ? NULL : win_prev, dialog);
win->posx = rect.xmin;
win->posy = rect.ymin;
*win->stereo3d_format = *win_prev->stereo3d_format;
@@ -925,6 +927,7 @@ int wm_window_new_exec(bContext *C, wmOperator *UNUSED(op))
area->spacetype,
false,
false,
+ false,
WIN_ALIGN_PARENT_CENTER) != NULL);
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
@@ -2077,7 +2080,7 @@ void WM_init_tablet_api(void)
if (g_system) {
switch (U.tablet_api) {
case USER_TABLET_NATIVE:
- GHOST_SetTabletAPI(g_system, GHOST_kTabletNative);
+ GHOST_SetTabletAPI(g_system, GHOST_kTabletWinPointer);
break;
case USER_TABLET_WINTAB:
GHOST_SetTabletAPI(g_system, GHOST_kTabletWintab);
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 39bf2f1e32d..a4b32fac9fc 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -371,14 +371,14 @@ if(WITH_PYTHON)
"${BLENDER_VERSION_CYCLE}" STREQUAL "rc")
set(ADDON_EXCLUDE_CONDITIONAL "addons_contrib/*")
else()
- set(ADDON_EXCLUDE_CONDITIONAL "_addons_contrib/*") # dummy, wont do anything
+ set(ADDON_EXCLUDE_CONDITIONAL "_addons_contrib/*") # dummy, won't do anything
endif()
# do not install freestyle dir if disabled
if(NOT WITH_FREESTYLE)
set(FREESTYLE_EXCLUDE_CONDITIONAL "freestyle/*")
else()
- set(FREESTYLE_EXCLUDE_CONDITIONAL "_freestyle/*") # dummy, wont do anything
+ set(FREESTYLE_EXCLUDE_CONDITIONAL "_freestyle/*") # dummy, won't do anything
endif()
install(
@@ -631,9 +631,9 @@ if(UNIX AND NOT APPLE)
PATTERN "doc" EXCLUDE # ./doc
PATTERN "tests" EXCLUDE # ./tests
PATTERN "f2py" EXCLUDE # ./f2py - fortran/python interface code, not for blender.
- PATTERN "include" EXCLUDE # include dirs all over, we wont use NumPy/CAPI
+ PATTERN "include" EXCLUDE # include dirs all over, we won't use NumPy/CAPI
PATTERN "*.h" EXCLUDE # some includes are not in include dirs
- PATTERN "*.a" EXCLUDE # ./core/lib/libnpymath.a - for linking, we dont need.
+ PATTERN "*.a" EXCLUDE # ./core/lib/libnpymath.a - for linking, we don't need.
)
unset(_suffix)
endif()
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 8b1ac05f086..3f5ca84fbef 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -1317,6 +1317,7 @@ static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(a
G.background = 1;
}
BLI_windows_register_blend_extension(G.background);
+ TerminateProcess(GetCurrentProcess(), 0);
# else
(void)data; /* unused */
# endif
@@ -1959,7 +1960,9 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
}
BLI_strncpy(filename, argv[0], sizeof(filename));
+ BLI_path_slash_native(filename);
BLI_path_abs_from_cwd(filename, sizeof(filename));
+ BLI_path_normalize(NULL, filename);
/* load the file */
BKE_reports_init(&reports, RPT_PRINT);
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index 2a89aaa4aea..6e2dd380793 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -1,6 +1,6 @@
if(WITH_GTESTS)
- # Otherwise we get warnings here that we cant fix in external projects
+ # Otherwise we get warnings here that we can't fix in external projects
remove_strict_flags()
# Build common test executable used by most tests
diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py
index 7e64081cfbb..134ee091bb7 100644
--- a/tests/python/batch_import.py
+++ b/tests/python/batch_import.py
@@ -167,7 +167,7 @@ def main():
parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
- options, _args = parser.parse_args(argv) # In this example we wont use the args
+ options, _args = parser.parse_args(argv) # In this example we won't use the args
if not argv:
parser.print_help()
diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py
index 26fe6dac93d..6554dd8e414 100644
--- a/tests/python/bl_run_operators.py
+++ b/tests/python/bl_run_operators.py
@@ -89,7 +89,7 @@ op_blacklist = (
"wm.memory_statistics", # another annoying one
"wm.dependency_relations", # another annoying one
"wm.keymap_restore", # another annoying one
- "wm.addon_*", # harmless, but dont change state
+ "wm.addon_*", # harmless, but don't change state
"console.*", # just annoying - but harmless
"wm.url_open_preset", # Annoying but harmless (opens web pages).
@@ -178,7 +178,7 @@ if USE_ATTRSET:
if issubclass(cls, skip_classes):
continue
- # # to support skip-save we cant get all props
+ # # to support skip-save we can't get all props
# properties = cls.bl_rna.properties.keys()
properties = []
for prop_id, prop in cls.bl_rna.properties.items():
diff --git a/tests/python/bl_test.py b/tests/python/bl_test.py
index 110b4238f6c..6315ffbfa9d 100644
--- a/tests/python/bl_test.py
+++ b/tests/python/bl_test.py
@@ -32,18 +32,9 @@ def replace_bpy_app_version():
app = bpy.app
app_fake = type(bpy)("bpy.app")
- app_attr_exclude = {
- # This causes a noisy warning every time.
- "binary_path_python",
- }
-
for attr in dir(app):
- if attr.startswith("_"):
- continue
- if attr in app_attr_exclude:
- continue
-
- setattr(app_fake, attr, getattr(app, attr))
+ if not attr.startswith("_"):
+ setattr(app_fake, attr, getattr(app, attr))
app_fake.version = 0, 0, 0
app_fake.version_string = "0.00 (sub 0)"