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-07-14 23:07:36 +0300
committerHans Goudey <h.goudey@me.com>2021-07-14 23:07:36 +0300
commitdc0c71d3ae772c9afdec0718ae135b9b91f57e8b (patch)
tree3c89c71d0a33ecb3a3b4abfb67641051e34608f7
parentd7a74a2ad69914602f563852610efff3e8ed6e1c (diff)
parent093074aefe87259882b56a911d8eeb311408ff14 (diff)
Merge branch 'master' into temp-geometry-nodes-curve-sample
-rw-r--r--build_files/build_environment/cmake/versions.cmake4
-rwxr-xr-xbuild_files/build_environment/install_deps.sh12
-rw-r--r--build_files/windows/autodetect_msvc.cmd4
-rw-r--r--intern/cycles/blender/blender_image.cpp6
-rw-r--r--intern/cycles/blender/blender_object.cpp12
-rw-r--r--intern/cycles/blender/blender_sync.cpp16
-rw-r--r--intern/cycles/kernel/svm/svm_vector_rotate.h11
-rw-r--r--intern/cycles/render/session.cpp183
-rw-r--r--intern/cycles/render/session.h3
-rw-r--r--intern/ghost/CMakeLists.txt1
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp11
-rw-r--r--intern/ghost/test/gears/GHOST_Test.cpp4
-rw-r--r--intern/guardedalloc/intern/mallocn_intern.h10
-rw-r--r--intern/libmv/libmv/numeric/numeric.h2
-rw-r--r--intern/libmv/libmv/tracking/retrack_region_tracker.cc2
-rw-r--r--release/scripts/freestyle/modules/freestyle/shaders.py6
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py1
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py8
-rw-r--r--release/scripts/startup/bl_ui/space_node.py93
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py14
-rw-r--r--release/scripts/startup/nodeitems_builtins.py2
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_deform.h14
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h35
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh10
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h11
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h6
-rw-r--r--source/blender/blenkernel/BKE_mesh_types.h1
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_node_ui_storage.hh133
-rw-r--r--source/blender/blenkernel/BKE_object.h8
-rw-r--r--source/blender/blenkernel/BKE_scene.h8
-rw-r--r--source/blender/blenkernel/BKE_spline.hh12
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h2
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h7
-rw-r--r--source/blender/blenkernel/CMakeLists.txt5
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc22
-rw-r--r--source/blender/blenkernel/intern/action.c38
-rw-r--r--source/blender/blenkernel/intern/action_test.cc144
-rw-r--r--source/blender/blenkernel/intern/anim_data.c32
-rw-r--r--source/blender/blenkernel/intern/armature.c2
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c14
-rw-r--r--source/blender/blenkernel/intern/armature_update.c12
-rw-r--r--source/blender/blenkernel/intern/blendfile.c2
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/cloth.c2
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c2
-rw-r--r--source/blender/blenkernel/intern/deform.c182
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c12
-rw-r--r--source/blender/blenkernel/intern/editmesh.c17
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c1
-rw-r--r--source/blender/blenkernel/intern/fluid.c10
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc72
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc1
-rw-r--r--source/blender/blenkernel/intern/gpencil.c41
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c12
-rw-r--r--source/blender/blenkernel/intern/ipo.c26
-rw-r--r--source/blender/blenkernel/intern/key.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c6
-rw-r--r--source/blender/blenkernel/intern/lattice_deform.c4
-rw-r--r--source/blender/blenkernel/intern/layer.c130
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c1
-rw-r--r--source/blender/blenkernel/intern/mesh.c14
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc19
-rw-r--r--source/blender/blenkernel/intern/node.cc10
-rw-r--r--source/blender/blenkernel/intern/node_ui_storage.cc169
-rw-r--r--source/blender/blenkernel/intern/object.c71
-rw-r--r--source/blender/blenkernel/intern/object_deform.c80
-rw-r--r--source/blender/blenkernel/intern/object_update.c23
-rw-r--r--source/blender/blenkernel/intern/particle.c2
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/scene.c49
-rw-r--r--source/blender/blenkernel/intern/screen.c6
-rw-r--r--source/blender/blenkernel/intern/softbody.c10
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc40
-rw-r--r--source/blender/blenkernel/intern/studiolight.c2
-rw-r--r--source/blender/blenkernel/intern/undo_system.c29
-rw-r--r--source/blender/blenlib/BLI_array_utils.h31
-rw-r--r--source/blender/blenlib/BLI_assert.h10
-rw-r--r--source/blender/blenlib/BLI_enumerable_thread_specific.hh16
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/intern/BLI_assert.c5
-rw-r--r--source/blender/blenlib/intern/array_utils.c82
-rw-r--r--source/blender/blenlib/intern/math_rotation.c2
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc9
-rw-r--r--source/blender/blenlib/intern/path_util.c2
-rw-r--r--source/blender/blenlib/tests/BLI_array_utils_test.cc50
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c60
-rw-r--r--source/blender/bmesh/bmesh_class.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c12
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c2
-rw-r--r--source/blender/compositor/CMakeLists.txt5
-rw-r--r--source/blender/compositor/COM_defines.h3
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc7
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h30
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.cc6
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc66
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h25
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc10
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc65
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.h40
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc105
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc72
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc3
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc15
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc9
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc5
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc10
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h10
-rw-r--r--source/blender/draw/CMakeLists.txt8
-rw-r--r--source/blender/draw/engines/image/image_engine.c39
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c11
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c1
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c1
-rw-r--r--source/blender/draw/intern/draw_cache.c4
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h2
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_private.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c15
-rw-r--r--source/blender/draw/intern/draw_manager.c2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c15
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c2
-rw-r--r--source/blender/editors/armature/armature_skinning.c2
-rw-r--r--source/blender/editors/armature/editarmature_undo.c2
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c82
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_bake_animation.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c51
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c6
-rw-r--r--source/blender/editors/include/ED_gpencil.h7
-rw-r--r--source/blender/editors/include/ED_keyframing.h2
-rw-r--r--source/blender/editors/include/ED_mesh.h2
-rw-r--r--source/blender/editors/include/UI_interface.h49
-rw-r--r--source/blender/editors/interface/interface_context_menu.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c296
-rw-r--r--source/blender/editors/interface/interface_intern.h3
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c4
-rw-r--r--source/blender/editors/interface/interface_widgets.c3
-rw-r--r--source/blender/editors/lattice/editlattice_select.c2
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c1
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c4
-rw-r--r--source/blender/editors/mesh/editmesh_path.c1
-rw-r--r--source/blender/editors/mesh/editmesh_select.c5
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c13
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c3
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c17
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c48
-rw-r--r--source/blender/editors/mesh/mesh_data.c1
-rw-r--r--source/blender/editors/mesh/meshtools.c29
-rw-r--r--source/blender/editors/metaball/editmball_undo.c2
-rw-r--r--source/blender/editors/object/object_add.c2
-rw-r--r--source/blender/editors/object/object_data_transfer.c6
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_hook.c10
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c33
-rw-r--r--source/blender/editors/object/object_transform.c490
-rw-r--r--source/blender/editors/object/object_vgroup.c192
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c20
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c22
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_action/action_data.c4
-rw-r--r--source/blender/editors/space_file/file_draw.c28
-rw-r--r--source/blender/editors/space_file/file_intern.h5
-rw-r--r--source/blender/editors/space_file/file_ops.c22
-rw-r--r--source/blender/editors/space_file/filelist.c35
-rw-r--r--source/blender/editors/space_file/filelist.h3
-rw-r--r--source/blender/editors/space_file/filesel.c53
-rw-r--r--source/blender/editors/space_file/space_file.c12
-rw-r--r--source/blender/editors/space_image/image_undo.c2
-rw-r--r--source/blender/editors/space_info/info_ops.c9
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt18
-rw-r--r--source/blender/editors/space_node/node_buttons.c250
-rw-r--r--source/blender/editors/space_node/node_draw.cc259
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc88
-rw-r--r--source/blender/editors/space_node/node_intern.h3
-rw-r--r--source/blender/editors/space_node/space_node.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c26
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc34
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc91
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c13
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c6
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc25
-rw-r--r--source/blender/editors/space_text/text_undo.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c117
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c85
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c70
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c26
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c1
-rw-r--r--source/blender/editors/transform/transform_convert_object.c4
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c2
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c5
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c30
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/imbuf/intern/bmp.c7
-rw-r--r--source/blender/io/collada/ControllerExporter.cpp23
-rw-r--r--source/blender/io/collada/ControllerExporter.h10
-rw-r--r--source/blender/io/collada/SkinInfo.cpp4
-rw-r--r--source/blender/makesdna/DNA_ID.h9
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h6
-rw-r--r--source/blender/makesdna/DNA_lattice_types.h5
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h10
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h16
-rw-r--r--source/blender/makesdna/DNA_object_types.h11
-rw-r--r--source/blender/makesdna/DNA_pointcache_types.h50
-rw-r--r--source/blender/makesdna/DNA_space_types.h7
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_ID.c15
-rw-r--r--source/blender/makesrna/intern/rna_access.c31
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c4
-rw-r--r--source/blender/makesrna/intern/rna_armature.c20
-rw-r--r--source/blender/makesrna/intern/rna_asset.c10
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c8
-rw-r--r--source/blender/makesrna/intern/rna_internal.h4
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_layer.c10
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c19
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c73
-rw-r--r--source/blender/makesrna/intern/rna_object.c101
-rw-r--r--source/blender/makesrna/intern/rna_particle.c6
-rw-r--r--source/blender/makesrna/intern/rna_pose.c10
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c19
-rw-r--r--source/blender/makesrna/intern/rna_space.c14
-rw-r--r--source/blender/makesrna/intern/rna_timeline.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui.c9
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c9
-rw-r--r--source/blender/makesrna/intern/rna_wm.c17
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo.c18
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c4
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_build.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c12
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc15
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c8
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc132
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc56
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.hh7
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c12
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c5
-rw-r--r--source/blender/modifiers/intern/MOD_util.c21
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c5
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c7
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt10
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh8
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh309
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc241
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc76
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc2
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc361
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc16
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc2
-rw-r--r--source/blender/python/gpu/gpu_py_uniformbuffer.c2
-rw-r--r--source/blender/python/intern/bpy_rna.c58
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c4
-rw-r--r--source/blender/python/intern/bpy_utils_previews.c1
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c2
-rw-r--r--source/blender/render/intern/bake.c10
-rw-r--r--source/blender/render/intern/engine.c2
-rw-r--r--source/blender/render/intern/pipeline.c4
-rw-r--r--source/blender/render/intern/texture_pointdensity.c8
-rw-r--r--source/blender/sequencer/CMakeLists.txt2
-rw-r--r--source/blender/sequencer/SEQ_clipboard.h4
-rw-r--r--source/blender/sequencer/intern/clipboard.c28
-rw-r--r--tests/performance/api/graph.py21
-rw-r--r--tests/performance/api/graph.template.html2
-rw-r--r--tests/performance/tests/cycles.py22
-rw-r--r--tests/python/bl_run_operators_event_simulate.py35
-rwxr-xr-xtests/python/modules/render_report.py2
322 files changed, 5063 insertions, 2831 deletions
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 2d015440d5d..bb0ee961f05 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -456,9 +456,9 @@ set(NASM_HASH aded8b796c996a486a56e0515c83e414116decc3b184d88043480b32eb0a8589)
set(NASM_HASH_TYPE SHA256)
set(NASM_FILE nasm-${NASM_VERSION}.tar.gz)
-set(XR_OPENXR_SDK_VERSION 1.0.14)
+set(XR_OPENXR_SDK_VERSION 1.0.17)
set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz)
-set(XR_OPENXR_SDK_HASH 0df6b2fd6045423451a77ff6bc3e1a75)
+set(XR_OPENXR_SDK_HASH bf0fd8828837edff01047474e90013e1)
set(XR_OPENXR_SDK_HASH_TYPE MD5)
set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz)
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 65918777e47..c5b7198d012 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -572,7 +572,7 @@ FFMPEG_FORCE_REBUILD=false
FFMPEG_SKIP=false
_ffmpeg_list_sep=";"
-XR_OPENXR_VERSION="1.0.14"
+XR_OPENXR_VERSION="1.0.17"
XR_OPENXR_VERSION_SHORT="1.0"
XR_OPENXR_VERSION_MIN="1.0.8"
XR_OPENXR_VERSION_MAX="2.0"
@@ -1108,9 +1108,9 @@ FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
XR_OPENXR_USE_REPO=false
XR_OPENXR_SOURCE=("https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_VERSION}.tar.gz")
-#~ XR_OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK.git")
-#~ XR_OPENXR_REPO_UID="5900c51562769b03bea699dc0352cae56acb6419d"
-#~ XR_OPENXR_REPO_BRANCH="master"
+XR_OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK.git")
+XR_OPENXR_REPO_UID="bf21ccb1007bb531b45d9978919a56ea5059c245"
+XR_OPENXR_REPO_BRANCH="master"
# C++11 is required now
CXXFLAGS_BACK=$CXXFLAGS
@@ -2738,7 +2738,7 @@ _init_openvdb() {
_git=false
_inst=$INST/openvdb-$OPENVDB_VERSION_SHORT
_inst_shortcut=$INST/openvdb
-
+
_openvdb_source=$OPENVDB_SOURCE
if [ "$WITH_NANOVDB" = true ]; then
_openvdb_source=$NANOVDB_SOURCE
@@ -2843,7 +2843,7 @@ compile_OPENVDB() {
if [ -d $INST/blosc ]; then
cmake_d="$cmake_d -D Blosc_ROOT=$INST/blosc"
fi
-
+
cmake $cmake_d ..
make -j$THREADS install
diff --git a/build_files/windows/autodetect_msvc.cmd b/build_files/windows/autodetect_msvc.cmd
index 6cee4765b93..a4ab8929040 100644
--- a/build_files/windows/autodetect_msvc.cmd
+++ b/build_files/windows/autodetect_msvc.cmd
@@ -1,9 +1,9 @@
echo No explicit msvc version requested, autodetecting version.
-call "%~dp0\detect_msvc2017.cmd"
+call "%~dp0\detect_msvc2019.cmd"
if %ERRORLEVEL% EQU 0 goto DetectionComplete
-call "%~dp0\detect_msvc2019.cmd"
+call "%~dp0\detect_msvc2017.cmd"
if %ERRORLEVEL% EQU 0 goto DetectionComplete
call "%~dp0\detect_msvc2022.cmd"
diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp
index 3a9d159e461..f27275bd457 100644
--- a/intern/cycles/blender/blender_image.cpp
+++ b/intern/cycles/blender/blender_image.cpp
@@ -137,9 +137,9 @@ bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
/* Premultiply, byte images are always straight for Blender. */
unsigned char *cp = (unsigned char *)pixels;
for (size_t i = 0; i < num_pixels; i++, cp += channels) {
- cp[0] = (cp[0] * cp[3]) >> 8;
- cp[1] = (cp[1] * cp[3]) >> 8;
- cp[2] = (cp[2] * cp[3]) >> 8;
+ cp[0] = (cp[0] * cp[3]) / 255;
+ cp[1] = (cp[1] * cp[3]) / 255;
+ cp[2] = (cp[2] * cp[3]) / 255;
}
}
}
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 635392fb3d4..f5e8db2aee1 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -109,23 +109,23 @@ void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob
}
Geometry *geom = object->get_geometry();
- geom->set_use_motion_blur(false);
- geom->set_motion_steps(0);
- uint motion_steps;
+ int motion_steps = 0;
+ bool use_motion_blur = false;
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
- geom->set_motion_steps(motion_steps);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
- geom->set_use_motion_blur(true);
+ use_motion_blur = true;
}
}
else {
motion_steps = 3;
- geom->set_motion_steps(motion_steps);
}
+ geom->set_use_motion_blur(use_motion_blur);
+ geom->set_motion_steps(motion_steps);
+
motion.resize(motion_steps, transform_empty());
if (motion_steps) {
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 3b3a193b3e8..ce399579e25 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -404,8 +404,6 @@ void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
Film *film = scene->film;
- vector<Pass> prevpasses = scene->passes;
-
if (b_v3d) {
film->set_display_pass(update_viewport_display_passes(b_v3d, scene->passes));
}
@@ -435,11 +433,6 @@ void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
break;
}
}
-
- if (!Pass::equals(prevpasses, scene->passes)) {
- film->tag_passes_update(scene, prevpasses, false);
- film->tag_modified();
- }
}
/* Render Layer */
@@ -749,10 +742,13 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
DENOISING_CLEAN_ALL_PASSES);
scene->film->set_denoising_prefiltered_pass(denoising.store_passes &&
denoising.type == DENOISER_NLM);
-
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
- scene->film->tag_passes_update(scene, passes);
- scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
+
+ if (!Pass::equals(passes, scene->passes)) {
+ scene->film->tag_passes_update(scene, passes);
+ scene->film->tag_modified();
+ scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
+ }
return passes;
}
diff --git a/intern/cycles/kernel/svm/svm_vector_rotate.h b/intern/cycles/kernel/svm/svm_vector_rotate.h
index 79a4ec2c40e..50045752484 100644
--- a/intern/cycles/kernel/svm/svm_vector_rotate.h
+++ b/intern/cycles/kernel/svm/svm_vector_rotate.h
@@ -50,24 +50,29 @@ ccl_device void svm_node_vector_rotate(ShaderData *sd,
}
else {
float3 axis;
+ float axis_length;
switch (type) {
case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
axis = make_float3(1.0f, 0.0f, 0.0f);
+ axis_length = 1.0f;
break;
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
axis = make_float3(0.0f, 1.0f, 0.0f);
+ axis_length = 1.0f;
break;
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
axis = make_float3(0.0f, 0.0f, 1.0f);
+ axis_length = 1.0f;
break;
default:
- axis = normalize(stack_load_float3(stack, axis_stack_offset));
+ axis = stack_load_float3(stack, axis_stack_offset);
+ axis_length = len(axis);
break;
}
float angle = stack_load_float(stack, angle_stack_offset);
angle = invert ? -angle : angle;
- result = (len_squared(axis) != 0.0f) ?
- rotate_around_axis(vector - center, axis, angle) + center :
+ result = (axis_length != 0.0f) ?
+ rotate_around_axis(vector - center, axis / axis_length, angle) + center :
vector;
}
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index ca90af77f6e..19d4a66353d 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -227,66 +227,25 @@ void Session::run_gpu()
progress.set_render_start_time();
while (!progress.get_cancel()) {
- /* advance to next tile */
- bool no_tiles = !tile_manager.next();
+ const bool no_tiles = !run_update_for_next_iteration();
- DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN;
if (no_tiles) {
- kernel_state = device->get_active_kernel_switch_state();
- }
-
- if (params.background) {
- /* if no work left and in background mode, we can stop immediately */
- if (no_tiles) {
+ if (params.background) {
+ /* if no work left and in background mode, we can stop immediately */
progress.set_status("Finished");
break;
}
}
- else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) {
- reset_gpu(tile_manager.params, params.samples);
+ if (run_wait_for_work(no_tiles)) {
+ continue;
}
- else {
- /* if in interactive mode, and we are either paused or done for now,
- * wait for pause condition notify to wake up again */
- thread_scoped_lock pause_lock(pause_mutex);
-
- if (!pause && !tile_manager.done()) {
- /* reset could have happened after no_tiles was set, before this lock.
- * in this case we shall not wait for pause condition
- */
- }
- else if (pause || no_tiles) {
- update_status_time(pause, no_tiles);
-
- while (1) {
- scoped_timer pause_timer;
- pause_cond.wait(pause_lock);
- if (pause) {
- progress.add_skip_time(pause_timer, params.background);
- }
-
- update_status_time(pause, no_tiles);
- progress.set_update();
-
- if (!pause)
- break;
- }
- }
-
- if (progress.get_cancel())
- break;
+ if (progress.get_cancel()) {
+ break;
}
if (!no_tiles) {
- /* update scene */
- scoped_timer update_timer;
- if (update_scene()) {
- profiler.reset(scene->shaders.size(), scene->objects.size());
- }
- progress.add_skip_time(update_timer, params.background);
-
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -729,82 +688,27 @@ void Session::run_cpu()
last_update_time = time_dt();
last_display_time = last_update_time;
- {
- /* reset once to start */
- thread_scoped_lock reset_lock(delayed_reset.mutex);
- thread_scoped_lock buffers_lock(buffers_mutex);
- thread_scoped_lock display_lock(display_mutex);
-
- reset_(delayed_reset.params, delayed_reset.samples);
- delayed_reset.do_reset = false;
- }
-
while (!progress.get_cancel()) {
- /* advance to next tile */
- bool no_tiles = !tile_manager.next();
+ const bool no_tiles = !run_update_for_next_iteration();
bool need_copy_to_display_buffer = false;
- DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN;
if (no_tiles) {
- kernel_state = device->get_active_kernel_switch_state();
- }
-
- if (params.background) {
- /* if no work left and in background mode, we can stop immediately */
- if (no_tiles) {
+ if (params.background) {
+ /* if no work left and in background mode, we can stop immediately */
progress.set_status("Finished");
break;
}
}
- else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) {
- reset_cpu(tile_manager.params, params.samples);
+ if (run_wait_for_work(no_tiles)) {
+ continue;
}
- else {
- /* if in interactive mode, and we are either paused or done for now,
- * wait for pause condition notify to wake up again */
- thread_scoped_lock pause_lock(pause_mutex);
-
- if (!pause && delayed_reset.do_reset) {
- /* reset once to start */
- thread_scoped_lock reset_lock(delayed_reset.mutex);
- thread_scoped_lock buffers_lock(buffers_mutex);
- thread_scoped_lock display_lock(display_mutex);
-
- reset_(delayed_reset.params, delayed_reset.samples);
- delayed_reset.do_reset = false;
- }
- else if (pause || no_tiles) {
- update_status_time(pause, no_tiles);
-
- while (1) {
- scoped_timer pause_timer;
- pause_cond.wait(pause_lock);
- if (pause) {
- progress.add_skip_time(pause_timer, params.background);
- }
-
- update_status_time(pause, no_tiles);
- progress.set_update();
-
- if (!pause)
- break;
- }
- }
-
- if (progress.get_cancel())
- break;
+ if (progress.get_cancel()) {
+ break;
}
if (!no_tiles) {
- /* update scene */
- scoped_timer update_timer;
- if (update_scene()) {
- profiler.reset(scene->shaders.size(), scene->objects.size());
- }
- progress.add_skip_time(update_timer, params.background);
-
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -894,6 +798,63 @@ void Session::run()
progress.set_update();
}
+bool Session::run_update_for_next_iteration()
+{
+ thread_scoped_lock scene_lock(scene->mutex);
+ thread_scoped_lock reset_lock(delayed_reset.mutex);
+
+ if (delayed_reset.do_reset) {
+ thread_scoped_lock buffers_lock(buffers_mutex);
+ reset_(delayed_reset.params, delayed_reset.samples);
+ delayed_reset.do_reset = false;
+ }
+
+ const bool have_tiles = tile_manager.next();
+
+ if (have_tiles) {
+ scoped_timer update_timer;
+ if (update_scene()) {
+ profiler.reset(scene->shaders.size(), scene->objects.size());
+ }
+ progress.add_skip_time(update_timer, params.background);
+ }
+
+ return have_tiles;
+}
+
+bool Session::run_wait_for_work(bool no_tiles)
+{
+ /* In an offline rendering there is no pause, and no tiles will mean the job is fully done. */
+ if (params.background) {
+ return false;
+ }
+
+ thread_scoped_lock pause_lock(pause_mutex);
+
+ if (!pause && !no_tiles) {
+ return false;
+ }
+
+ update_status_time(pause, no_tiles);
+
+ while (true) {
+ scoped_timer pause_timer;
+ pause_cond.wait(pause_lock);
+ if (pause) {
+ progress.add_skip_time(pause_timer, params.background);
+ }
+
+ update_status_time(pause, no_tiles);
+ progress.set_update();
+
+ if (!pause) {
+ break;
+ }
+ }
+
+ return no_tiles;
+}
+
bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params)
{
if (device_use_gl)
@@ -1012,8 +973,6 @@ void Session::wait()
bool Session::update_scene()
{
- thread_scoped_lock scene_lock(scene->mutex);
-
/* update camera if dimensions changed for progressive render. the camera
* knows nothing about progressive or cropped rendering, it just gets the
* image dimensions passed in */
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 43ff07e5884..bc3b8366c05 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -178,6 +178,9 @@ class Session {
void run();
+ bool run_update_for_next_iteration();
+ bool run_wait_for_work(bool no_tiles);
+
void update_status_time(bool show_pause = false, bool show_done = false);
void render(bool use_denoise);
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 6edd7b386da..a35c9fffcab 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -293,6 +293,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
intern/GHOST_WindowWayland.cpp
intern/GHOST_SystemWayland.h
+ intern/GHOST_WaylandCursorSettings.h
intern/GHOST_WindowWayland.h
)
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 72c7c525114..75a80de983d 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -52,9 +52,14 @@
#include <cstring>
-#define BTN_LEFT 0x110
-#define BTN_RIGHT 0x111
-#define BTN_MIDDLE 0x112
+/* selected input event code defines from 'linux/input-event-codes.h'
+ * We include some of the button input event codes here, since the header is
+ * only available in more recent kernel versions. The event codes are used to
+ * to differentiate from which mouse button an event comes from.
+ */
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
struct buffer_t {
void *data;
diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp
index aaac62a1a03..c1cb5f29e2e 100644
--- a/intern/ghost/test/gears/GHOST_Test.cpp
+++ b/intern/ghost/test/gears/GHOST_Test.cpp
@@ -365,8 +365,8 @@ void StereoProjection(float left,
* of zero parallax.
*
* -0.31
- * eye = half the eye separation; positive for the right eye subfield,
- * negative for the left eye subfield.
+ * eye = half the eye separation; positive for the right eye sub-field,
+ * negative for the left eye sub-field.
*/
{
float xmid, ymid, clip_near, clip_far, topw, bottomw, leftw, rightw, dx, dy, n_over_d;
diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h
index aa956150484..e4bd3d533a3 100644
--- a/intern/guardedalloc/intern/mallocn_intern.h
+++ b/intern/guardedalloc/intern/mallocn_intern.h
@@ -53,14 +53,8 @@ size_t malloc_usable_size(void *ptr);
# undef USE_MALLOC_USABLE_SIZE
#endif
-/* Blame Microsoft for LLP64 and no inttypes.h, quick workaround needed: */
-#if defined(WIN64)
-# define SIZET_FORMAT "%I64u"
-# define SIZET_ARG(a) ((unsigned long long)(a))
-#else
-# define SIZET_FORMAT "%lu"
-# define SIZET_ARG(a) ((unsigned long)(a))
-#endif
+#define SIZET_FORMAT "%zu"
+#define SIZET_ARG(a) ((size_t)(a))
#define SIZET_ALIGN_4(len) ((len + 3) & ~(size_t)3)
diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h
index e3d44226338..e3ebdb5a4bb 100644
--- a/intern/libmv/libmv/numeric/numeric.h
+++ b/intern/libmv/libmv/numeric/numeric.h
@@ -43,7 +43,7 @@ inline void sincos(double x, double* sinx, double* cosx) {
# endif
#endif // !__MINGW64__
-#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
inline long lround(double d) {
return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5));
}
diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.cc b/intern/libmv/libmv/tracking/retrack_region_tracker.cc
index 9152078053c..124a032cdff 100644
--- a/intern/libmv/libmv/tracking/retrack_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/retrack_region_tracker.cc
@@ -37,7 +37,7 @@ bool RetrackRegionTracker::Track(const FloatImage& image1,
}
// Now track x2 and y2 backward, to get xx1 and yy1 which, if the track is
// good, should match x1 and y1 (but may not if the track is bad).
- double xx1 = *x2, yy1 = *x2;
+ double xx1 = *x2, yy1 = *y2;
if (!tracker_->Track(image2, image1, *x2, *y2, &xx1, &yy1)) {
return false;
}
diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py
index 28b8aa9b23e..95e1c873657 100644
--- a/release/scripts/freestyle/modules/freestyle/shaders.py
+++ b/release/scripts/freestyle/modules/freestyle/shaders.py
@@ -1153,11 +1153,9 @@ class RoundCapShader(StrokeShader):
return
# calculate the number of additional vertices to form caps
thickness_beg = sum(stroke[0].attribute.thickness)
- caplen_beg = thickness_beg / 2.0
nverts_beg = max(5, int(thickness_beg))
thickness_end = sum(stroke[-1].attribute.thickness)
- caplen_end = (thickness_end) / 2.0
nverts_end = max(5, int(thickness_end))
# adjust the total number of stroke vertices
@@ -1169,7 +1167,7 @@ class RoundCapShader(StrokeShader):
# reshape the cap at the beginning of the stroke
q, attr = buffer[1]
p, attr = buffer[0]
- direction = (p - q).normalized() * caplen_beg
+ direction = (p - q).normalized() * thickness_beg
n = 1.0 / nverts_beg
R, L = attr.thickness
for t, svert in zip(range(nverts_beg, 0, -1), stroke):
@@ -1180,7 +1178,7 @@ class RoundCapShader(StrokeShader):
# reshape the cap at the end of the stroke
q, attr = buffer[-2]
p, attr = buffer[-1]
- direction = (p - q).normalized() * caplen_beg
+ direction = (p - q).normalized() * thickness_end
n = 1.0 / nverts_end
R, L = attr.thickness
for t, svert in zip(range(nverts_end, 0, -1), reversed(stroke)):
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 4319e3a962b..0af7493ed47 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -5551,6 +5551,7 @@ def km_view3d_walk_modal(_params):
("DECELERATE", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "any": True, "repeat": True}, None),
("ACCELERATE", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "any": True}, None),
("DECELERATE", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "any": True}, None),
+ ("AXIS_LOCK_Z", {"type": 'Z', "value": 'PRESS'}, None),
])
return keymap
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index fb8aedd1f49..7f4328bb25a 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -41,7 +41,6 @@ class MESH_MT_vertex_group_context_menu(Menu):
).sort_type = 'BONE_HIERARCHY'
layout.separator()
layout.operator("object.vertex_group_copy", icon='DUPLICATE')
- layout.operator("object.vertex_group_copy_to_linked")
layout.operator("object.vertex_group_copy_to_selected")
layout.separator()
layout.operator("object.vertex_group_mirror", icon='ARROW_LEFTRIGHT').use_topology = False
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 926be1ff820..afbc3abf302 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -72,8 +72,9 @@ class CLIP_PT_marker_display(Panel):
col.prop(view, "show_marker_pattern", text="Pattern")
col.prop(view, "show_marker_search", text="Search")
- col.active = view.show_track_path
col.prop(view, "show_track_path", text="Path")
+ col = col.column()
+ col.active = view.show_track_path
col.prop(view, "path_length", text="Length")
col = row.column()
@@ -113,7 +114,6 @@ class CLIP_PT_clip_display(Panel):
row = layout.row()
col = row.column()
col.prop(sc.clip_user, "use_render_undistorted", text="Render Undistorted")
- col.prop(sc, "lock_selection", text="Lock to Selection")
col = row.column()
col.prop(sc, "show_stable", text="Show Stable")
col.prop(sc, "show_grid", text="Grid")
@@ -190,7 +190,7 @@ class CLIP_HT_header(Header):
row.prop(sc, "pivot_point", text="", icon_only=True)
row = layout.row(align=True)
icon = 'LOCKED' if sc.lock_selection else 'UNLOCKED'
- row.prop(sc, "lock_selection", icon=icon, text="")
+ row.operator("clip.lock_selection_toggle", icon=icon, text="", depress=sc.lock_selection)
row.popover(panel='CLIP_PT_display')
elif sc.view == 'GRAPH':
@@ -250,7 +250,7 @@ class CLIP_HT_header(Header):
row.popover(panel='CLIP_PT_mask_display')
row = layout.row(align=True)
icon = 'LOCKED' if sc.lock_selection else 'UNLOCKED'
- row.prop(sc, "lock_selection", icon=icon, text="")
+ row.operator("clip.lock_selection_toggle", icon=icon, text="", depress=sc.lock_selection)
row.popover(panel='CLIP_PT_display')
def draw(self, context):
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 1208ca0a64a..fba86676ad4 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -694,6 +694,97 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
layout.template_node_socket(color=color)
+class NodeTreeInterfacePanel:
+ def draw_socket_list(self, context, in_out, sockets_propname, active_socket_propname):
+ layout = self.layout
+
+ snode = context.space_data
+ tree = snode.edit_tree
+ sockets = getattr(tree, sockets_propname)
+ active_socket_index = getattr(tree, active_socket_propname)
+ active_socket = sockets[active_socket_index] if active_socket_index >= 0 else None
+
+ split = layout.row()
+
+ split.template_list("NODE_UL_interface_sockets", in_out, tree, sockets_propname, tree, active_socket_propname)
+
+ ops_col = split.column()
+
+ add_remove_col = ops_col.column(align=True)
+ props = add_remove_col.operator("node.tree_socket_add", icon='ADD', text="")
+ props.in_out = in_out
+ props = add_remove_col.operator("node.tree_socket_remove", icon='REMOVE', text="")
+ props.in_out = in_out
+
+ ops_col.separator()
+
+ up_down_col = ops_col.column(align=True)
+ props = up_down_col.operator("node.tree_socket_move", icon='TRIA_UP', text="")
+ props.in_out = in_out
+ props.direction = 'UP'
+ props = up_down_col.operator("node.tree_socket_move", icon='TRIA_DOWN', text="")
+ props.in_out = in_out
+ props.direction = 'DOWN'
+
+ if active_socket is not None:
+ # Mimicking property split.
+ layout.use_property_split = False
+ layout.use_property_decorate = False
+ layout_row = layout.row(align=True)
+ layout_split = layout_row.split(factor=0.4, align=True)
+
+ label_column = layout_split.column(align=True)
+ label_column.alignment = 'RIGHT'
+ # Menu to change the socket type.
+ label_column.label(text="Type")
+
+ property_row = layout_split.row(align=True)
+ props = property_row.operator_menu_enum(
+ "node.tree_socket_change_type",
+ "socket_type",
+ text=active_socket.bl_label if active_socket.bl_label else active_socket.bl_idname
+ )
+ props.in_out = in_out
+
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ layout.prop(active_socket, "name")
+ # Display descriptions only for Geometry Nodes, since it's only used in the modifier panel.
+ if tree.type == 'GEOMETRY':
+ layout.prop(active_socket, "description")
+ active_socket.draw(context, layout)
+
+
+class NODE_PT_node_tree_interface_inputs(NodeTreeInterfacePanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Group"
+ bl_label = "Inputs"
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ return snode.edit_tree is not None
+
+ def draw(self, context):
+ self.draw_socket_list(context, "IN", "inputs", "active_input")
+
+class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Group"
+ bl_label = "Outputs"
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ return snode.edit_tree is not None
+
+ def draw(self, context):
+ self.draw_socket_list(context, "OUT", "outputs", "active_output")
+
+
# Grease Pencil properties
class NODE_PT_annotation(AnnotationDataPanel, Panel):
bl_space_type = 'NODE_EDITOR'
@@ -752,6 +843,8 @@ classes = (
NODE_PT_quality,
NODE_PT_annotation,
NODE_UL_interface_sockets,
+ NODE_PT_node_tree_interface_inputs,
+ NODE_PT_node_tree_interface_outputs,
node_panel(EEVEE_MATERIAL_PT_settings),
node_panel(MATERIAL_PT_viewport),
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 1c21d27a117..df41445ee6f 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2765,23 +2765,27 @@ class VIEW3D_MT_make_single_user(Menu):
props = layout.operator("object.make_single_user", text="Object")
props.object = True
- props.obdata = props.material = props.animation = False
+ props.obdata = props.material = props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Object & Data")
props.object = props.obdata = True
- props.material = props.animation = False
+ props.material = props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Object & Data & Materials")
props.object = props.obdata = props.material = True
- props.animation = False
+ props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Materials")
props.material = True
- props.object = props.obdata = props.animation = False
+ props.object = props.obdata = props.animation = props.obdata_animation = False
props = layout.operator("object.make_single_user", text="Object Animation")
props.animation = True
- props.object = props.obdata = props.material = False
+ props.object = props.obdata = props.material = props.obdata_animation = False
+
+ props = layout.operator("object.make_single_user", text="Object Data Animation")
+ props.obdata_animation = props.obdata = True
+ props.object = props.material = props.animation = False
class VIEW3D_MT_object_convert(Menu):
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index b1ed1441245..d617cfab988 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -516,6 +516,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeCurveStar"),
NodeItem("GeometryNodeCurveSpiral"),
NodeItem("GeometryNodeCurveQuadraticBezier"),
+ NodeItem("GeometryNodeCurvePrimitiveQuadrilateral"),
NodeItem("GeometryNodeCurvePrimitiveBezierSegment"),
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
@@ -559,6 +560,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshUVSphere"),
]),
+
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),
NodeItem("GeometryNodePointInstance"),
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index 6c07708b5ef..14ab9f21424 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -50,8 +50,8 @@ bool id_can_have_animdata(const struct ID *id);
/* Get AnimData from the given ID-block */
struct AnimData *BKE_animdata_from_id(struct ID *id);
-/* Add AnimData to the given ID-block */
-struct AnimData *BKE_animdata_add_id(struct ID *id);
+/* Ensure AnimData is present in the ID-block (when supported). */
+struct AnimData *BKE_animdata_ensure_id(struct ID *id);
/* Set active action used by AnimData from the given ID-block */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 9d286b94b04..dffd70c077f 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 8
+#define BLENDER_FILE_SUBVERSION 11
/* 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_deform.h b/source/blender/blenkernel/BKE_deform.h
index 8b5fdf69bb0..0ab126a70ae 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -37,6 +37,19 @@ struct MLoop;
struct MPoly;
struct Object;
struct bDeformGroup;
+struct ID;
+
+bool BKE_object_supports_vertex_groups(const struct Object *ob);
+const struct ListBase *BKE_object_defgroup_list(const struct Object *ob);
+struct ListBase *BKE_object_defgroup_list_mutable(struct Object *ob);
+
+int BKE_object_defgroup_count(const struct Object *ob);
+int BKE_object_defgroup_active_index_get(const struct Object *ob);
+void BKE_object_defgroup_active_index_set(struct Object *ob, const int new_index);
+
+const struct ListBase *BKE_id_defgroup_list_get(const struct ID *id);
+struct ListBase *BKE_id_defgroup_list_get_mutable(struct ID *id);
+int BKE_id_defgroup_name_index(const struct ID *id, const char *name);
struct bDeformGroup *BKE_object_defgroup_new(struct Object *ob, const char *name);
void BKE_defgroup_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
@@ -171,6 +184,7 @@ void BKE_defvert_blend_write(struct BlendWriter *writer, int count, struct MDefo
void BKE_defvert_blend_read(struct BlendDataReader *reader,
int count,
struct MDeformVert *mdverts);
+void BKE_defbase_blend_write(struct BlendWriter *writer, const ListBase *defbase);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 9112877b5a3..ce7df62389f 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -24,7 +24,7 @@
* only concerned with low level operations on the #BMEditMesh structure.
*/
-#include "BKE_customdata.h"
+#include "DNA_customdata_types.h"
#include "bmesh.h"
#ifdef __cplusplus
@@ -44,34 +44,39 @@ struct Scene;
/**
* This structure is used for mesh edit-mode.
*
- * through this, you get access to both the edit #BMesh,
- * its tessellation, and various stuff that doesn't belong in the BMesh
- * struct itself.
+ * Through this, you get access to both the edit #BMesh, its tessellation,
+ * and various data that doesn't belong in the #BMesh struct itself
+ * (mostly related to mesh evaluation).
*
- * the entire derivedmesh and modifier system works with this structure,
- * and not BMesh. Mesh->edit_bmesh stores a pointer to this structure. */
+ * The entire modifier system works with this structure, and not #BMesh.
+ * #Mesh.edit_bmesh stores a pointer to this structure. */
typedef struct BMEditMesh {
struct BMesh *bm;
- /* we store tessellations as triplets of three loops,
- * which each define a triangle. */
+ /**
+ * Face triangulation (tessellation) is stored as triplets of three loops,
+ * which each define a triangle.
+ *
+ * \see #MLoopTri as the documentation gives useful hints that apply to this data too.
+ */
struct BMLoop *(*looptris)[3];
int tottri;
struct Mesh *mesh_eval_final, *mesh_eval_cage;
- /** Cached cage bounding box for selection. */
+ /** Cached cage bounding box of `mesh_eval_cage` for selection. */
struct BoundBox *bb_cage;
/** Evaluated mesh data-mask. */
CustomData_MeshMasks lastDataMask;
- /* Selection mode. */
+ /** Selection mode (#SCE_SELECT_VERTEX, #SCE_SELECT_EDGE & #SCE_SELECT_FACE). */
short selectmode;
+ /** The active material (assigned to newly created faces). */
short mat_nr;
- /* Temp variables for x-mirror editing. */
- int mirror_cdlayer; /* -1 is invalid */
+ /** Temp variables for x-mirror editing (-1 when the layer does not exist). */
+ int mirror_cdlayer;
/**
* ID data is older than edit-mode data.
@@ -94,11 +99,11 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em);
-BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate);
+BMEditMesh *BKE_editmesh_create(BMesh *bm);
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
-void BKE_editmesh_free_derivedmesh(BMEditMesh *em);
-void BKE_editmesh_free(BMEditMesh *em);
+void BKE_editmesh_free_derived_caches(BMEditMesh *em);
+void BKE_editmesh_free_data(BMEditMesh *em);
float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
struct BMEditMesh *em,
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index c8d6f18baf8..c79977752c9 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -337,10 +337,6 @@ class MeshComponent : public GeometryComponent {
private:
Mesh *mesh_ = nullptr;
GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
- /* Due to historical design choices, vertex group data is stored in the mesh, but the vertex
- * group names are stored on an object. Since we don't have an object here, we copy over the
- * names into this map. */
- blender::Map<std::string, int> vertex_group_names_;
public:
MeshComponent();
@@ -350,14 +346,8 @@ class MeshComponent : public GeometryComponent {
void clear();
bool has_mesh() const;
void replace(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
- void replace_mesh_but_keep_vertex_group_names(
- Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
Mesh *release();
- void copy_vertex_group_names_from_object(const struct Object &object);
- const blender::Map<std::string, int> &vertex_group_names() const;
- blender::Map<std::string, int> &vertex_group_names();
-
const Mesh *get_for_read() const;
Mesh *get_for_write();
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index c11c34cb312..1f9c3e766aa 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -154,17 +154,6 @@ bool BKE_gpencil_merge_materials(struct Object *ob,
/* statistics functions */
void BKE_gpencil_stats_update(struct bGPdata *gpd);
-/* Utilities for creating and populating GP strokes */
-/* - Number of values defining each point in the built-in data
- * buffers for primitives (e.g. 2D Monkey)
- */
-#define GP_PRIM_DATABUF_SIZE 5
-
-void BKE_gpencil_stroke_add_points(struct bGPDstroke *gps,
- const float *array,
- const int totpoints,
- const float mat[4][4]);
-
struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness);
struct bGPDstroke *BKE_gpencil_stroke_add(
struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head);
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 8fbc2112c77..33524e47473 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -325,6 +325,12 @@ struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl);
+int BKE_gpencil_time_modifier_cfra(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bGPDlayer *gpl,
+ const int cfra,
+ const bool is_render);
void BKE_gpencil_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase);
void BKE_gpencil_modifier_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb);
diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h
index aed8c44a031..b223d3872ff 100644
--- a/source/blender/blenkernel/BKE_mesh_types.h
+++ b/source/blender/blenkernel/BKE_mesh_types.h
@@ -27,6 +27,7 @@ typedef enum eMeshBatchDirtyMode {
BKE_MESH_BATCH_DIRTY_SELECT,
BKE_MESH_BATCH_DIRTY_SELECT_PAINT,
BKE_MESH_BATCH_DIRTY_SHADING,
+ BKE_MESH_BATCH_DIRTY_DEFORM,
BKE_MESH_BATCH_DIRTY_UVEDIT_ALL,
BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT,
} eMeshBatchDirtyMode;
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 61d26379052..5e977fbc0cd 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1458,7 +1458,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_VIEWER 1067
#define GEO_NODE_CURVE_PRIMITIVE_LINE 1068
#define GEO_NODE_CURVE_ENDPOINTS 1069
-#define GEO_NODE_CURVE_SAMPLE 1070
+#define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070
+#define GEO_NODE_CURVE_SAMPLE 1071
/** \} */
diff --git a/source/blender/blenkernel/BKE_node_ui_storage.hh b/source/blender/blenkernel/BKE_node_ui_storage.hh
deleted file mode 100644
index 4ec165aad8c..00000000000
--- a/source/blender/blenkernel/BKE_node_ui_storage.hh
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include <mutex>
-
-#include "BLI_hash.hh"
-#include "BLI_map.hh"
-#include "BLI_session_uuid.h"
-#include "BLI_set.hh"
-
-#include "DNA_ID.h"
-#include "DNA_customdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_session_uuid_types.h"
-
-#include "BKE_attribute.h"
-
-struct ModifierData;
-struct Object;
-struct bNode;
-struct bNodeTree;
-struct bContext;
-
-/**
- * Contains the context necessary to determine when to display settings for a certain node tree
- * that may be used for multiple modifiers and objects. The object name and modifier session UUID
- * are used instead of pointers because they are re-allocated between evaluations.
- *
- * \note This does not yet handle the context of nested node trees.
- */
-class NodeTreeEvaluationContext {
- private:
- std::string object_name_;
- SessionUUID modifier_session_uuid_;
-
- public:
- NodeTreeEvaluationContext(const Object &object, const ModifierData &modifier)
- {
- object_name_ = reinterpret_cast<const ID &>(object).name;
- modifier_session_uuid_ = modifier.session_uuid;
- }
-
- uint64_t hash() const
- {
- return blender::get_default_hash_2(object_name_, modifier_session_uuid_);
- }
-
- friend bool operator==(const NodeTreeEvaluationContext &a, const NodeTreeEvaluationContext &b)
- {
- return a.object_name_ == b.object_name_ &&
- BLI_session_uuid_is_equal(&a.modifier_session_uuid_, &b.modifier_session_uuid_);
- }
-};
-
-enum class NodeWarningType {
- Error,
- Warning,
- Info,
-};
-
-struct NodeWarning {
- NodeWarningType type;
- std::string message;
-};
-
-struct AvailableAttributeInfo {
- std::string name;
- AttributeDomain domain;
- CustomDataType data_type;
-
- uint64_t hash() const
- {
- return blender::get_default_hash(name);
- }
-
- friend bool operator==(const AvailableAttributeInfo &a, const AvailableAttributeInfo &b)
- {
- return a.name == b.name;
- }
-};
-
-struct NodeUIStorage {
- blender::Vector<NodeWarning> warnings;
- blender::Set<AvailableAttributeInfo> attribute_hints;
-};
-
-struct NodeTreeUIStorage {
- std::mutex mutex;
- blender::Map<NodeTreeEvaluationContext, blender::Map<std::string, NodeUIStorage>> context_map;
-
- /**
- * Attribute search uses this to store the fake info for the string typed into a node, in order
- * to pass the info to the execute callback that sets node socket values. This is mutable since
- * we can count on only one attribute search being open at a time, and there is no real data
- * stored here.
- */
- mutable AvailableAttributeInfo dummy_info_for_search;
-};
-
-const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C,
- const bNodeTree &ntree,
- const bNode &node);
-
-void BKE_nodetree_ui_storage_free_for_context(bNodeTree &ntree,
- const NodeTreeEvaluationContext &context);
-
-void BKE_nodetree_error_message_add(bNodeTree &ntree,
- const NodeTreeEvaluationContext &context,
- const bNode &node,
- const NodeWarningType type,
- std::string message);
-
-void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
- const NodeTreeEvaluationContext &context,
- const bNode &node,
- const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index cd66f026828..a16822fd7dd 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -70,10 +70,6 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
-void BKE_object_preview_geometry_set_add(struct Object *ob,
- const uint64_t key,
- struct GeometrySet *geometry_set);
-
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
struct HookGpencilModifierData *hmd);
@@ -378,6 +374,10 @@ 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);
+void BKE_object_data_eval_batch_cache_dirty_tag(struct Depsgraph *depsgraph,
+ struct ID *object_data);
+void BKE_object_data_eval_batch_cache_deform_tag(struct Depsgraph *depsgraph,
+ struct ID *object_data);
/* this function returns a superset of the scenes selection based on relationships */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 9792f819bf9..6d58e165ea3 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -124,14 +124,16 @@ bool BKE_scene_camera_switch_update(struct Scene *scene);
const char *BKE_scene_find_marker_name(const struct Scene *scene, int frame);
const char *BKE_scene_find_last_marker_name(const struct Scene *scene, int frame);
-int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int cfra);
+int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int frame);
/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
+float BKE_scene_ctime_get(const struct Scene *scene);
+float BKE_scene_frame_to_ctime(const struct Scene *scene, const int frame);
+
float BKE_scene_frame_get(const struct Scene *scene);
-float BKE_scene_frame_to_ctime(const struct Scene *scene, const float frame);
-void BKE_scene_frame_set(struct Scene *scene, double cfra);
+void BKE_scene_frame_set(struct Scene *scene, float frame);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(struct Scene *scene,
int flag);
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index d7b2dd181b4..f1c66de7773 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -343,6 +343,18 @@ class BezierSpline final : public Spline {
blender::MutableSpan<blender::float3> positions) const;
bool segment_is_vector(const int start_index) const;
+ /** See comment and diagram for #calculate_segment_insertion. */
+ struct InsertResult {
+ blender::float3 handle_prev;
+ blender::float3 left_handle;
+ blender::float3 position;
+ blender::float3 right_handle;
+ blender::float3 handle_next;
+ };
+ InsertResult calculate_segment_insertion(const int index,
+ const int next_index,
+ const float parameter);
+
private:
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index 70b8743bcd2..59b1c2b28d9 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -145,7 +145,7 @@ typedef struct StudioLight {
void BKE_studiolight_init(void);
void BKE_studiolight_free(void);
-void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4]);
+void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3]);
struct StudioLight *BKE_studiolight_find(const char *name, int flag);
struct StudioLight *BKE_studiolight_findindex(int index, int flag);
struct StudioLight *BKE_studiolight_find_default(int flag);
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index efac5d9097f..2973a432723 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -162,6 +162,13 @@ typedef enum UndoTypeFlags {
* \note Callback is still supposed to properly deal with a NULL context pointer.
*/
UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE = 1 << 0,
+
+ /**
+ * When the active undo step is of this type, it must be read before loading other undo steps.
+ *
+ * This is typically used for undo systems that store both before/after states.
+ */
+ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP = 1 << 1,
} UndoTypeFlags;
/* Expose since we need to perform operations on specific undo types (rarely). */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1db23002c1e..2c25b940578 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -215,7 +215,6 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
- intern/node_ui_storage.cc
intern/object.c
intern/object_deform.c
intern/object_dupli.cc
@@ -331,7 +330,6 @@ set(SRC
BKE_customdata_file.h
BKE_data_transfer.h
BKE_deform.h
- BKE_spline.hh
BKE_displist.h
BKE_displist_tangent.h
BKE_duplilist.h
@@ -399,7 +397,6 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
- BKE_node_ui_storage.hh
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@@ -423,6 +420,7 @@ set(SRC
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
+ BKE_spline.hh
BKE_studiolight.h
BKE_subdiv.h
BKE_subdiv_ccg.h
@@ -767,6 +765,7 @@ add_dependencies(bf_blenkernel bf_dna)
if(WITH_GTESTS)
set(TEST_SRC
+ intern/action_test.cc
intern/armature_test.cc
intern/cryptomatte_test.cc
intern/fcurve_test.cc
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 46dec073bab..ba8cf8debe9 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -900,7 +900,7 @@ static Mesh *prepare_geometry_set_for_mesh_modifier(Mesh *mesh, GeometrySet &r_g
{
/* Add the mesh to the geometry set. */
MeshComponent &mesh_component = r_geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace_mesh_but_keep_vertex_group_names(mesh, GeometryOwnershipType::Editable);
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
}
{
/* Combine mesh and all instances into a single mesh that can be passed to the modifier. */
@@ -948,8 +948,7 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
/* Replace only the mesh rather than the whole component, because the entire #MeshComponent
* might have been replaced by data from a different object in the node tree, which means the
* component contains vertex group name data for that object that should not be removed. */
- mesh_component.replace_mesh_but_keep_vertex_group_names(input_mesh,
- GeometryOwnershipType::Editable);
+ mesh_component.replace(input_mesh, GeometryOwnershipType::Editable);
/* Let the modifier change the geometry set. */
mti->modifyGeometrySet(md, &mectx, &geometry_set);
@@ -993,12 +992,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
GeometrySet geometry_set_final;
- /* Add the initial mesh component, with a copy of the vertex group names from the object,
- * since they need to be stored in the geometry set for evaluation. */
- MeshComponent &initial_mesh_component =
- geometry_set_final.get_component_for_write<MeshComponent>();
- initial_mesh_component.copy_vertex_group_names_from_object(*ob);
-
BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
/* Deformed vertex locations array. Deform only modifier need this type of
@@ -1602,12 +1595,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
GeometrySet geometry_set_final;
- /* Add the initial mesh component, with a copy of the vertex group names from the object,
- * since they need to be stored in the geometry set for evaluation. */
- MeshComponent &initial_mesh_component =
- geometry_set_final.get_component_for_write<MeshComponent>();
- initial_mesh_component.copy_vertex_group_names_from_object(*ob);
-
/* Deformed vertex locations array. Deform only modifier need this type of
* float array rather than MVert*. Tracked along with mesh_final as an
* optimization to avoid copying coordinates back and forth if there are
@@ -1951,8 +1938,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
/* Add the final mesh as read-only non-owning component to the geometry set. */
MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>();
- mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_eval,
- GeometryOwnershipType::ReadOnly);
+ mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly);
ob->runtime.geometry_set_eval = geometry_set_eval;
ob->runtime.mesh_deform_eval = mesh_deform_eval;
@@ -1990,7 +1976,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
BKE_sculpt_update_object_before_eval(obedit);
}
- BKE_editmesh_free_derivedmesh(em);
+ BKE_editmesh_free_derived_caches(em);
Mesh *me_cage;
Mesh *me_final;
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 13ca5ecf23c..d55f023d209 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -497,9 +497,8 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
}
/* Reconstruct group channel pointers.
- * Assumes that the channels are still in the proper order, i.e. that channels of the same group
- * are adjacent in the act->channels list. It also assumes that the groups
- * referred to by the FCurves are already in act->groups.
+ * Assumes that the groups referred to by the FCurves are already in act->groups.
+ * Reorders the main channel list to match group order.
*/
void BKE_action_groups_reconstruct(bAction *act)
{
@@ -514,23 +513,30 @@ void BKE_action_groups_reconstruct(bAction *act)
BLI_listbase_clear(&group->channels);
}
- bActionGroup *grp;
- bActionGroup *last_grp = NULL;
- LISTBASE_FOREACH (FCurve *, fcurve, &act->curves) {
- if (fcurve->grp == NULL) {
- continue;
- }
+ /* Sort the channels into the group lists, destroying the act->curves list. */
+ ListBase ungrouped = {NULL, NULL};
- grp = fcurve->grp;
- if (last_grp != grp) {
- /* If this is the first time we see this group, this must be the first channel. */
- grp->channels.first = fcurve;
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcurve, &act->curves) {
+ if (fcurve->grp) {
+ BLI_assert(BLI_findindex(&act->groups, fcurve->grp) >= 0);
+
+ BLI_addtail(&fcurve->grp->channels, fcurve);
+ }
+ else {
+ BLI_addtail(&ungrouped, fcurve);
}
+ }
+
+ /* Recombine into the main list. */
+ BLI_listbase_clear(&act->curves);
- /* This is the last channel, until it's overwritten by a later iteration. */
- grp->channels.last = fcurve;
- last_grp = grp;
+ LISTBASE_FOREACH (bActionGroup *, group, &act->groups) {
+ /* Copy the list header to preserve the pointers in the group. */
+ ListBase tmp = group->channels;
+ BLI_movelisttolist(&act->curves, &tmp);
}
+
+ BLI_movelisttolist(&act->curves, &ungrouped);
}
/* Remove the given channel from all groups */
diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc
new file mode 100644
index 00000000000..c02eca966ad
--- /dev/null
+++ b/source/blender/blenkernel/intern/action_test.cc
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+#include "BKE_action.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+
+#include "BLI_listbase.h"
+
+#include "testing/testing.h"
+
+namespace blender::bke::tests {
+
+TEST(action_groups, ReconstructGroupsWithReordering)
+{
+ /* Construct an Action with three groups. */
+ bAction action = {{nullptr}};
+ FCurve groupAcurve1 = {nullptr};
+ FCurve groupAcurve2 = {nullptr};
+ FCurve groupBcurve1 = {nullptr};
+ FCurve groupBcurve2 = {nullptr};
+ FCurve groupBcurve3 = {nullptr};
+ /* Group C has no curves intentionally. */
+ FCurve groupDcurve1 = {nullptr};
+ FCurve groupDcurve2 = {nullptr};
+
+ groupAcurve1.rna_path = (char *)"groupAcurve1";
+ groupAcurve2.rna_path = (char *)"groupAcurve2";
+ groupBcurve1.rna_path = (char *)"groupBcurve1";
+ groupBcurve2.rna_path = (char *)"groupBcurve2";
+ groupDcurve1.rna_path = (char *)"groupDcurve1";
+ groupBcurve3.rna_path = (char *)"groupBcurve3";
+ groupDcurve2.rna_path = (char *)"groupDcurve2";
+
+ BLI_addtail(&action.curves, &groupAcurve1);
+ BLI_addtail(&action.curves, &groupAcurve2);
+ BLI_addtail(&action.curves, &groupBcurve1);
+ BLI_addtail(&action.curves, &groupBcurve2);
+ BLI_addtail(&action.curves, &groupDcurve1);
+ BLI_addtail(&action.curves, &groupBcurve3); /* <-- The error that should be corrected. */
+ BLI_addtail(&action.curves, &groupDcurve2);
+
+ /* Introduce another error type, by changing some `prev` pointers. */
+ groupBcurve1.prev = nullptr;
+ groupBcurve3.prev = &groupBcurve2;
+ groupDcurve1.prev = &groupBcurve3;
+
+ bActionGroup groupA = {nullptr};
+ bActionGroup groupB = {nullptr};
+ bActionGroup groupC = {nullptr};
+ bActionGroup groupD = {nullptr};
+ strcpy(groupA.name, "groupA");
+ strcpy(groupB.name, "groupB");
+ strcpy(groupC.name, "groupC");
+ strcpy(groupD.name, "groupD");
+
+ BLI_addtail(&action.groups, &groupA);
+ BLI_addtail(&action.groups, &groupB);
+ BLI_addtail(&action.groups, &groupC);
+ BLI_addtail(&action.groups, &groupD);
+
+ groupAcurve1.grp = &groupA;
+ groupAcurve2.grp = &groupA;
+ groupBcurve1.grp = &groupB;
+ groupBcurve2.grp = &groupB;
+ groupBcurve3.grp = &groupB;
+ groupDcurve1.grp = &groupD;
+ groupDcurve2.grp = &groupD;
+
+ groupA.channels.first = &groupAcurve1;
+ groupA.channels.last = &groupAcurve2;
+ groupB.channels.first = &groupBcurve1;
+ groupB.channels.last = &groupBcurve3; /* The last channel in group B, after group C curve 1. */
+ groupD.channels.first = &groupDcurve1;
+ groupD.channels.last = &groupDcurve2;
+
+ EXPECT_EQ(groupA.channels.first, &groupAcurve1);
+ EXPECT_EQ(groupA.channels.last, &groupAcurve2);
+ EXPECT_EQ(groupB.channels.first, &groupBcurve1);
+ EXPECT_EQ(groupB.channels.last, &groupBcurve3);
+ EXPECT_EQ(groupC.channels.first, nullptr);
+ EXPECT_EQ(groupC.channels.last, nullptr);
+ EXPECT_EQ(groupD.channels.first, &groupDcurve1);
+ EXPECT_EQ(groupD.channels.last, &groupDcurve2);
+
+ BKE_action_groups_reconstruct(&action);
+
+ EXPECT_EQ(action.curves.first, &groupAcurve1);
+ EXPECT_EQ(action.curves.last, &groupDcurve2);
+
+ EXPECT_EQ(groupA.prev, nullptr);
+ EXPECT_EQ(groupB.prev, &groupA);
+ EXPECT_EQ(groupC.prev, &groupB);
+ EXPECT_EQ(groupD.prev, &groupC);
+
+ EXPECT_EQ(groupA.next, &groupB);
+ EXPECT_EQ(groupB.next, &groupC);
+ EXPECT_EQ(groupC.next, &groupD);
+ EXPECT_EQ(groupD.next, nullptr);
+
+ EXPECT_EQ(groupA.channels.first, &groupAcurve1);
+ EXPECT_EQ(groupA.channels.last, &groupAcurve2);
+ EXPECT_EQ(groupB.channels.first, &groupBcurve1);
+ EXPECT_EQ(groupB.channels.last, &groupBcurve3);
+ EXPECT_EQ(groupC.channels.first, nullptr);
+ EXPECT_EQ(groupC.channels.last, nullptr);
+ EXPECT_EQ(groupD.channels.first, &groupDcurve1);
+ EXPECT_EQ(groupD.channels.last, &groupDcurve2);
+
+ EXPECT_EQ(groupAcurve1.prev, nullptr);
+ EXPECT_EQ(groupAcurve2.prev, &groupAcurve1);
+ EXPECT_EQ(groupBcurve1.prev, &groupAcurve2);
+ EXPECT_EQ(groupBcurve2.prev, &groupBcurve1);
+ EXPECT_EQ(groupBcurve3.prev, &groupBcurve2);
+ EXPECT_EQ(groupDcurve1.prev, &groupBcurve3);
+ EXPECT_EQ(groupDcurve2.prev, &groupDcurve1);
+
+ EXPECT_EQ(groupAcurve1.next, &groupAcurve2);
+ EXPECT_EQ(groupAcurve2.next, &groupBcurve1);
+ EXPECT_EQ(groupBcurve1.next, &groupBcurve2);
+ EXPECT_EQ(groupBcurve2.next, &groupBcurve3);
+ EXPECT_EQ(groupBcurve3.next, &groupDcurve1);
+ EXPECT_EQ(groupDcurve1.next, &groupDcurve2);
+ EXPECT_EQ(groupDcurve2.next, nullptr);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 4766fc6096b..7e4ab754500 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -89,16 +89,16 @@ bool id_can_have_animdata(const ID *id)
return id_type_can_have_animdata(GS(id->name));
}
-/* Get AnimData from the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate.
+/**
+ * Get #AnimData from the given ID-block.
*/
AnimData *BKE_animdata_from_id(ID *id)
{
- /* only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and extract the
- * AnimData that way
- */
+ /* In order for this to work, we assume that the #AnimData pointer is stored
+ * immediately after the given ID-block in the struct, as per IdAdtTemplate. */
+
+ /* Only some ID-blocks have this info for now, so we cast the types that do
+ * to be of type IdAdtTemplate, and add the AnimData to it using the template. */
if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
return iat->adt;
@@ -106,16 +106,16 @@ AnimData *BKE_animdata_from_id(ID *id)
return NULL;
}
-/* Add AnimData to the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate. Also note that
+/**
+ * Ensure #AnimData exists in the given ID-block (when supported).
*/
-AnimData *BKE_animdata_add_id(ID *id)
+AnimData *BKE_animdata_ensure_id(ID *id)
{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and add the AnimData
- * to it using the template
- */
+ /* In order for this to work, we assume that the #AnimData pointer is stored
+ * immediately after the given ID-block in the struct, as per IdAdtTemplate. */
+
+ /* Only some ID-blocks have this info for now, so we cast the types that do
+ * to be of type IdAdtTemplate, and add the AnimData to it using the template. */
if (id_can_have_animdata(id)) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
@@ -667,7 +667,7 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
/* get animdata from src, and create for destination (if needed) */
srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_animdata_add_id(dstID);
+ dstAdt = BKE_animdata_ensure_id(dstID);
if (ELEM(NULL, srcAdt, dstAdt)) {
if (G.debug & G_DEBUG) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 22d6cfba893..b8ed519e8d1 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2843,7 +2843,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
* hopefully this is OK. */
BKE_pose_ensure(NULL, ob, arm, true);
- ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ ctime = BKE_scene_ctime_get(scene); /* not accurate... */
/* In edit-mode or rest-position we read the data from the bones. */
if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index bca5503c8d2..5e9259f05bb 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -47,6 +47,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
@@ -485,7 +486,7 @@ static void armature_deform_coords_impl(const Object *ob_arm,
int defbase_len = 0; /* safety for vertexgroup index overflow */
int i, dverts_len = 0; /* safety for vertexgroup overflow */
bool use_dverts = false;
- int armature_def_nr;
+ int armature_def_nr = -1;
int cd_dvert_offset = -1;
/* in editmode, or not an armature */
@@ -500,11 +501,11 @@ static void armature_deform_coords_impl(const Object *ob_arm,
BLI_assert(0);
}
- /* get the def_nr for the overall armature vertex group if present */
- armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name);
-
if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
- defbase_len = BLI_listbase_count(&ob_target->defbase);
+ /* get the def_nr for the overall armature vertex group if present */
+ armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name);
+
+ defbase_len = BKE_object_defgroup_count(ob_target);
if (ob_target->type == OB_MESH) {
if (em_target == NULL) {
@@ -551,7 +552,8 @@ static void armature_deform_coords_impl(const Object *ob_arm,
*
* - Check whether keeping this consistent across frames gives speedup.
*/
- for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob_target);
+ for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name);
/* exclude non-deforming bones */
if (pchan_from_defbase[i]) {
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 0a195f2ba55..35ae2d2dbef 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -828,7 +828,7 @@ void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *ob
{
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
BLI_assert(object->type == OB_ARMATURE);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */
bArmature *armature = (bArmature *)object->data;
if (armature->flag & ARM_RESTPOS) {
return;
@@ -869,7 +869,7 @@ void BKE_pose_eval_bone(struct Depsgraph *depsgraph, Scene *scene, Object *objec
else {
if ((pchan->flag & POSE_DONE) == 0) {
/* TODO(sergey): Use time source node for time. */
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ float ctime = BKE_scene_ctime_get(scene); /* not accurate... */
BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1);
}
}
@@ -897,7 +897,7 @@ void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
}
else {
if ((pchan->flag & POSE_DONE) == 0) {
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ float ctime = BKE_scene_ctime_get(scene); /* not accurate... */
BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1);
}
}
@@ -981,7 +981,7 @@ void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph,
DEG_debug_print_eval_subdata(
depsgraph, __func__, object->id.name, object, "rootchan", rootchan->name, rootchan);
BLI_assert(object->type == OB_ARMATURE);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */
if (armature->flag & ARM_RESTPOS) {
return;
}
@@ -1002,7 +1002,7 @@ void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph,
DEG_debug_print_eval_subdata(
depsgraph, __func__, object->id.name, object, "rootchan", rootchan->name, rootchan);
BLI_assert(object->type == OB_ARMATURE);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */
if (armature->flag & ARM_RESTPOS) {
return;
}
@@ -1031,7 +1031,7 @@ void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, Scene *scene, Object *ob
bPose *pose = object->pose;
BLI_assert(pose != NULL);
UNUSED_VARS_NDEBUG(pose);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ const float ctime = BKE_scene_ctime_get(scene); /* not accurate... */
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
BLI_assert(object->type == OB_ARMATURE);
/* Release the IK tree. */
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index f31d8f5ade7..912cc66920e 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -128,7 +128,7 @@ static void setup_app_userdef(BlendFileData *bfd)
}
/**
- * Context matching, handle no-ui case
+ * Context matching, handle no-UI case.
*
* \note this is called on Undo so any slow conversion functions here
* should be avoided or check (mode != LOAD_UNDO).
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 30e9ae39b67..eaba5d33a20 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -314,7 +314,7 @@ bool BKE_cachefile_filepath_get(const Main *bmain,
if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
Scene *scene = DEG_get_evaluated_scene(depsgraph);
- const float ctime = BKE_scene_frame_get(scene);
+ const float ctime = BKE_scene_ctime_get(scene);
const float fps = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
const float frame = BKE_cachefile_time_offset(cache_file, ctime, fps);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 2bca3f5da76..8678a659c0a 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -597,7 +597,7 @@ static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexC
Cloth *cloth = clmd->clothObject;
if (clmd->clothObject) {
- /* inverse matrix is not uptodate... */
+ /* Inverse matrix is not up to date. */
invert_m4_m4(ob->imat, ob->obmat);
for (i = 0; i < cloth->mvert_num; i++) {
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index aec849ebf59..605061570b8 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -1437,7 +1437,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
if (vgroup_name) {
mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
if (mdef) {
- vg_idx = BKE_object_defgroup_name_index(ob_dst, vgroup_name);
+ vg_idx = BKE_id_defgroup_name_index(&me_dst->id, vgroup_name);
}
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 19840a70bf0..f7ef84728b6 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -29,6 +29,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -64,7 +66,9 @@ bDeformGroup *BKE_object_defgroup_new(Object *ob, const char *name)
BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
- BLI_addtail(&ob->defbase, defgroup);
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
+ BLI_addtail(defbase, defgroup);
BKE_object_defgroup_unique_name(defgroup, ob);
BKE_object_batch_cache_dirty_tag(ob);
@@ -484,18 +488,120 @@ void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int
}
}
+bool BKE_object_supports_vertex_groups(const Object *ob)
+{
+ const ID *id = (const ID *)ob->data;
+ if (id == NULL) {
+ return false;
+ }
+
+ return ELEM(GS(id->name), ID_ME, ID_LT, ID_GD);
+}
+
+const ListBase *BKE_id_defgroup_list_get(const ID *id)
+{
+ switch (GS(id->name)) {
+ case ID_ME: {
+ const Mesh *me = (const Mesh *)id;
+ return &me->vertex_group_names;
+ }
+ case ID_LT: {
+ const Lattice *lt = (const Lattice *)id;
+ return &lt->vertex_group_names;
+ }
+ case ID_GD: {
+ const bGPdata *gpd = (const bGPdata *)id;
+ return &gpd->vertex_group_names;
+ }
+ default: {
+ BLI_assert_unreachable();
+ }
+ }
+ return NULL;
+}
+
+static const int *object_defgroup_active_index_get_p(const Object *ob)
+{
+ BLI_assert(BKE_object_supports_vertex_groups(ob));
+ switch (ob->type) {
+ case OB_MESH: {
+ const Mesh *mesh = (const Mesh *)ob->data;
+ return &mesh->vertex_group_active_index;
+ }
+ case OB_LATTICE: {
+ const Lattice *lattice = (const Lattice *)ob->data;
+ return &lattice->vertex_group_active_index;
+ }
+ case OB_GPENCIL: {
+ const bGPdata *gpd = (const bGPdata *)ob->data;
+ return &gpd->vertex_group_active_index;
+ }
+ }
+ return NULL;
+}
+
+ListBase *BKE_id_defgroup_list_get_mutable(ID *id)
+{
+ /* Cast away const just for the accessor. */
+ return (ListBase *)BKE_id_defgroup_list_get(id);
+}
+
bDeformGroup *BKE_object_defgroup_find_name(const Object *ob, const char *name)
{
- return (name && name[0] != '\0') ?
- BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)) :
- NULL;
+ if (name == NULL || name[0] == '\0') {
+ return NULL;
+ }
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ return BLI_findstring(defbase, name, offsetof(bDeformGroup, name));
+}
+
+int BKE_id_defgroup_name_index(const ID *id, const char *name)
+{
+ if (name == NULL || name[0] == '\0') {
+ return -1;
+ }
+ const ListBase *defbase = BKE_id_defgroup_list_get(id);
+ return BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
+}
+
+const ListBase *BKE_object_defgroup_list(const Object *ob)
+{
+ BLI_assert(BKE_object_supports_vertex_groups(ob));
+ return BKE_id_defgroup_list_get((const ID *)ob->data);
}
int BKE_object_defgroup_name_index(const Object *ob, const char *name)
{
- return (name && name[0] != '\0') ?
- BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) :
- -1;
+ return BKE_id_defgroup_name_index((ID *)ob->data, name);
+}
+
+ListBase *BKE_object_defgroup_list_mutable(Object *ob)
+{
+ BLI_assert(BKE_object_supports_vertex_groups(ob));
+ return BKE_id_defgroup_list_get_mutable((ID *)ob->data);
+}
+
+int BKE_object_defgroup_count(const Object *ob)
+{
+ return BLI_listbase_count(BKE_object_defgroup_list(ob));
+}
+
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
+int BKE_object_defgroup_active_index_get(const Object *ob)
+{
+ return *object_defgroup_active_index_get_p(ob);
+}
+
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
+void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
+{
+ /* Cast away const just for the accessor. */
+ int *index = (int *)object_defgroup_active_index_get_p(ob);
+ *index = new_index;
}
/**
@@ -503,7 +609,8 @@ int BKE_object_defgroup_name_index(const Object *ob, const char *name)
*/
int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default)
{
- int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ int defbase_tot = *flip_map_len = BLI_listbase_count(defbase);
if (defbase_tot == 0) {
return NULL;
@@ -517,7 +624,7 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo
map[i] = -1;
}
- for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
+ for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
if (map[i] == -1) { /* may be calculated previously */
/* in case no valid value is found, use this */
@@ -547,7 +654,8 @@ int *BKE_object_defgroup_flip_map_single(const Object *ob,
const bool use_default,
int defgroup)
{
- int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ int defbase_tot = *flip_map_len = BLI_listbase_count(defbase);
if (defbase_tot == 0) {
return NULL;
@@ -561,7 +669,7 @@ int *BKE_object_defgroup_flip_map_single(const Object *ob,
map[i] = use_default ? i : -1;
}
- dg = BLI_findlink(&ob->defbase, defgroup);
+ dg = BLI_findlink(defbase, defgroup);
BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
@@ -578,7 +686,8 @@ int *BKE_object_defgroup_flip_map_single(const Object *ob,
int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_default)
{
- bDeformGroup *dg = BLI_findlink(&ob->defbase, index);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *dg = BLI_findlink(defbase, index);
int flip_index = -1;
if (dg) {
@@ -595,9 +704,10 @@ int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_d
static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *ob)
{
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
bDeformGroup *curdef;
- for (curdef = ob->defbase.first; curdef; curdef = curdef->next) {
+ for (curdef = defbase->first; curdef; curdef = curdef->next) {
if (dg != curdef) {
if (STREQ(curdef->name, name)) {
return true;
@@ -1189,7 +1299,10 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
{
int idx_src;
int idx_dst;
- int tot_dst = BLI_listbase_count(&ob_dst->defbase);
+ const ListBase *src_list = BKE_object_defgroup_list(ob_src);
+ ListBase *dst_defbase = BKE_object_defgroup_list_mutable(ob_dst);
+
+ int tot_dst = BLI_listbase_count(dst_defbase);
const size_t elem_size = sizeof(*((MDeformVert *)NULL));
@@ -1218,7 +1331,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
}
else if (use_delete && idx_dst > idx_src) {
while (idx_dst-- > idx_src) {
- BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last);
+ BKE_object_defgroup_remove(ob_dst, dst_defbase->last);
}
}
if (r_map) {
@@ -1255,7 +1368,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
if (use_delete) {
/* Remove all unused dst vgroups first, simpler in this case. */
- for (dg_dst = ob_dst->defbase.first; dg_dst;) {
+ for (dg_dst = dst_defbase->first; dg_dst;) {
bDeformGroup *dg_dst_next = dg_dst->next;
if (BKE_object_defgroup_name_index(ob_src, dg_dst->name) == -1) {
@@ -1265,7 +1378,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
}
}
- for (idx_src = 0, dg_src = ob_src->defbase.first; idx_src < num_layers_src;
+ for (idx_src = 0, dg_src = src_list->first; idx_src < num_layers_src;
idx_src++, dg_src = dg_src->next) {
if (!use_layers_src[idx_src]) {
continue;
@@ -1274,7 +1387,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
if ((idx_dst = BKE_object_defgroup_name_index(ob_dst, dg_src->name)) == -1) {
if (use_create) {
BKE_object_defgroup_add_name(ob_dst, dg_src->name);
- idx_dst = ob_dst->actdef - 1;
+ idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
}
else {
/* If we are not allowed to create missing dst vgroups, just skip matching src one. */
@@ -1340,8 +1453,12 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
* This implies we may have to handle data layout itself while having NULL data itself,
* and even have to support NULL data_src in transfer data code
* (we always create a data_dst, though).
+ *
+ * Note: Above comment is outdated, but this function was written when that was true.
*/
- if (BLI_listbase_is_empty(&ob_src->defbase)) {
+
+ const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
+ if (BLI_listbase_is_empty(src_defbase)) {
if (use_delete) {
BKE_object_defgroup_remove_all(ob_dst);
}
@@ -1361,35 +1478,37 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
if (fromlayers >= 0) {
idx_src = fromlayers;
- if (idx_src >= BLI_listbase_count(&ob_src->defbase)) {
+ if (idx_src >= BLI_listbase_count(src_defbase)) {
/* This can happen when vgroups are removed from source object...
* Remapping would be really tricky here, we'd need to go over all objects in
* Main every time we delete a vgroup... for now, simpler and safer to abort. */
return false;
}
}
- else if ((idx_src = ob_src->actdef - 1) == -1) {
+ else if ((idx_src = BKE_object_defgroup_active_index_get(ob_src) - 1) == -1) {
return false;
}
if (tolayers >= 0) {
/* NOTE: in this case we assume layer exists! */
idx_dst = tolayers;
- BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase));
+ const ListBase *dst_defbase = BKE_object_defgroup_list(ob_dst);
+ BLI_assert(idx_dst < BLI_listbase_count(dst_defbase));
+ UNUSED_VARS_NDEBUG(dst_defbase);
}
else if (tolayers == DT_LAYERS_ACTIVE_DST) {
- if ((idx_dst = ob_dst->actdef - 1) == -1) {
+ if ((idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1) == -1) {
bDeformGroup *dg_src;
if (!use_create) {
return true;
}
- dg_src = BLI_findlink(&ob_src->defbase, idx_src);
+ dg_src = BLI_findlink(src_defbase, idx_src);
BKE_object_defgroup_add_name(ob_dst, dg_src->name);
- idx_dst = ob_dst->actdef - 1;
+ idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
}
}
else if (tolayers == DT_LAYERS_INDEX_DST) {
- int num = BLI_listbase_count(&ob_src->defbase);
+ int num = BLI_listbase_count(src_defbase);
idx_dst = idx_src;
if (num <= idx_dst) {
if (!use_create) {
@@ -1402,13 +1521,13 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
}
}
else if (tolayers == DT_LAYERS_NAME_DST) {
- bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src);
+ bDeformGroup *dg_src = BLI_findlink(src_defbase, idx_src);
if ((idx_dst = BKE_object_defgroup_name_index(ob_dst, dg_src->name)) == -1) {
if (!use_create) {
return true;
}
BKE_object_defgroup_add_name(ob_dst, dg_src->name);
- idx_dst = ob_dst->actdef - 1;
+ idx_dst = BKE_object_defgroup_active_index_get(ob_dst) - 1;
}
}
else {
@@ -1531,6 +1650,13 @@ void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight)
/** \name .blend file I/O
* \{ */
+void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
+{
+ LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) {
+ BLO_write_struct(writer, bDeformGroup, defgroup);
+ }
+}
+
void BKE_defvert_blend_write(BlendWriter *writer, int count, MDeformVert *dvlist)
{
if (dvlist == NULL) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 6091e774d4a..52996e3bcc7 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -3818,7 +3818,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
ob,
true,
SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene),
+ BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false);
numOfVerts_p = mesh_p->totvert;
@@ -3834,7 +3834,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
ob,
true,
SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene),
+ BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
mesh_c = dynamicPaint_brush_mesh_get(brush);
numOfVerts_c = mesh_c->totvert;
@@ -3894,7 +3894,7 @@ static void dynamicPaint_brushObjectCalculateVelocity(
ob,
false,
SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene),
+ BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
@@ -3906,7 +3906,7 @@ static void dynamicPaint_brushObjectCalculateVelocity(
ob,
false,
SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene),
+ BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
/* calculate speed */
@@ -6271,7 +6271,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
brushObj,
true,
SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene),
+ BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
}
@@ -6312,7 +6312,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
brushObj,
true,
SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene),
+ BKE_scene_ctime_get(scene),
eModifierType_DynamicPaint);
}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 2eb6b488da2..9cae74e4e9a 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,15 +39,14 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_object.h"
-BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
+/**
+ * \note The caller is responsible for ensuring triangulation data,
+ * typically by calling #BKE_editmesh_looptri_calc.
+ */
+BMEditMesh *BKE_editmesh_create(BMesh *bm)
{
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
-
em->bm = bm;
- if (do_tessellate) {
- BKE_editmesh_looptri_calc(em);
- }
-
return em;
}
@@ -209,7 +208,7 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
});
}
-void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
+void BKE_editmesh_free_derived_caches(BMEditMesh *em)
{
if (em->mesh_eval_cage) {
BKE_id_free(NULL, em->mesh_eval_cage);
@@ -223,9 +222,9 @@ void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
}
/* Does not free the #BMEditMesh struct itself. */
-void BKE_editmesh_free(BMEditMesh *em)
+void BKE_editmesh_free_data(BMEditMesh *em)
{
- BKE_editmesh_free_derivedmesh(em);
+ BKE_editmesh_free_derived_caches(em);
if (em->looptris) {
MEM_freeN(em->looptris);
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index e5e639fa3f1..da4ea742656 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -25,6 +25,7 @@
#include "DNA_defs.h"
#include "DNA_meshdata_types.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_tangent.h"
#include "BKE_mesh.h"
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 947417af55d..2b48683a3a8 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1283,10 +1283,10 @@ static void compute_obstaclesemission(Scene *scene,
# endif
/* Update frame time, this is considering current subframe fraction
* BLI_mutex_lock() called in manta_step(), so safe to update subframe here
- * TODO(sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph)
+ * TODO(sebbas): Using BKE_scene_ctime_get(scene) instead of new DEG_get_ctime(depsgraph)
* as subframes don't work with the latter yet. */
BKE_object_modifier_update_subframe(
- depsgraph, scene, effecobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid);
+ depsgraph, scene, effecobj, true, 5, BKE_scene_ctime_get(scene), eModifierType_Fluid);
if (subframes) {
obstacles_from_mesh(effecobj, fds, fes, &bb_temp, subframe_dt);
@@ -1616,7 +1616,7 @@ static void emit_from_particles(Object *flow_ob,
}
/* `DEG_get_ctime(depsgraph)` does not give sub-frame time. */
- state.time = BKE_scene_frame_get(scene);
+ state.time = BKE_scene_ctime_get(scene);
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
continue;
@@ -2820,10 +2820,10 @@ static void compute_flowsemission(Scene *scene,
# endif
/* Update frame time, this is considering current subframe fraction
* BLI_mutex_lock() called in manta_step(), so safe to update subframe here
- * TODO(sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph)
+ * TODO(sebbas): Using BKE_scene_ctime_get(scene) instead of new DEG_get_ctime(depsgraph)
* as subframes don't work with the latter yet. */
BKE_object_modifier_update_subframe(
- depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid);
+ depsgraph, scene, flowobj, true, 5, BKE_scene_ctime_get(scene), eModifierType_Fluid);
/* Emission from particles. */
if (ffs->source == FLUID_FLOW_SOURCE_PARTICLES) {
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 28e46aab732..af500ab3427 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -53,7 +53,6 @@ GeometryComponent *MeshComponent::copy() const
if (mesh_ != nullptr) {
new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
new_component->ownership_ = GeometryOwnershipType::Owned;
- new_component->vertex_group_names_ = blender::Map(vertex_group_names_);
}
return new_component;
}
@@ -67,7 +66,6 @@ void MeshComponent::clear()
}
mesh_ = nullptr;
}
- vertex_group_names_.clear();
}
bool MeshComponent::has_mesh() const
@@ -84,23 +82,6 @@ void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to
- * be able to replace the mesh data without losing the vertex group names, which may have come
- * from another object. */
-void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh,
- GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- if (mesh_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, mesh_);
- }
- mesh_ = nullptr;
- }
- mesh_ = mesh;
- ownership_ = ownership;
-}
-
/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
* mesh (if the component was responsible before). */
Mesh *MeshComponent::release()
@@ -111,28 +92,6 @@ Mesh *MeshComponent::release()
return mesh;
}
-void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
-{
- BLI_assert(this->is_mutable());
- vertex_group_names_.clear();
- int index = 0;
- LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) {
- vertex_group_names_.add(group->name, index);
- index++;
- }
-}
-
-const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const
-{
- return vertex_group_names_;
-}
-
-/* This is only exposed for the internal attribute API. */
-blender::Map<std::string, int> &MeshComponent::vertex_group_names()
-{
- return vertex_group_names_;
-}
-
/* Get the mesh from this component. This method can be used by multiple threads at the same
* time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
const Mesh *MeshComponent::get_for_read() const
@@ -864,8 +823,8 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
- const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
- attribute_name, -1);
+ const int vertex_group_index = BLI_findstringindex(
+ &mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name));
if (vertex_group_index < 0) {
return {};
}
@@ -889,8 +848,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
if (mesh == nullptr) {
return {};
}
- const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
- attribute_name, -1);
+
+ const int vertex_group_index = BLI_findstringindex(
+ &mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name));
if (vertex_group_index < 0) {
return {};
}
@@ -913,13 +873,13 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+ Mesh *mesh = mesh_component.get_for_write();
- const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as(
- attribute_name, -1);
+ const int vertex_group_index = BLI_findstringindex(
+ &mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name));
if (vertex_group_index < 0) {
return false;
}
- Mesh *mesh = mesh_component.get_for_write();
if (mesh == nullptr) {
return true;
}
@@ -938,14 +898,14 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- for (const auto item : mesh_component.vertex_group_names().items()) {
- const StringRefNull name = item.key;
- const int vertex_group_index = item.value;
- if (vertex_group_index >= 0) {
- AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT};
- if (!callback(name, meta_data)) {
- return false;
- }
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return true;
+ }
+
+ LISTBASE_FOREACH (const bDeformGroup *, group, &mesh->vertex_group_names) {
+ if (!callback(group->name, {ATTR_DOMAIN_POINT, CD_PROP_FLOAT})) {
+ return false;
}
}
return true;
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 01b51d552a9..47c8df03375 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -48,7 +48,6 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
- mesh_component.copy_vertex_group_names_from_object(object);
}
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 647db970d09..e13b9d543d7 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -87,6 +87,8 @@ static void greasepencil_copy_data(Main *UNUSED(bmain),
gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
}
+ BKE_defgroup_copy_list(&gpd_dst->vertex_group_names, &gpd_src->vertex_group_names);
+
/* copy layers */
BLI_listbase_clear(&gpd_dst->layers);
LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
@@ -165,6 +167,8 @@ static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id
BKE_animdata_blend_write(writer, gpd->adt);
}
+ BKE_defbase_blend_write(writer, &gpd->vertex_group_names);
+
BLO_write_pointer_array(writer, gpd->totcol, gpd->mat);
/* write grease-pencil layers to file */
@@ -227,6 +231,8 @@ void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd)
}
}
+ BLO_read_list(reader, &gpd->vertex_group_names);
+
/* Materials. */
BLO_read_pointer_array(reader, (void **)&gpd->mat);
@@ -498,6 +504,8 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all)
/* materials */
MEM_SAFE_FREE(gpd->mat);
+ BLI_freelistN(&gpd->vertex_group_names);
+
/* free all data */
if (free_all) {
/* clear cache */
@@ -798,32 +806,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
/* Utilities for easier bulk-creation of geometry */
/**
- * Populate stroke with point data from data buffers.
- * \param gps: Grease pencil stroke
- * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
- * \param totpoints: Total of points
- * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
- */
-void BKE_gpencil_stroke_add_points(bGPDstroke *gps,
- const float *array,
- const int totpoints,
- const float mat[4][4])
-{
- for (int i = 0; i < totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- const int x = GP_PRIM_DATABUF_SIZE * i;
-
- pt->x = array[x];
- pt->y = array[x + 1];
- pt->z = array[x + 2];
- mul_m4_v3(mat, &pt->x);
-
- pt->pressure = array[x + 3];
- pt->strength = array[x + 4];
- }
-}
-
-/**
* Create a new stroke, with pre-allocated data buffers.
* \param mat_idx: Index of the material
* \param totpoints: Total points
@@ -2087,8 +2069,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
{
bGPdata *gpd = ob->data;
MDeformVert *dvert = NULL;
- const int def_nr = BLI_findindex(&ob->defbase, defgroup);
- const int totgrp = BLI_listbase_count(&ob->defbase);
+
+ const int def_nr = BLI_findindex(&gpd->vertex_group_names, defgroup);
+ const int totgrp = BLI_listbase_count(&gpd->vertex_group_names);
/* Remove points data */
if (gpd) {
@@ -2117,7 +2100,7 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
}
/* Remove the group */
- BLI_freelinkN(&ob->defbase, defgroup);
+ BLI_freelinkN(&gpd->vertex_group_names, defgroup);
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 4d9c9878a67..0e2219e6c7f 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -257,9 +257,13 @@ bool BKE_gpencil_is_first_lineart_in_stack(const Object *ob, const GpencilModifi
return false;
}
-/* apply time modifiers */
-static int gpencil_time_modifier(
- Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render)
+/* Get Time modifier frame number. */
+int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ bGPDlayer *gpl,
+ const int cfra,
+ const bool is_render)
{
bGPdata *gpd = ob->data;
const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
@@ -665,7 +669,7 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
int remap_cfra = cfra_eval;
if (time_remap) {
- remap_cfra = gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render);
+ remap_cfra = BKE_gpencil_time_modifier_cfra(depsgraph, scene, ob, gpl, cfra_eval, is_render);
}
return remap_cfra;
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index a1f82b1dcb6..8a70f065e40 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -2087,7 +2087,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* check if object has any animation data */
if (ob->nlastrips.first) {
/* Add AnimData block */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
/* IPO first to take into any non-NLA'd Object Animation */
if (ob->ipo) {
@@ -2109,7 +2109,7 @@ void do_versions_ipos_to_animato(Main *bmain)
}
else if ((ob->ipo) || (ob->action)) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Action first - so that Action name get conserved */
if (ob->action) {
@@ -2133,7 +2133,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* check PoseChannels for constraints with local data */
if (ob->pose) {
/* Verify if there's AnimData block */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
@@ -2159,7 +2159,7 @@ void do_versions_ipos_to_animato(Main *bmain)
*/
if (con->ipo) {
/* Verify if there's AnimData block, just in case */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
/* although this was the constraint's local IPO, we still need to provide con
* so that drivers can be added properly...
@@ -2176,7 +2176,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* check constraint channels - we need to remove them anyway... */
if (ob->constraintChannels.first) {
/* Verify if there's AnimData block */
- BKE_animdata_add_id(id);
+ BKE_animdata_ensure_id(id);
for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) {
/* get pointer to next Constraint Channel */
@@ -2217,7 +2217,7 @@ void do_versions_ipos_to_animato(Main *bmain)
*/
if (key->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Shapekey data... */
ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL);
@@ -2242,7 +2242,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (ma->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Material data... */
ipo_to_animdata(bmain, id, ma->ipo, NULL, NULL, NULL);
@@ -2267,7 +2267,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (wo->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert World data... */
ipo_to_animdata(bmain, id, wo->ipo, NULL, NULL, NULL);
@@ -2288,7 +2288,7 @@ void do_versions_ipos_to_animato(Main *bmain)
if (ed && ed->seqbasep) {
Sequence *seq;
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
SEQ_ALL_BEGIN (ed, seq) {
IpoCurve *icu = (seq->ipo) ? seq->ipo->curve.first : NULL;
@@ -2346,7 +2346,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (te->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Texture data... */
ipo_to_animdata(bmain, id, te->ipo, NULL, NULL, NULL);
@@ -2371,7 +2371,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (ca->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Camera data... */
ipo_to_animdata(bmain, id, ca->ipo, NULL, NULL, NULL);
@@ -2396,7 +2396,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (la->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Light data... */
ipo_to_animdata(bmain, id, la->ipo, NULL, NULL, NULL);
@@ -2421,7 +2421,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* we're only interested in the IPO */
if (cu->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
/* Convert Curve data... */
ipo_to_animdata(bmain, id, cu->ipo, NULL, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 6cc90f86b4a..52f888d9543 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -1317,7 +1317,7 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac
if (cache) {
if (cache->defgroup_weights == NULL) {
- int num_defgroup = BLI_listbase_count(&ob->defbase);
+ int num_defgroup = BKE_object_defgroup_count(ob);
cache->defgroup_weights = MEM_callocN(sizeof(*cache->defgroup_weights) * num_defgroup,
"cached defgroup weights");
cache->num_defgroup_weights = num_defgroup;
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 1357424d5ff..9875d776d33 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -87,6 +87,8 @@ static void lattice_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const i
lattice_dst->key->from = &lattice_dst->id;
}
+ BKE_defgroup_copy_list(&lattice_dst->vertex_group_names, &lattice_src->vertex_group_names);
+
if (lattice_src->dvert) {
int tot = lattice_src->pntsu * lattice_src->pntsv * lattice_src->pntsw;
lattice_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
@@ -103,6 +105,8 @@ static void lattice_free_data(ID *id)
BKE_lattice_batch_cache_free(lattice);
+ BLI_freelistN(&lattice->vertex_group_names);
+
MEM_SAFE_FREE(lattice->def);
if (lattice->dvert) {
BKE_defvert_array_free(lattice->dvert, lattice->pntsu * lattice->pntsv * lattice->pntsw);
@@ -150,6 +154,7 @@ static void lattice_blend_write(BlendWriter *writer, ID *id, const void *id_addr
/* direct data */
BLO_write_struct_array(writer, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
+ BKE_defbase_blend_write(writer, &lt->vertex_group_names);
BKE_defvert_blend_write(writer, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
}
}
@@ -161,6 +166,7 @@ static void lattice_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &lt->dvert);
BKE_defvert_blend_read(reader, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
+ BLO_read_list(reader, &lt->vertex_group_names);
lt->editlatt = NULL;
lt->batch_cache = NULL;
diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c
index bd1972e9f1f..f9437eeaffa 100644
--- a/source/blender/blenkernel/intern/lattice_deform.c
+++ b/source/blender/blenkernel/intern/lattice_deform.c
@@ -112,7 +112,7 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob
int defgrp_index = -1;
const MDeformVert *dvert = BKE_lattice_deform_verts_get(oblatt);
if (lt->vgroup[0] && dvert) {
- defgrp_index = BKE_object_defgroup_name_index(oblatt, lt->vgroup);
+ defgrp_index = BKE_id_defgroup_name_index(&lt->id, lt->vgroup);
if (defgrp_index != -1) {
lattice_weights = MEM_malloc_arrayN(sizeof(float), num_points, "lattice_weights");
@@ -364,7 +364,7 @@ static void lattice_deform_coords_impl(const Object *ob_lattice,
* We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
*/
if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
- defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name);
+ defgrp_index = BKE_id_defgroup_name_index((ID *)ob_target->data, defgrp_name);
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index d49eb0d4da8..60e42c09ff3 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -737,6 +737,73 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* in at least one layer collection. That list is also synchronized here, and
* stores state like selection. */
+static void layer_collection_objects_sync(ViewLayer *view_layer,
+ LayerCollection *layer,
+ ListBase *new_object_bases,
+ const short collection_restrict,
+ const short layer_restrict,
+ const ushort local_collections_bits)
+{
+ /* No need to sync objects if the collection is excluded. */
+ if ((layer->flag & LAYER_COLLECTION_EXCLUDE) != 0) {
+ return;
+ }
+
+ LISTBASE_FOREACH (CollectionObject *, cob, &layer->collection->gobject) {
+ if (cob->ob == NULL) {
+ continue;
+ }
+
+ /* Tag linked object as a weak reference so we keep the object
+ * base pointer on file load and remember hidden state. */
+ id_lib_indirect_weak_link(&cob->ob->id);
+
+ void **base_p;
+ Base *base;
+ if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
+ /* Move from old base list to new base list. Base might have already
+ * been moved to the new base list and the first/last test ensure that
+ * case also works. */
+ base = *base_p;
+ if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
+ BLI_remlink(&view_layer->object_bases, base);
+ BLI_addtail(new_object_bases, base);
+ }
+ }
+ else {
+ /* Create new base. */
+ base = object_base_new(cob->ob);
+ base->local_collections_bits = local_collections_bits;
+ *base_p = base;
+ BLI_addtail(new_object_bases, base);
+ }
+
+ if ((collection_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) {
+ base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH);
+ if ((layer_restrict & LAYER_COLLECTION_HIDE) == 0) {
+ base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER;
+ }
+ if (((collection_restrict & COLLECTION_RESTRICT_SELECT) == 0)) {
+ base->flag_from_collection |= BASE_SELECTABLE;
+ }
+ }
+
+ if ((collection_restrict & COLLECTION_RESTRICT_RENDER) == 0) {
+ base->flag_from_collection |= BASE_ENABLED_RENDER;
+ }
+
+ /* Holdout and indirect only */
+ if (layer->flag & LAYER_COLLECTION_HOLDOUT) {
+ base->flag_from_collection |= BASE_HOLDOUT;
+ }
+ if (layer->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
+ base->flag_from_collection |= BASE_INDIRECT_ONLY;
+ }
+
+ layer->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
+ }
+}
+
static void layer_collection_sync(ViewLayer *view_layer,
const ListBase *lb_collections,
ListBase *lb_layer_collections,
@@ -812,7 +879,8 @@ static void layer_collection_sync(ViewLayer *view_layer,
child_layer_restrict,
local_collections_bits);
- /* Layer collection exclude is not inherited. */
+ /* Layer collection exclude is not inherited, we can skip the remaining process, including
+ * object bases synchronization. */
lc->runtime_flag = 0;
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
continue;
@@ -829,60 +897,12 @@ static void layer_collection_sync(ViewLayer *view_layer,
lc->runtime_flag |= LAYER_COLLECTION_VISIBLE_VIEW_LAYER;
}
- /* Sync objects, except if collection was excluded. */
- LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- if (cob->ob == NULL) {
- continue;
- }
-
- /* Tag linked object as a weak reference so we keep the object
- * base pointer on file load and remember hidden state. */
- id_lib_indirect_weak_link(&cob->ob->id);
-
- void **base_p;
- Base *base;
- if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
- /* Move from old base list to new base list. Base might have already
- * been moved to the new base list and the first/last test ensure that
- * case also works. */
- base = *base_p;
- if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
- BLI_remlink(&view_layer->object_bases, base);
- BLI_addtail(new_object_bases, base);
- }
- }
- else {
- /* Create new base. */
- base = object_base_new(cob->ob);
- base->local_collections_bits = local_collections_bits;
- *base_p = base;
- BLI_addtail(new_object_bases, base);
- }
-
- if ((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) {
- base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH);
- if ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0) {
- base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER;
- }
- if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) {
- base->flag_from_collection |= BASE_SELECTABLE;
- }
- }
-
- if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) {
- base->flag_from_collection |= BASE_ENABLED_RENDER;
- }
-
- /* Holdout and indirect only */
- if (lc->flag & LAYER_COLLECTION_HOLDOUT) {
- base->flag_from_collection |= BASE_HOLDOUT;
- }
- if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
- base->flag_from_collection |= BASE_INDIRECT_ONLY;
- }
-
- lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
- }
+ layer_collection_objects_sync(view_layer,
+ lc,
+ new_object_bases,
+ child_restrict,
+ child_layer_restrict,
+ local_collections_bits);
}
/* Free potentially remaining unused layer collections in old list.
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
index 10ab0a06dd0..48179e0c3bf 100644
--- a/source/blender/blenkernel/intern/layer_utils.c
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -23,6 +23,7 @@
#include "BLI_array.h"
#include "BKE_collection.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index a92401d3ba0..c4186ad3180 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -39,6 +39,7 @@
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_linklist.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
@@ -125,6 +126,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_dst->mat = MEM_dupallocN(mesh_src->mat);
+ BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names);
+
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert);
CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge);
@@ -155,6 +158,8 @@ static void mesh_free_data(ID *id)
{
Mesh *mesh = (Mesh *)id;
+ BLI_freelistN(&mesh->vertex_group_names);
+
BKE_mesh_runtime_clear_cache(mesh);
mesh_clear_geometry(mesh);
MEM_SAFE_FREE(mesh->mat);
@@ -229,6 +234,8 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BKE_animdata_blend_write(writer, mesh->adt);
}
+ BKE_defbase_blend_write(writer, &mesh->vertex_group_names);
+
BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect);
@@ -288,6 +295,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
/* Normally BKE_defvert_blend_read should be called in CustomData_blend_read,
* but for backwards compatibility in do_versions to work we do it here. */
BKE_defvert_blend_read(reader, mesh->totvert, mesh->dvert);
+ BLO_read_list(reader, &mesh->vertex_group_names);
CustomData_blend_read(reader, &mesh->vdata, mesh->totvert);
CustomData_blend_read(reader, &mesh->edata, mesh->totedge);
@@ -923,6 +931,12 @@ void BKE_mesh_copy_parameters(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);
+
+ /* Some callers call this on existing meshes, so free the existing vertex groups first. */
+ BLI_freelistN(&me_dst->vertex_group_names);
+ BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names);
+
+ me_dst->vertex_group_active_index = me_src->vertex_group_active_index;
}
/**
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index 369e3de2c67..91fd022a316 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -676,7 +676,7 @@ void BKE_mesh_calc_volume(const MVert *mverts,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name NGon Tessellation (NGon/Tessface Conversion)
+/** \name NGon Tessellation (NGon to MFace Conversion)
* \{ */
static void bm_corners_to_loops_ex(ID *id,
@@ -750,9 +750,9 @@ static void bm_corners_to_loops_ex(ID *id,
corners = multires_mdisp_corners(fd);
if (corners == 0) {
- /* Empty MDisp layers appear in at least one of the sintel.blend files.
+ /* Empty #MDisp layers appear in at least one of the `sintel.blend` files.
* Not sure why this happens, but it seems fine to just ignore them here.
- * If (corners == 0) for a non-empty layer though, something went wrong. */
+ * If `corners == 0` for a non-empty layer though, something went wrong. */
BLI_assert(fd->totdisp == 0);
}
else {
@@ -802,15 +802,16 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
/**
* The same as #BKE_mesh_convert_mfaces_to_mpolys
- * but oriented to be used in #do_versions from readfile.c
- * the difference is how active/render/clone/stencil indices are handled here
+ * but oriented to be used in #do_versions from `readfile.c`
+ * the difference is how active/render/clone/stencil indices are handled here.
*
- * normally thay're being set from pdata which totally makes sense for meshes which are already
- * converted to bmesh structures, but when loading older files indices shall be updated in other
- * way around, so newly added pdata and ldata would have this indices set based on fdata layer
+ * normally they're being set from `pdata` which totally makes sense for meshes which are already
+ * converted to #BMesh structures, but when loading older files indices shall be updated in other
+ * way around, so newly added `pdata` and `ldata` would have this indices set
+ * based on `fdata` layer.
*
* this is normally only needed when reading older files,
- * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used
+ * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
*/
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
{
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 55882f961a2..715c2fa91d2 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -69,7 +69,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BKE_node_ui_storage.hh"
#include "BLI_ghash.h"
#include "BLI_threads.h"
@@ -220,10 +219,6 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* node tree will generate its own interface type */
ntree_dst->interface_type = nullptr;
-
- /* Don't copy error messages in the runtime struct.
- * They should be filled during execution anyway. */
- ntree_dst->ui_storage = nullptr;
}
static void ntree_free_data(ID *id)
@@ -277,8 +272,6 @@ static void ntree_free_data(ID *id)
if (ntree->id.tag & LIB_TAG_LOCALIZED) {
BKE_libblock_free_data(&ntree->id, true);
}
-
- delete ntree->ui_storage;
}
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
@@ -621,7 +614,6 @@ static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_addres
ntree->interface_type = nullptr;
ntree->progress = nullptr;
ntree->execdata = nullptr;
- ntree->ui_storage = nullptr;
BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id);
@@ -653,7 +645,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->progress = nullptr;
ntree->execdata = nullptr;
- ntree->ui_storage = nullptr;
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
@@ -5121,6 +5112,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_primitive_circle();
register_node_type_geo_curve_primitive_line();
register_node_type_geo_curve_primitive_quadratic_bezier();
+ register_node_type_geo_curve_primitive_quadrilateral();
register_node_type_geo_curve_primitive_spiral();
register_node_type_geo_curve_primitive_star();
register_node_type_geo_curve_sample();
diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc
deleted file mode 100644
index e5e9f00c7c3..00000000000
--- a/source/blender/blenkernel/intern/node_ui_storage.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "CLG_log.h"
-
-#include <mutex>
-
-#include "BLI_map.hh"
-#include "BLI_string_ref.hh"
-#include "BLI_vector.hh"
-
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_context.h"
-#include "BKE_node_ui_storage.hh"
-#include "BKE_object.h"
-
-static CLG_LogRef LOG = {"bke.node_ui_storage"};
-
-using blender::Map;
-using blender::StringRef;
-using blender::Vector;
-
-/* Use a global mutex because otherwise it would have to be stored directly in the
- * bNodeTree struct in DNA. This could change if the node tree had a runtime struct. */
-static std::mutex global_ui_storage_mutex;
-
-static NodeTreeUIStorage &ui_storage_ensure(bNodeTree &ntree)
-{
- /* As an optimization, only acquire a lock if the UI storage doesn't exist,
- * because it only needs to be allocated once for every node tree. */
- if (ntree.ui_storage == nullptr) {
- std::lock_guard<std::mutex> lock(global_ui_storage_mutex);
- /* Check again-- another thread may have allocated the storage while this one waited. */
- if (ntree.ui_storage == nullptr) {
- ntree.ui_storage = new NodeTreeUIStorage();
- }
- }
- return *ntree.ui_storage;
-}
-
-const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C,
- const bNodeTree &ntree,
- const bNode &node)
-{
- const NodeTreeUIStorage *ui_storage = ntree.ui_storage;
- if (ui_storage == nullptr) {
- return nullptr;
- }
-
- const Object *active_object = CTX_data_active_object(C);
- if (active_object == nullptr) {
- return nullptr;
- }
-
- const ModifierData *active_modifier = BKE_object_active_modifier(active_object);
- if (active_modifier == nullptr) {
- return nullptr;
- }
-
- const NodeTreeEvaluationContext context(*active_object, *active_modifier);
- const Map<std::string, NodeUIStorage> *storage = ui_storage->context_map.lookup_ptr(context);
- if (storage == nullptr) {
- return nullptr;
- }
-
- return storage->lookup_ptr_as(StringRef(node.name));
-}
-
-/**
- * Removes only the UI data associated with a particular evaluation context. The same node tree
- * can be used for execution in multiple places, but the entire UI storage can't be removed when
- * one execution starts, or all of the data associated with the node tree would be lost.
- */
-void BKE_nodetree_ui_storage_free_for_context(bNodeTree &ntree,
- const NodeTreeEvaluationContext &context)
-{
- NodeTreeUIStorage *ui_storage = ntree.ui_storage;
- if (ui_storage != nullptr) {
- std::lock_guard<std::mutex> lock(ui_storage->mutex);
- ui_storage->context_map.remove(context);
- }
-}
-
-static void node_error_message_log(bNodeTree &ntree,
- const bNode &node,
- const StringRef message,
- const NodeWarningType type)
-{
- switch (type) {
- case NodeWarningType::Error:
- CLOG_ERROR(&LOG,
- "Node Tree: \"%s\", Node: \"%s\", %s",
- ntree.id.name + 2,
- node.name,
- message.data());
- break;
- case NodeWarningType::Warning:
- CLOG_WARN(&LOG,
- "Node Tree: \"%s\", Node: \"%s\", %s",
- ntree.id.name + 2,
- node.name,
- message.data());
- break;
- case NodeWarningType::Info:
- CLOG_INFO(&LOG,
- 2,
- "Node Tree: \"%s\", Node: \"%s\", %s",
- ntree.id.name + 2,
- node.name,
- message.data());
- break;
- }
-}
-
-static NodeUIStorage &node_ui_storage_ensure(NodeTreeUIStorage &locked_ui_storage,
- const NodeTreeEvaluationContext &context,
- const bNode &node)
-{
- Map<std::string, NodeUIStorage> &node_tree_ui_storage =
- locked_ui_storage.context_map.lookup_or_add_default(context);
- NodeUIStorage &node_ui_storage = node_tree_ui_storage.lookup_or_add_default_as(
- StringRef(node.name));
- return node_ui_storage;
-}
-
-void BKE_nodetree_error_message_add(bNodeTree &ntree,
- const NodeTreeEvaluationContext &context,
- const bNode &node,
- const NodeWarningType type,
- std::string message)
-{
- NodeTreeUIStorage &ui_storage = ui_storage_ensure(ntree);
- std::lock_guard lock{ui_storage.mutex};
-
- node_error_message_log(ntree, node, message, type);
-
- NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ui_storage, context, node);
- node_ui_storage.warnings.append({type, std::move(message)});
-}
-
-void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
- const NodeTreeEvaluationContext &context,
- const bNode &node,
- const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type)
-{
- NodeTreeUIStorage &ui_storage = ui_storage_ensure(ntree);
- std::lock_guard lock{ui_storage.mutex};
-
- NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ui_storage, context, node);
- node_ui_storage.attribute_hints.add_as(
- AvailableAttributeInfo{attribute_name, domain, data_type});
-}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index e0b23958ec9..912b5e0a0dd 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -234,7 +234,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
}
}
- BKE_defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
+
BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
@@ -285,7 +285,6 @@ static void object_free_data(ID *id)
MEM_SAFE_FREE(ob->iuser);
MEM_SAFE_FREE(ob->runtime.bb);
- BLI_freelistN(&ob->defbase);
BLI_freelistN(&ob->fmaps);
if (ob->pose) {
BKE_pose_free_ex(ob->pose, false);
@@ -510,13 +509,6 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
-static void write_defgroups(BlendWriter *writer, ListBase *defbase)
-{
- LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) {
- BLO_write_struct(writer, bDeformGroup, defgroup);
- }
-}
-
static void write_fmaps(BlendWriter *writer, ListBase *fbase)
{
LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
@@ -561,7 +553,6 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
}
BKE_pose_blend_write(writer, ob->pose, arm);
- write_defgroups(writer, &ob->defbase);
write_fmaps(writer, &ob->fmaps);
BKE_constraint_blend_write(writer, &ob->constraints);
animviz_motionpath_blend_write(writer, ob->mpath);
@@ -644,7 +635,9 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
animviz_motionpath_blend_read_data(reader, ob->mpath);
}
+ /* Only for versioning, vertex group names are now stored on object data. */
BLO_read_list(reader, &ob->defbase);
+
BLO_read_list(reader, &ob->fmaps);
/* XXX deprecated - old animation system <<< */
direct_link_nlastrips(reader, &ob->nlastrips);
@@ -1760,10 +1753,6 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
ob->runtime.geometry_set_eval = NULL;
}
- if (ob->runtime.geometry_set_previews != NULL) {
- BLI_ghash_free(ob->runtime.geometry_set_previews, NULL, (GHashValFreeFP)BKE_geometry_set_free);
- ob->runtime.geometry_set_previews = NULL;
- }
}
void BKE_object_free_caches(Object *object)
@@ -1814,24 +1803,6 @@ void BKE_object_free_caches(Object *object)
}
}
-/* Can be called from multiple threads. */
-void BKE_object_preview_geometry_set_add(Object *ob,
- const uint64_t key,
- struct GeometrySet *geometry_set)
-{
- static ThreadMutex mutex = BLI_MUTEX_INITIALIZER;
- BLI_mutex_lock(&mutex);
- if (ob->runtime.geometry_set_previews == NULL) {
- ob->runtime.geometry_set_previews = BLI_ghash_int_new(__func__);
- }
- BLI_ghash_reinsert(ob->runtime.geometry_set_previews,
- POINTER_FROM_UINT(key),
- geometry_set,
- NULL,
- (GHashValFreeFP)BKE_geometry_set_free);
- BLI_mutex_unlock(&mutex);
-}
-
/**
* Actual check for internal data, not context or flags.
*/
@@ -2835,7 +2806,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* add new animdata block */
if (!ob->adt) {
- ob->adt = BKE_animdata_add_id(&ob->id);
+ ob->adt = BKE_animdata_ensure_id(&ob->id);
}
/* make a copy of all the drivers (for now), then correct any links that need fixing */
@@ -2923,9 +2894,6 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
ob->data = target->data;
id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
- /* copy vertex groups */
- BKE_defgroup_copy_list(&ob->defbase, &target->defbase);
-
/* copy material and index information */
ob->actcol = ob->totcol = 0;
if (ob->mat) {
@@ -4165,6 +4133,30 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
return ok;
}
+struct GPencilStrokePointIterData {
+ const float (*obmat)[4];
+
+ void (*point_func_cb)(const float co[3], void *user_data);
+ void *user_data;
+};
+
+static void foreach_display_point_gpencil_stroke_fn(bGPDlayer *UNUSED(layer),
+ bGPDframe *UNUSED(frame),
+ bGPDstroke *stroke,
+ void *thunk)
+{
+ struct GPencilStrokePointIterData *iter_data = thunk;
+ {
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = stroke->points; i < stroke->totpoints; i++, pt++) {
+ float co[3];
+ mul_v3_m4v3(co, iter_data->obmat, &pt->x);
+ iter_data->point_func_cb(co, iter_data->user_data);
+ }
+ }
+}
+
void BKE_object_foreach_display_point(Object *ob,
const float obmat[4][4],
void (*func_cb)(const float[3], void *),
@@ -4182,6 +4174,13 @@ void BKE_object_foreach_display_point(Object *ob,
func_cb(co, user_data);
}
}
+ else if (ob->type == OB_GPENCIL) {
+ struct GPencilStrokePointIterData iter_data = {
+ .obmat = obmat, .point_func_cb = func_cb, .user_data = user_data};
+
+ BKE_gpencil_visible_stroke_iter(
+ ob->data, NULL, foreach_display_point_gpencil_stroke_fn, &iter_data);
+ }
else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
DispList *dl;
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 1e7624d0d7d..c69326a23c6 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -33,6 +33,7 @@
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
#include "DNA_curve_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -123,8 +124,7 @@ bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
}
defgroup = BKE_object_defgroup_new(ob, name);
-
- ob->actdef = BLI_listbase_count(&ob->defbase);
+ BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_count(ob));
return defgroup;
}
@@ -171,7 +171,8 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
{
MDeformVert *dv;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const int def_nr = BLI_findindex(defbase, dg);
bool changed = false;
if (ob->type == OB_MESH) {
@@ -249,7 +250,9 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
bDeformGroup *dg;
bool changed = false;
- for (dg = ob->defbase.first; dg; dg = dg->next) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
+ for (dg = defbase->first; dg; dg = dg->next) {
if (BKE_object_defgroup_clear(ob, dg, use_selection)) {
changed = true;
}
@@ -265,7 +268,7 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
static void object_defgroup_remove_update_users(Object *ob, const int idx)
{
- int i, defbase_tot = BLI_listbase_count(&ob->defbase) + 1;
+ int i, defbase_tot = BKE_object_defgroup_count(ob) + 1;
int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del");
map[idx] = map[0] = 0;
@@ -285,15 +288,18 @@ static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const in
object_defgroup_remove_update_users(ob, def_nr + 1);
/* Remove the group */
- BLI_freelinkN(&ob->defbase, dg);
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
+ BLI_freelinkN(defbase, dg);
/* Update the active deform index if necessary */
- if (ob->actdef > def_nr) {
- ob->actdef--;
+ const int active_index = BKE_object_defgroup_active_index_get(ob);
+ if (active_index > def_nr) {
+ BKE_object_defgroup_active_index_set(ob, active_index - 1);
}
/* remove all dverts */
- if (BLI_listbase_is_empty(&ob->defbase)) {
+ if (BLI_listbase_is_empty(defbase)) {
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
@@ -307,8 +313,9 @@ static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const in
}
}
}
- else if (ob->actdef < 1) { /* Keep a valid active index if we still have some vgroups. */
- ob->actdef = 1;
+ else if (BKE_object_defgroup_active_index_get(ob) < 1) {
+ /* Keep a valid active index if we still have some vgroups. */
+ BKE_object_defgroup_active_index_set(ob, 1);
}
}
@@ -316,7 +323,9 @@ static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg)
{
MDeformVert *dvert_array = NULL;
int dvert_tot = 0;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
+ const int def_nr = BLI_findindex(defbase, dg);
BLI_assert(def_nr != -1);
@@ -347,7 +356,8 @@ static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg)
static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
{
int i;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const int def_nr = BLI_findindex(defbase, dg);
BLI_assert(def_nr != -1);
@@ -425,7 +435,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
*/
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
- bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
+ bDeformGroup *dg = (bDeformGroup *)defbase->first;
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
if (dg) {
@@ -444,7 +456,7 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
dg = next_dg;
}
}
- else { /* ob->defbase is empty... */
+ else { /* defbase is empty... */
/* remove all dverts */
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
@@ -459,7 +471,7 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
}
}
/* Fix counters/indices */
- ob->actdef = 0;
+ BKE_object_defgroup_active_index_set(ob, 0);
}
}
@@ -478,20 +490,23 @@ void BKE_object_defgroup_remove_all(struct Object *ob)
*/
int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
{
+ const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
+ const ListBase *dst_defbase = BKE_object_defgroup_list(ob_dst);
+
/* Build src to merged mapping of vgroup indices. */
- if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) {
+ if (BLI_listbase_is_empty(src_defbase) || BLI_listbase_is_empty(dst_defbase)) {
*r_map_len = 0;
return NULL;
}
bDeformGroup *dg_src;
- *r_map_len = BLI_listbase_count(&ob_src->defbase);
+ *r_map_len = BLI_listbase_count(src_defbase);
int *vgroup_index_map = MEM_malloc_arrayN(
*r_map_len, sizeof(*vgroup_index_map), "defgroup index map create");
bool is_vgroup_remap_needed = false;
int i;
- for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) {
+ for (dg_src = src_defbase->first, i = 0; dg_src; dg_src = dg_src->next, i++) {
vgroup_index_map[i] = BKE_object_defgroup_name_index(ob_dst, dg_src->name);
is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i);
}
@@ -576,17 +591,17 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
/**
* gets the status of "flag" for each bDeformGroup
- * in ob->defbase and returns an array containing them
+ * in the object data's vertex group list and returns an array containing them
*/
bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot)
{
bool is_locked = false;
int i;
- // int defbase_tot = BLI_listbase_count(&ob->defbase);
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
bool *lock_flags = MEM_mallocN(defbase_tot * sizeof(bool), "defflags");
bDeformGroup *defgroup;
- for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup;
+ for (i = 0, defgroup = defbase->first; i < defbase_tot && defgroup;
defgroup = defgroup->next, i++) {
lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
is_locked |= lock_flags[i];
@@ -606,17 +621,17 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
bool *defgroup_validmap;
GHash *gh;
int i, step1 = 1;
- // int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
VirtualModifierData virtualModifierData;
- if (BLI_listbase_is_empty(&ob->defbase)) {
+ if (BLI_listbase_is_empty(defbase)) {
return NULL;
}
gh = BLI_ghash_str_new_ex(__func__, defbase_tot);
/* add all names to a hash table */
- for (dg = ob->defbase.first; dg; dg = dg->next) {
+ for (dg = defbase->first; dg; dg = dg->next) {
BLI_ghash_insert(gh, dg->name, NULL);
}
@@ -655,7 +670,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
defgroup_validmap = MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map");
/* add all names to a hash table */
- for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
+ for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL);
}
@@ -676,9 +691,11 @@ bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_fl
Object *armob = BKE_object_pose_armature_get(ob);
(*r_dg_flags_sel_tot) = 0;
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
if (armob) {
bPose *pose = armob->pose;
- for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup;
+ for (i = 0, defgroup = defbase->first; i < defbase_tot && defgroup;
defgroup = defgroup->next, i++) {
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, defgroup->name);
if (pchan && (pchan->bone->flag & BONE_SELECTED)) {
@@ -774,11 +791,13 @@ void BKE_object_defgroup_mirror_selection(struct Object *ob,
bool *dg_flags_sel,
int *r_dg_flags_sel_tot)
{
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
bDeformGroup *defgroup;
unsigned int i;
int i_mirr;
- for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup;
+ for (i = 0, defgroup = defbase->first; i < defbase_tot && defgroup;
defgroup = defgroup->next, i++) {
if (dg_selection[i]) {
char name_flip[MAXBONENAME];
@@ -804,11 +823,12 @@ bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
int *r_subset_count)
{
bool *defgroup_validmap = NULL;
- *r_defgroup_tot = BLI_listbase_count(&ob->defbase);
+
+ *r_defgroup_tot = BKE_object_defgroup_count(ob);
switch (subset_type) {
case WT_VGROUP_ACTIVE: {
- const int def_nr_active = ob->actdef - 1;
+ const int def_nr_active = BKE_object_defgroup_active_index_get(ob) - 1;
defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__);
memset(defgroup_validmap, false, *r_defgroup_tot * sizeof(*defgroup_validmap));
if ((def_nr_active >= 0) && (def_nr_active < *r_defgroup_tot)) {
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index ab247ef5507..7cdea14e9bd 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -123,7 +123,7 @@ void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bConstraintOb *cob;
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
@@ -388,12 +388,31 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
BKE_object_data_batch_cache_dirty_tag(ob->data);
}
+void BKE_object_data_eval_batch_cache_dirty_tag(Depsgraph *depsgraph, ID *object_data)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
+ BKE_object_data_batch_cache_dirty_tag(object_data);
+}
+
+void BKE_object_data_eval_batch_cache_deform_tag(Depsgraph *depsgraph, ID *object_data)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
+ switch (GS(object_data->name)) {
+ case ID_ME:
+ BKE_mesh_batch_cache_dirty_tag((Mesh *)object_data, BKE_MESH_BATCH_DIRTY_DEFORM);
+ break;
+ default:
+ /* Only mesh is currently supported. Fallback to dirty all for other datablocks types. */
+ BKE_object_data_batch_cache_dirty_tag(object_data);
+ break;
+ }
+}
+
void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type != OB_ARMATURE);
BKE_object_handle_data_update(depsgraph, scene, ob);
- BKE_object_batch_cache_dirty_tag(ob);
}
void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph, Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 7504fbeed19..db1fbb56125 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3961,7 +3961,7 @@ static ModifierData *object_add_or_copy_particle_system(
psys->totpart = 0;
psys->flag = PSYS_CURRENT;
if (scene != NULL) {
- psys->cfra = BKE_scene_frame_to_ctime(scene, CFRA + 1);
+ psys->cfra = BKE_scene_frame_to_ctime(scene, scene->r.cfra + 1);
}
DEG_relations_tag_update(bmain);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 90018e64f78..9ed5b0230e6 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -2807,8 +2807,8 @@ void BKE_ptcache_id_time(
cache = pid->cache;
if (timescale) {
- time = BKE_scene_frame_get(scene);
- nexttime = BKE_scene_frame_to_ctime(scene, CFRA + 1.0f);
+ time = BKE_scene_ctime_get(scene);
+ nexttime = BKE_scene_frame_to_ctime(scene, scene->r.cfra + 1);
*timescale = MAX2(nexttime - time, 0.0f);
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index f8f4d52fcf2..cc5a8536a5a 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -2299,10 +2299,7 @@ Object *BKE_scene_camera_switch_find(Scene *scene)
return NULL;
}
- const int cfra = ((scene->r.images == scene->r.framapto) ?
- scene->r.cfra :
- (int)(scene->r.cfra *
- ((float)scene->r.framapto / (float)scene->r.images)));
+ const int ctime = (int)BKE_scene_ctime_get(scene);
int frame = -(MAXFRAME + 1);
int min_frame = MAXFRAME + 1;
Object *camera = NULL;
@@ -2310,11 +2307,11 @@ Object *BKE_scene_camera_switch_find(Scene *scene)
LISTBASE_FOREACH (TimeMarker *, m, &scene->markers) {
if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) {
- if ((m->frame <= cfra) && (m->frame > frame)) {
+ if ((m->frame <= ctime) && (m->frame > frame)) {
camera = m->camera;
frame = m->frame;
- if (frame == cfra) {
+ if (frame == ctime) {
break;
}
}
@@ -2396,13 +2393,13 @@ const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame)
return best_marker ? best_marker->name : NULL;
}
-int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int cfra)
+int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int frame)
{
const int fps = round_db_to_int(FPS * interval_in_seconds);
- const int second_prev = cfra - mod_i(cfra, fps);
+ const int second_prev = frame - mod_i(frame, fps);
const int second_next = second_prev + fps;
- const int delta_prev = cfra - second_prev;
- const int delta_next = second_next - cfra;
+ const int delta_prev = frame - second_prev;
+ const int delta_next = second_next - frame;
return (delta_prev < delta_next) ? second_prev : second_next;
}
@@ -2444,16 +2441,17 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
return true;
}
-/**
- * This function is needed to cope with fractional frames, needed for motion blur & physics.
- */
-float BKE_scene_frame_get(const Scene *scene)
+/* Return fractional frame number taking into account subframes and time
+ * remapping. This the time value used by animation, modifiers and physics
+ * evaluation. */
+float BKE_scene_ctime_get(const Scene *scene)
{
return BKE_scene_frame_to_ctime(scene, scene->r.cfra);
}
-/* This function is used to obtain arbitrary fractional frames */
-float BKE_scene_frame_to_ctime(const Scene *scene, const float frame)
+/* Convert integer frame number to fractional frame number taking into account
+ * subframes and time remapping. */
+float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
{
float ctime = frame;
ctime += scene->r.subframe;
@@ -2461,13 +2459,18 @@ float BKE_scene_frame_to_ctime(const Scene *scene, const float frame)
return ctime;
}
-/**
- * Sets the frame int/float components.
- */
-void BKE_scene_frame_set(struct Scene *scene, double cfra)
+
+/* Get current fractional frame based on frame and subframe. */
+float BKE_scene_frame_get(const Scene *scene)
+{
+ return scene->r.cfra + scene->r.subframe;
+}
+
+/* Set current frame and subframe based on a fractional frame. */
+void BKE_scene_frame_set(Scene *scene, float frame)
{
double intpart;
- scene->r.subframe = modf(cfra, &intpart);
+ scene->r.subframe = modf((double)frame, &intpart);
scene->r.cfra = (int)intpart;
}
@@ -2736,8 +2739,8 @@ void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool cle
* edits from callback are properly taken into account. Doing a time update on those would
* lose any possible unkeyed changes made by the handler. */
if (pass == 0) {
- const float ctime = BKE_scene_frame_get(scene);
- DEG_evaluate_on_framechange(depsgraph, ctime);
+ const float frame = BKE_scene_frame_get(scene);
+ DEG_evaluate_on_framechange(depsgraph, frame);
}
else {
DEG_evaluate_on_refresh(depsgraph);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index a2809543b95..73658c3184e 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -1734,6 +1734,12 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
sfile->runtime = NULL;
BLO_read_data_address(reader, &sfile->params);
BLO_read_data_address(reader, &sfile->asset_params);
+ if (sfile->params) {
+ sfile->params->rename_id = NULL;
+ }
+ if (sfile->asset_params) {
+ sfile->asset_params->base_params.rename_id = NULL;
+ }
}
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index adcc8551ba8..e4e2ed94b41 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -2704,8 +2704,8 @@ static void mesh_to_softbody(Object *ob)
bp = sb->bpoint;
defgroup_index = me->dvert ? (sb->vertgroup - 1) : -1;
- defgroup_index_mass = me->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Mass) : -1;
- defgroup_index_spring = me->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Spring_K) :
+ defgroup_index_mass = me->dvert ? BKE_id_defgroup_name_index(&me->id, sb->namedVG_Mass) : -1;
+ defgroup_index_spring = me->dvert ? BKE_id_defgroup_name_index(&me->id, sb->namedVG_Spring_K) :
-1;
for (a = 0; a < me->totvert; a++, bp++) {
@@ -2934,8 +2934,8 @@ static void lattice_to_softbody(Object *ob)
bp = sb->bpoint;
defgroup_index = lt->dvert ? (sb->vertgroup - 1) : -1;
- defgroup_index_mass = lt->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Mass) : -1;
- defgroup_index_spring = lt->dvert ? BKE_object_defgroup_name_index(ob, sb->namedVG_Spring_K) :
+ defgroup_index_mass = lt->dvert ? BKE_id_defgroup_name_index(&lt->id, sb->namedVG_Mass) : -1;
+ defgroup_index_spring = lt->dvert ? BKE_id_defgroup_name_index(&lt->id, sb->namedVG_Spring_K) :
-1;
/* same code used as for mesh vertices */
@@ -3086,7 +3086,7 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts,
if (sb->solverflags & SBSO_ESTIMATEIPO) {
SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale);
}
- /* inverse matrix is not uptodate... */
+ /* Inverse matrix is not up to date. */
invert_m4_m4(ob->imat, ob->obmat);
for (a = 0; a < numVerts; a++, bp++) {
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 02d26ac715b..b6764f65631 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -333,6 +333,46 @@ void BezierSpline::correct_end_tangents() const
}
}
+/**
+ * De Casteljau Bezier subdivision.
+ * \param index: The index of the segment's start control point.
+ * \param next_index: The index of the control point at the end of the segment. Could be 0,
+ * if the spline is cyclic.
+ * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
+ * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
+ *
+ * <pre>
+ * handle_prev handle_next
+ * x----------------x
+ * / \
+ * / x---O---x \
+ * / result \
+ * / \
+ * O O
+ * point_prev point_next
+ * </pre>
+ */
+BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int index,
+ const int next_index,
+ const float parameter)
+{
+ BLI_assert(parameter <= 1.0f && parameter >= 0.0f);
+ BLI_assert(next_index == 0 || next_index == index + 1);
+ const float3 &point_prev = positions_[index];
+ const float3 &handle_prev = handle_positions_right_[index];
+ const float3 &handle_next = handle_positions_left_[next_index];
+ const float3 &point_next = positions_[next_index];
+ const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter);
+
+ BezierSpline::InsertResult result;
+ result.handle_prev = float3::interpolate(point_prev, handle_prev, parameter);
+ result.handle_next = float3::interpolate(handle_next, point_next, parameter);
+ result.left_handle = float3::interpolate(result.handle_prev, center_point, parameter);
+ result.right_handle = float3::interpolate(center_point, result.handle_next, parameter);
+ result.position = float3::interpolate(result.left_handle, result.right_handle, parameter);
+ return result;
+}
+
static void bezier_forward_difference_3d(const float3 &point_0,
const float3 &point_1,
const float3 &point_2,
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 4cc2d101b02..dc5162f201e 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -1352,7 +1352,7 @@ static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
ITER_PIXELS_END;
}
-void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4])
+void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3])
{
copy_v3_fl3(light_ambient, 0.0, 0.0, 0.0);
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index fe2aa701c63..03bd9323f39 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -722,6 +722,24 @@ eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
}
/**
+ * When reading undo steps for undo/redo,
+ * some extra checks are needed when so the correct undo step is decoded.
+ */
+static UndoStep *undosys_step_iter_first(UndoStep *us_reference, const eUndoStepDir undo_dir)
+{
+ if (us_reference->type->flags & UNDOTYPE_FLAG_DECODE_ACTIVE_STEP) {
+ /* Reading this step means an undo action reads undo twice.
+ * This should be avoided where possible, however some undo systems require it.
+ *
+ * Redo skips the current state as this represents the currently loaded state. */
+ return (undo_dir == -1) ? us_reference : us_reference->next;
+ }
+
+ /* Typical case, skip reading the current undo step. */
+ return (undo_dir == -1) ? us_reference->prev : us_reference->next;
+}
+
+/**
* Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
*
* \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
@@ -786,15 +804,10 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
us_target->type->name,
undo_dir);
- /* Undo/Redo steps until we reach given target step (or beyond if it has to be skipped), from
- * given reference step.
- *
- * NOTE: Unlike with redo case, where we can expect current active step to fully reflect current
- * data status, in undo case we also do reload the active step.
- * FIXME: this feels weak, and should probably not be actually needed? Or should also be done in
- * redo case? */
+ /* Undo/Redo steps until we reach given target step (or beyond if it has to be skipped),
+ * from given reference step. */
bool is_processing_extra_skipped_steps = false;
- for (UndoStep *us_iter = (undo_dir == -1) ? us_reference : us_reference->next; us_iter != NULL;
+ for (UndoStep *us_iter = undosys_step_iter_first(us_reference, undo_dir); us_iter != NULL;
us_iter = (undo_dir == -1) ? us_iter->prev : us_iter->next) {
BLI_assert(us_iter != NULL);
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 2847bc960ad..52d41173a0e 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -28,52 +28,53 @@
extern "C" {
#endif
-void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride);
+void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr)))
-void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir);
+void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
#define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
-void _bli_array_permute(void *arr,
- const unsigned int arr_len,
- const size_t arr_stride,
- const unsigned int *order,
- void *arr_temp);
+void _bli_array_permute(
+ void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL)
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
-int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride);
+#define BLI_array_deduplicate_ordered(arr, arr_len) \
+ _bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr)))
+
+int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
-int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
+int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_rfindindex(arr, arr_len, p) \
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
void _bli_array_binary_and(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride);
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride);
#define BLI_array_binary_and(arr, arr_a, arr_b, arr_len) \
(CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_and(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
void _bli_array_binary_or(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride);
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride);
#define BLI_array_binary_or(arr, arr_a, arr_b, arr_len) \
(CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
bool _bli_array_iter_span(const void *arr,
- unsigned int arr_len,
+ uint arr_len,
size_t arr_stride,
bool use_wrap,
bool use_delimit_bounds,
bool (*test_fn)(const void *arr_item, void *user_data),
void *user_data,
- unsigned int span_step[2],
- unsigned int *r_span_len);
+ uint span_step[2],
+ uint *r_span_len);
#define BLI_array_iter_span( \
arr, arr_len, use_wrap, use_delimit_bounds, test_fn, user_data, span_step, r_span_len) \
_bli_array_iter_span(arr, \
@@ -86,7 +87,7 @@ bool _bli_array_iter_span(const void *arr,
span_step, \
r_span_len)
-bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride);
+bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
bool _bli_array_iter_spiral_square(const void *arr_v,
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 685f526b4ad..7f7bec425ce 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -31,6 +31,7 @@ extern "C" {
/* Utility functions. */
void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id);
+void _BLI_assert_print_extra(const char *str);
void _BLI_assert_print_backtrace(void);
void _BLI_assert_abort(void);
void _BLI_assert_unreachable_print(const char *file, const int line, const char *function);
@@ -61,8 +62,17 @@ void _BLI_assert_unreachable_print(const char *file, const int line, const char
_BLI_ASSERT_ABORT(), \
NULL)) : \
NULL)
+/** A version of #BLI_assert() to pass an additional message to be printed on failure. */
+# define BLI_assert_msg(a, msg) \
+ (void)((!(a)) ? ((_BLI_assert_print_backtrace(), \
+ _BLI_ASSERT_PRINT_POS(a), \
+ _BLI_assert_print_extra(msg), \
+ _BLI_ASSERT_ABORT(), \
+ NULL)) : \
+ NULL)
#else
# define BLI_assert(a) ((void)0)
+# define BLI_assert_msg(a, msg) ((void)0)
#endif
#if defined(__cplusplus)
diff --git a/source/blender/blenlib/BLI_enumerable_thread_specific.hh b/source/blender/blenlib/BLI_enumerable_thread_specific.hh
index 25fd02b41fb..3051d980d45 100644
--- a/source/blender/blenlib/BLI_enumerable_thread_specific.hh
+++ b/source/blender/blenlib/BLI_enumerable_thread_specific.hh
@@ -77,17 +77,18 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
* their addresses do not change when the map grows. */
Map<int, std::reference_wrapper<T>> values_;
Vector<std::unique_ptr<T>> owned_values_;
- std::function<T()> initializer_;
+ std::function<void(void *)> initializer_;
public:
using iterator = typename Map<int, std::reference_wrapper<T>>::MutableValueIterator;
- EnumerableThreadSpecific() : initializer_([]() { return T(); })
+ EnumerableThreadSpecific() : initializer_([](void *buffer) { new (buffer) T(); })
{
}
template<typename F>
- EnumerableThreadSpecific(F initializer) : initializer_(std::move(initializer))
+ EnumerableThreadSpecific(F initializer)
+ : initializer_([=](void *buffer) { new (buffer) T(initializer()); })
{
}
@@ -96,11 +97,10 @@ template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
const int thread_id = enumerable_thread_specific_utils::thread_id;
std::lock_guard lock{mutex_};
return values_.lookup_or_add_cb(thread_id, [&]() {
- /* `std::make_unique` does not work here if T is non-copyable and non-movable. */
- std::unique_ptr<T> value{new T(initializer_())};
- std::reference_wrapper<T> ref = *value;
- owned_values_.append(std::move(value));
- return ref;
+ T *value = (T *)::operator new(sizeof(T));
+ initializer_(value);
+ owned_values_.append(std::unique_ptr<T>{value});
+ return std::reference_wrapper<T>{*value};
});
}
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 677df9db026..ea5572f1c8a 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -188,6 +188,7 @@ set(SRC
BLI_dynstr.h
BLI_easing.h
BLI_edgehash.h
+ BLI_endian_defines.h
BLI_endian_switch.h
BLI_endian_switch_inline.h
BLI_enumerable_thread_specific.hh
diff --git a/source/blender/blenlib/intern/BLI_assert.c b/source/blender/blenlib/intern/BLI_assert.c
index 887f583242f..cebc6f8957f 100644
--- a/source/blender/blenlib/intern/BLI_assert.c
+++ b/source/blender/blenlib/intern/BLI_assert.c
@@ -31,6 +31,11 @@ void _BLI_assert_print_pos(const char *file, const int line, const char *functio
fprintf(stderr, "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", file, line, function, id);
}
+void _BLI_assert_print_extra(const char *str)
+{
+ fprintf(stderr, " %s\n", str);
+}
+
void _BLI_assert_unreachable_print(const char *file, const int line, const char *function)
{
fprintf(stderr, "Code marked as unreachable has been executed. Please report this as a bug.\n");
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 25261e82cc9..9a12a7442b7 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -40,11 +40,11 @@
*
* Access via #BLI_array_reverse
*/
-void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride)
+void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
{
- const unsigned int arr_stride_uint = (unsigned int)arr_stride;
- const unsigned int arr_half_stride = (arr_len / 2) * arr_stride_uint;
- unsigned int i, i_end;
+ const uint arr_stride_uint = (uint)arr_stride;
+ const uint arr_half_stride = (arr_len / 2) * arr_stride_uint;
+ uint i, i_end;
char *arr = arr_v;
char *buf = BLI_array_alloca(buf, arr_stride);
@@ -62,7 +62,7 @@ void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride)
*
* Access via #BLI_array_wrap
*/
-void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int dir)
+void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
{
char *arr = arr_v;
char *buf = BLI_array_alloca(buf, arr_stride);
@@ -88,16 +88,13 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d
*
* Access via #BLI_array_wrap
*/
-void _bli_array_permute(void *arr,
- const unsigned int arr_len,
- const size_t arr_stride,
- const unsigned int *order,
- void *arr_temp)
+void _bli_array_permute(
+ void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp)
{
const size_t len = arr_len * arr_stride;
- const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const uint arr_stride_uint = (uint)arr_stride;
void *arr_orig;
- unsigned int i;
+ uint i;
if (arr_temp == NULL) {
arr_orig = MEM_mallocN(len, __func__);
@@ -121,16 +118,45 @@ void _bli_array_permute(void *arr,
}
/**
+ * In-place array de-duplication of an ordered array.
+ *
+ * \return The new length of the array.
+ *
+ * Access via #BLI_array_deduplicate_ordered
+ */
+uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
+{
+ if (UNLIKELY(arr_len <= 1)) {
+ return arr_len;
+ }
+
+ const uint arr_stride_uint = (uint)arr_stride;
+ uint j = 0;
+ for (uint i = 0; i < arr_len; i++) {
+ if ((i == j) || (memcmp(POINTER_OFFSET(arr, arr_stride_uint * i),
+ POINTER_OFFSET(arr, arr_stride_uint * j),
+ arr_stride) == 0)) {
+ continue;
+ }
+ j += 1;
+ memcpy(POINTER_OFFSET(arr, arr_stride_uint * j),
+ POINTER_OFFSET(arr, arr_stride_uint * i),
+ arr_stride);
+ }
+ return j + 1;
+}
+
+/**
* Find the first index of an item in an array.
*
* Access via #BLI_array_findindex
*
* \note Not efficient, use for error checks/asserts.
*/
-int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
- for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ for (uint i = 0; i < arr_len; i++, arr_step += arr_stride) {
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
}
@@ -141,10 +167,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
/**
* A version of #BLI_array_findindex that searches from the end of the list.
*/
-int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr + (arr_stride * arr_len);
- for (unsigned int i = arr_len; i-- != 0;) {
+ for (uint i = arr_len; i-- != 0;) {
arr_step -= arr_stride;
if (memcmp(arr_step, p, arr_stride) == 0) {
return (int)i;
@@ -154,7 +180,7 @@ int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stri
}
void _bli_array_binary_and(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride)
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride)
{
char *dst = arr;
const char *src_a = arr_a;
@@ -167,7 +193,7 @@ void _bli_array_binary_and(
}
void _bli_array_binary_or(
- void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride)
+ void *arr, const void *arr_a, const void *arr_b, uint arr_len, size_t arr_stride)
{
char *dst = arr;
const char *src_a = arr_a;
@@ -196,14 +222,14 @@ void _bli_array_binary_or(
* where calculating the length isn't a simple subtraction.
*/
bool _bli_array_iter_span(const void *arr,
- unsigned int arr_len,
+ uint arr_len,
size_t arr_stride,
bool use_wrap,
bool use_delimit_bounds,
bool (*test_fn)(const void *arr_item, void *user_data),
void *user_data,
- unsigned int span_step[2],
- unsigned int *r_span_len)
+ uint span_step[2],
+ uint *r_span_len)
{
if (arr_len == 0) {
return false;
@@ -212,11 +238,11 @@ bool _bli_array_iter_span(const void *arr,
return false;
}
- const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const uint arr_stride_uint = (uint)arr_stride;
const void *item_prev;
bool test_prev;
- unsigned int i_curr;
+ uint i_curr;
if ((span_step[0] == arr_len) && (span_step[1] == arr_len)) {
if (use_wrap) {
@@ -249,11 +275,11 @@ bool _bli_array_iter_span(const void *arr,
while (i_curr < arr_len) {
bool test_curr = test_fn(item_curr, user_data);
if ((test_prev == false) && (test_curr == true)) {
- unsigned int span_len;
- unsigned int i_step_prev = i_curr;
+ uint span_len;
+ uint i_step_prev = i_curr;
if (use_wrap) {
- unsigned int i_step = i_curr + 1;
+ uint i_step = i_curr + 1;
if (UNLIKELY(i_step == arr_len)) {
i_step = 0;
}
@@ -273,7 +299,7 @@ bool _bli_array_iter_span(const void *arr,
}
}
else {
- unsigned int i_step = i_curr + 1;
+ uint i_step = i_curr + 1;
while ((i_step != arr_len) &&
test_fn(POINTER_OFFSET(arr, i_step * arr_stride_uint), user_data)) {
i_step_prev = i_step;
@@ -307,7 +333,7 @@ bool _bli_array_iter_span(const void *arr,
/**
* Simple utility to check memory is zeroed.
*/
-bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_stride)
+bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
{
const char *arr_step = (const char *)arr_v;
size_t i = arr_stride * arr_len;
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index d86a88b977f..34baac6f2a4 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -373,7 +373,7 @@ void mat3_normalized_to_quat(float q[4], const float mat[3][3])
q[2] = (mat[2][1] + mat[1][2]) * s;
}
- /* Make sure w is nonnegative for a canonical result. */
+ /* Make sure W is non-negative for a canonical result. */
if (q[0] < 0) {
negate_v4(q);
}
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index dddf8851767..8b8850c7cdb 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -1460,11 +1460,6 @@ static int find_cell_for_point_near_edge(mpq3 p,
return c;
}
-static const Vert *max_x_vert(const Vert *a, const Vert *b)
-{
- return (a->co_exact.x > b->co_exact.x) ? a : b;
-}
-
/**
* Find the ambient cell -- that is, the cell that is outside
* all other cells.
@@ -1492,7 +1487,9 @@ static int find_ambient_cell(const IMesh &tm,
/* First find a vertex with the maximum x value. */
/* Prefer not to populate the verts in the #IMesh just for this. */
const Vert *v_extreme;
-
+ auto max_x_vert = [](const Vert *a, const Vert *b) {
+ return (a->co_exact.x > b->co_exact.x) ? a : b;
+ };
if (component_patches == nullptr) {
v_extreme = threading::parallel_reduce(
tm.face_index_range(),
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 8969dd4f6b5..4d0dc43ed1e 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1275,7 +1275,7 @@ void BLI_setenv(const char *env, const char *val)
{
/* free windows */
-#if (defined(WIN32) || defined(WIN64))
+#if (defined(_WIN32) || defined(_WIN64))
uputenv(env, val);
#else
diff --git a/source/blender/blenlib/tests/BLI_array_utils_test.cc b/source/blender/blenlib/tests/BLI_array_utils_test.cc
index 5d12b8fbd4d..1bf221c5335 100644
--- a/source/blender/blenlib/tests/BLI_array_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_array_utils_test.cc
@@ -189,3 +189,53 @@ TEST(array_utils, BinaryOrInt4Mix)
BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
}
#undef BINARY_OR_TEST
+
+/* BLI_array_deduplicate_ordered */
+#define DEDUPLICATE_ORDERED_TEST(data, data_cmp) \
+ { \
+ const uint data_len_new = BLI_array_deduplicate_ordered(data, ARRAY_SIZE(data)); \
+ EXPECT_EQ(data_len_new, ARRAY_SIZE(data_cmp)); \
+ EXPECT_EQ_ARRAY(data, data_cmp, data_len_new); \
+ /* Ensure running a second time does nothing. */ \
+ const uint data_len_test = BLI_array_deduplicate_ordered(data, data_len_new); \
+ EXPECT_EQ(data_len_test, ARRAY_SIZE(data_cmp)); \
+ EXPECT_EQ_ARRAY(data, data_cmp, data_len_new); \
+ } \
+ ((void)0)
+
+TEST(array_utils, DeduplicateOrdered1)
+{
+ int data[] = {0};
+ const int data_cmp[] = {0};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered2)
+{
+ int data[] = {1, 2};
+ const int data_cmp[] = {1, 2};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered2Same)
+{
+ int data[] = {1, 1};
+ const int data_cmp[] = {1};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered3Same)
+{
+ int data[] = {1, 1, 1};
+ const int data_cmp[] = {1};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+TEST(array_utils, DeduplicateOrdered3)
+{
+ int data[] = {3, 3, 2, 2, 1, 1};
+ const int data_cmp[] = {3, 2, 1};
+ DEDUPLICATE_ORDERED_TEST(data, data_cmp);
+}
+
+#undef DEDUPLICATE_ORDERED_TEST
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 61a00ccdaa4..f5baf0dcb83 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -58,8 +58,8 @@ set(SRC
intern/versioning_280.c
intern/versioning_290.c
intern/versioning_300.c
- intern/versioning_cycles.c
intern/versioning_common.cc
+ intern/versioning_cycles.c
intern/versioning_defaults.c
intern/versioning_dna.c
intern/versioning_legacy.c
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index f16b73f3c7b..3c58c29c162 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -34,8 +34,10 @@
#include "DNA_modifier_types.h"
#include "DNA_text_types.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
+#include "BKE_deform.h"
#include "BKE_fcurve_driver.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -89,6 +91,19 @@ static void assert_sorted_ids(Main *bmain)
#endif
}
+static void move_vertex_group_names_to_object_data(Main *bmain)
+{
+ LISTBASE_FOREACH (Object *, object, &bmain->objects) {
+ if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ ListBase *new_defbase = BKE_object_defgroup_list_mutable(object);
+
+ /* Clear the list in case the it was already assigned from another object. */
+ BLI_freelistN(new_defbase);
+ *new_defbase = object->defbase;
+ }
+ }
+}
+
void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@@ -133,6 +148,10 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
assert_sorted_ids(bmain);
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 11)) {
+ move_vertex_group_names_to_object_data(bmain);
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -480,17 +499,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 9)) {
+ /* Fix a bug where reordering FCurves and bActionGroups could cause some corruption. Just
+ * reconstruct all the action groups & ensure that the FCurves of a group are continuously
+ * stored (i.e. not mixed with other groups) to be sure. See T89435. */
+ LISTBASE_FOREACH (bAction *, act, &bmain->actions) {
+ BKE_action_groups_reconstruct(act);
+ }
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
@@ -503,4 +518,27 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 10)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ if (tool_settings->snap_uv_mode & (1 << 4)) {
+ tool_settings->snap_uv_mode |= (1 << 6); /* SCE_SNAP_MODE_INCREMENT */
+ tool_settings->snap_uv_mode &= ~(1 << 4);
+ }
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
}
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 7aee93bb157..423d64ba62c 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -23,6 +23,8 @@
* that benefit from accessing connectivity information.
*/
+#include "BLI_assert.h"
+
/* disable holes for now,
* these are ifdef'd because they use more memory and can't be saved in DNA currently */
// #define USE_BMESH_HOLES
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index 97d1de39027..dea6561fe9a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -33,6 +33,7 @@
#include "BLI_task.h"
#include "BLI_utildefines.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
@@ -630,11 +631,14 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
{
const BMVert *v_pivot = l_curr->v;
const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
- const BMVert *v_1 = BM_edge_other_vert(l_curr->e, v_pivot);
+ const BMVert *v_1 = l_curr->next->v;
const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co;
- const BMVert *v_2 = BM_edge_other_vert(l_curr->prev->e, v_pivot);
+ const BMVert *v_2 = l_curr->prev->v;
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+ BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot));
+ BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot));
+
sub_v3_v3v3(vec_curr, co_1, co_pivot);
normalize_v3(vec_curr);
sub_v3_v3v3(vec_prev, co_2, co_pivot);
@@ -700,9 +704,11 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
/* Only need to compute previous edge's vector once,
* then we can just reuse old current one! */
{
- const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot);
+ const BMVert *v_2 = lfan_pivot->next->v;
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+ BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot));
+
sub_v3_v3v3(vec_org, co_2, co_pivot);
normalize_v3(vec_org);
copy_v3_v3(vec_curr, vec_org);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 9466be4a300..3978959a425 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -724,7 +724,7 @@ static BMOpDefine bmo_edgenet_fill_def = {
};
/*
- * Edgenet Prepare.
+ * Edge-net Prepare.
*
* Identifies several useful edge loop cases and modifies them so
* they'll become a face when edgenet_fill is called. The cases covered are:
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 51af4d24e52..242b269ed47 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup bmesh
*
- * Edgenet Fill.
+ * Edge-net Fill.
*/
#include <limits.h>
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index 1e9adea2615..eb56075e136 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -938,7 +938,7 @@ bool BM_mesh_intersect_edges(
}
if (va_dest == v_other_dest) {
- /* Edge/Edgenet to vertex - we can't split the face. */
+ /* Edge/Edge-net to vertex - we can't split the face. */
break;
}
if (edgenet_len == 0 && BM_edge_exists(va_dest, v_other_dest)) {
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 08d9be8b90e..20b56ceb55f 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
intern/COM_Device.cc
intern/COM_Device.h
intern/COM_Enums.cc
+ intern/COM_Enums.h
intern/COM_ExecutionGroup.cc
intern/COM_ExecutionGroup.h
intern/COM_ExecutionModel.cc
@@ -446,14 +447,14 @@ set(SRC
operations/COM_BrightnessOperation.h
operations/COM_ColorCorrectionOperation.cc
operations/COM_ColorCorrectionOperation.h
+ operations/COM_ConstantOperation.cc
+ operations/COM_ConstantOperation.h
operations/COM_GammaOperation.cc
operations/COM_GammaOperation.h
operations/COM_MixOperation.cc
operations/COM_MixOperation.h
operations/COM_ReadBufferOperation.cc
operations/COM_ReadBufferOperation.h
- operations/COM_ConstantOperation.cc
- operations/COM_ConstantOperation.h
operations/COM_SetColorOperation.cc
operations/COM_SetColorOperation.h
operations/COM_SetValueOperation.cc
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index 857cbf0beee..9f8e6f10215 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -60,9 +60,12 @@ 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_VECTOR_CHANNELS = COM_data_type_num_channels(DataType::Vector);
constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color);
+constexpr float COM_VECTOR_ZERO[3] = {0.0f, 0.0f, 0.0f};
constexpr float COM_VALUE_ZERO[1] = {0.0f};
+constexpr float COM_VALUE_ONE[1] = {1.0f};
/**
* Utility to get data type for given number of channels.
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index af593b2e1b5..18973bb5a00 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -460,6 +460,9 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
NodeOperationOutput *fromSocket,
NodeOperationInput *toSocket)
{
+ /* Data type conversions are executed before resolutions to ensure convert operations have
+ * resolution. This method have to ensure same datatypes are linked for new operations. */
+ BLI_assert(fromSocket->getDataType() == toSocket->getDataType());
ResizeMode mode = toSocket->getResizeMode();
NodeOperation *toOperation = &toSocket->getOperation();
@@ -515,7 +518,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
NodeOperation *first = nullptr;
ScaleOperation *scaleOperation = nullptr;
if (doScale) {
- scaleOperation = new ScaleOperation();
+ scaleOperation = new ScaleOperation(fromSocket->getDataType());
scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None);
scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None);
first = scaleOperation;
@@ -535,7 +538,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
builder.addOperation(scaleOperation);
}
- TranslateOperation *translateOperation = new TranslateOperation();
+ TranslateOperation *translateOperation = new TranslateOperation(toSocket->getDataType());
translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None);
translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None);
if (!first) {
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 89068a7b734..4ad0872b0b7 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -264,11 +264,14 @@ class MemoryBuffer {
x = 0;
}
if (x >= w) {
- x = w;
+ x = w - 1;
}
break;
case MemoryBufferExtend::Repeat:
- x = (x >= 0.0f ? (x % w) : (x % w) + w);
+ x %= w;
+ if (x < 0) {
+ x += w;
+ }
break;
}
@@ -280,13 +283,19 @@ class MemoryBuffer {
y = 0;
}
if (y >= h) {
- y = h;
+ y = h - 1;
}
break;
case MemoryBufferExtend::Repeat:
- y = (y >= 0.0f ? (y % h) : (y % h) + h);
+ y %= h;
+ if (y < 0) {
+ y += h;
+ }
break;
}
+
+ x = x + m_rect.xmin;
+ y = y + m_rect.ymin;
}
inline void wrap_pixel(float &x,
@@ -307,11 +316,14 @@ class MemoryBuffer {
x = 0.0f;
}
if (x >= w) {
- x = w;
+ x = w - 1;
}
break;
case MemoryBufferExtend::Repeat:
x = fmodf(x, w);
+ if (x < 0.0f) {
+ x += w;
+ }
break;
}
@@ -323,13 +335,19 @@ class MemoryBuffer {
y = 0.0f;
}
if (y >= h) {
- y = h;
+ y = h - 1;
}
break;
case MemoryBufferExtend::Repeat:
y = fmodf(y, h);
+ if (y < 0.0f) {
+ y += h;
+ }
break;
}
+
+ x = x + m_rect.xmin;
+ y = y + m_rect.ymin;
}
inline void read(float *result,
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc
index 1b2ce341a66..3a3e98c3472 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.cc
+++ b/source/blender/compositor/nodes/COM_TranslateNode.cc
@@ -42,6 +42,7 @@ void TranslateNode::convertToOperations(NodeConverter &converter,
NodeOutput *outputSocket = this->getOutputSocket(0);
TranslateOperation *operation = new TranslateOperation();
+ operation->set_wrapping(data->wrap_axis);
if (data->relative) {
const RenderData *rd = context.getRenderData();
const float render_size_factor = context.getRenderPercentageAsFactor();
@@ -55,11 +56,8 @@ void TranslateNode::convertToOperations(NodeConverter &converter,
converter.mapInputSocket(inputXSocket, operation->getInputSocket(1));
converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
-
- /* FullFrame does not support using WriteBufferOperation.
- * TODO: Implement TranslateOperation with wrap support in FullFrame.
- */
if (data->wrap_axis && context.get_execution_model() != eExecutionModel::FullFrame) {
+ /* TODO: To be removed with tiled implementation. */
WriteBufferOperation *writeOperation = new WriteBufferOperation(DataType::Color);
WrapOperation *wrapOperation = new WrapOperation(DataType::Color);
wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy());
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index 1ac451b95c2..34fea705c75 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cc
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
@@ -43,6 +43,7 @@ RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elem
this->m_inputBuffer = nullptr;
this->m_elementsize = elementsize;
this->m_rd = nullptr;
+ layer_buffer_ = nullptr;
this->addOutputSocket(type);
}
@@ -65,6 +66,9 @@ void RenderLayersProg::initExecution()
if (rl) {
this->m_inputBuffer = RE_RenderLayerGetPass(
rl, this->m_passName.c_str(), this->m_viewName);
+ if (m_inputBuffer) {
+ layer_buffer_ = new MemoryBuffer(m_inputBuffer, m_elementsize, getWidth(), getHeight());
+ }
}
}
}
@@ -186,6 +190,10 @@ void RenderLayersProg::executePixelSampled(float output[4], float x, float y, Pi
void RenderLayersProg::deinitExecution()
{
this->m_inputBuffer = nullptr;
+ if (layer_buffer_) {
+ delete layer_buffer_;
+ layer_buffer_ = nullptr;
+ }
}
void RenderLayersProg::determineResolution(unsigned int resolution[2],
@@ -255,6 +263,20 @@ std::unique_ptr<MetaData> RenderLayersProg::getMetaData()
return std::move(callback_data.meta_data);
}
+void RenderLayersProg::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ BLI_assert(output->get_num_channels() >= m_elementsize);
+ if (layer_buffer_) {
+ output->copy_from(layer_buffer_, area, 0, m_elementsize, 0);
+ }
+ else {
+ std::unique_ptr<float[]> zero_elem = std::make_unique<float[]>(m_elementsize);
+ output->fill(area, 0, zero_elem.get(), m_elementsize);
+ }
+}
+
/* ******** Render Layers AO Operation ******** */
void RenderLayersAOOperation::executePixelSampled(float output[4],
float x,
@@ -271,6 +293,21 @@ void RenderLayersAOOperation::executePixelSampled(float output[4],
output[3] = 1.0f;
}
+void RenderLayersAOOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ BLI_assert(output->get_num_channels() == COM_DATA_TYPE_COLOR_CHANNELS);
+ BLI_assert(m_elementsize == COM_DATA_TYPE_COLOR_CHANNELS);
+ if (layer_buffer_) {
+ output->copy_from(layer_buffer_, area, 0, COM_DATA_TYPE_VECTOR_CHANNELS, 0);
+ }
+ else {
+ output->fill(area, 0, COM_VECTOR_ZERO, COM_DATA_TYPE_VECTOR_CHANNELS);
+ }
+ output->fill(area, 3, COM_VALUE_ONE, COM_DATA_TYPE_VALUE_CHANNELS);
+}
+
/* ******** Render Layers Alpha Operation ******** */
void RenderLayersAlphaProg::executePixelSampled(float output[4],
float x,
@@ -289,6 +326,20 @@ void RenderLayersAlphaProg::executePixelSampled(float output[4],
}
}
+void RenderLayersAlphaProg::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ BLI_assert(output->get_num_channels() == COM_DATA_TYPE_VALUE_CHANNELS);
+ BLI_assert(m_elementsize == COM_DATA_TYPE_COLOR_CHANNELS);
+ if (layer_buffer_) {
+ output->copy_from(layer_buffer_, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
+ }
+ else {
+ output->fill(area, COM_VALUE_ZERO);
+ }
+}
+
/* ******** Render Layers Depth Operation ******** */
void RenderLayersDepthProg::executePixelSampled(float output[4],
float x,
@@ -309,4 +360,19 @@ void RenderLayersDepthProg::executePixelSampled(float output[4],
}
}
+void RenderLayersDepthProg::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> UNUSED(inputs))
+{
+ BLI_assert(output->get_num_channels() == COM_DATA_TYPE_VALUE_CHANNELS);
+ BLI_assert(m_elementsize == COM_DATA_TYPE_VALUE_CHANNELS);
+ if (layer_buffer_) {
+ output->copy_from(layer_buffer_, area);
+ }
+ else {
+ const float default_depth = 10e10f;
+ output->fill(area, &default_depth);
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index 56f83f691e8..dd76a56d645 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -20,7 +20,7 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -33,7 +33,7 @@ namespace blender::compositor {
*
* \todo Rename to operation.
*/
-class RenderLayersProg : public NodeOperation {
+class RenderLayersProg : public MultiThreadedOperation {
protected:
/**
* Reference to the scene object.
@@ -50,8 +50,11 @@ class RenderLayersProg : public NodeOperation {
*/
const char *m_viewName;
+ const MemoryBuffer *layer_buffer_;
+
/**
- * cached instance to the float buffer inside the layer
+ * Cached instance to the float buffer inside the layer.
+ * TODO: To be removed with tiled implementation.
*/
float *m_inputBuffer;
@@ -126,6 +129,10 @@ class RenderLayersProg : public NodeOperation {
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
std::unique_ptr<MetaData> getMetaData() override;
+
+ virtual void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
};
class RenderLayersAOOperation : public RenderLayersProg {
@@ -135,6 +142,10 @@ class RenderLayersAOOperation : public RenderLayersProg {
{
}
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 RenderLayersAlphaProg : public RenderLayersProg {
@@ -144,6 +155,10 @@ class RenderLayersAlphaProg : public RenderLayersProg {
{
}
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 RenderLayersDepthProg : public RenderLayersProg {
@@ -153,6 +168,10 @@ class RenderLayersDepthProg : public RenderLayersProg {
{
}
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_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 9dde73269fc..c3647a39909 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -36,12 +36,12 @@ namespace blender::compositor {
*
* http://www.iryoku.com/smaa/
*
- * This file is based on smaa-cpp:
+ * This file is based on SMAA-CPP:
*
* https://github.com/iRi-E/smaa-cpp
*
* Currently only SMAA 1x mode is provided, so the operation will be done
- * with no spatial multisampling nor temporal supersampling.
+ * with no spatial multi-sampling nor temporal super-sampling.
*
* NOTE: This program assumes the screen coordinates are DirectX style, so
* the vertical direction is upside-down. "top" and "bottom" actually mean
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc
index 18276fcc072..f03b9fcf34d 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cc
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cc
@@ -37,12 +37,16 @@ BaseScaleOperation::BaseScaleOperation()
m_variable_size = false;
}
-ScaleOperation::ScaleOperation() : BaseScaleOperation()
+ScaleOperation::ScaleOperation() : ScaleOperation(DataType::Color)
{
- this->addInputSocket(DataType::Color);
+}
+
+ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation()
+{
+ this->addInputSocket(data_type);
this->addInputSocket(DataType::Value);
this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->addOutputSocket(data_type);
this->setResolutionInputSocketIndex(0);
this->m_inputOperation = nullptr;
this->m_inputXOperation = nullptr;
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h
index dc3de3602bf..2f9a7be92e6 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.h
+++ b/source/blender/compositor/operations/COM_ScaleOperation.h
@@ -55,6 +55,7 @@ class ScaleOperation : public BaseScaleOperation {
public:
ScaleOperation();
+ ScaleOperation(DataType data_type);
bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output) override;
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc
index 49135f25320..a3db086e974 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cc
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
@@ -20,12 +20,15 @@
namespace blender::compositor {
-TranslateOperation::TranslateOperation()
+TranslateOperation::TranslateOperation() : TranslateOperation(DataType::Color)
{
- this->addInputSocket(DataType::Color);
+}
+TranslateOperation::TranslateOperation(DataType data_type)
+{
+ this->addInputSocket(data_type);
this->addInputSocket(DataType::Value);
this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->addOutputSocket(data_type);
this->setResolutionInputSocketIndex(0);
this->m_inputOperation = nullptr;
this->m_inputXOperation = nullptr;
@@ -33,6 +36,8 @@ TranslateOperation::TranslateOperation()
this->m_isDeltaSet = false;
this->m_factorX = 1.0f;
this->m_factorY = 1.0f;
+ this->x_extend_mode_ = MemoryBufferExtend::Clip;
+ this->y_extend_mode_ = MemoryBufferExtend::Clip;
}
void TranslateOperation::initExecution()
{
@@ -83,4 +88,58 @@ void TranslateOperation::setFactorXY(float factorX, float factorY)
m_factorY = factorY;
}
+void TranslateOperation::set_wrapping(int wrapping_type)
+{
+ switch (wrapping_type) {
+ case CMP_NODE_WRAP_X:
+ x_extend_mode_ = MemoryBufferExtend::Repeat;
+ break;
+ case CMP_NODE_WRAP_Y:
+ y_extend_mode_ = MemoryBufferExtend::Repeat;
+ break;
+ case CMP_NODE_WRAP_XY:
+ x_extend_mode_ = MemoryBufferExtend::Repeat;
+ y_extend_mode_ = MemoryBufferExtend::Repeat;
+ break;
+ default:
+ break;
+ }
+}
+
+void TranslateOperation::get_area_of_interest(const int input_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ if (input_idx == 0) {
+ ensureDelta();
+ r_input_area = output_area;
+ if (x_extend_mode_ == MemoryBufferExtend::Clip) {
+ const int delta_x = this->getDeltaX();
+ BLI_rcti_translate(&r_input_area, -delta_x, 0);
+ }
+ if (y_extend_mode_ == MemoryBufferExtend::Clip) {
+ const int delta_y = this->getDeltaY();
+ BLI_rcti_translate(&r_input_area, 0, -delta_y);
+ }
+ }
+}
+
+void TranslateOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ MemoryBuffer *input = inputs[0];
+ const int delta_x = this->getDeltaX();
+ const int delta_y = this->getDeltaY();
+ for (int y = area.ymin; y < area.ymax; y++) {
+ float *out = output->get_elem(area.xmin, y);
+ for (int x = area.xmin; x < area.xmax; x++) {
+ const int input_x = x - delta_x;
+ const int input_y = y - delta_y;
+ input->read(out, input_x, input_y, x_extend_mode_, y_extend_mode_);
+ out += output->elem_stride;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h
index eb3a664159f..ce1965cecef 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.h
+++ b/source/blender/compositor/operations/COM_TranslateOperation.h
@@ -18,11 +18,12 @@
#pragma once
-#include "COM_NodeOperation.h"
+#include "COM_ConstantOperation.h"
+#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
-class TranslateOperation : public NodeOperation {
+class TranslateOperation : public MultiThreadedOperation {
private:
SocketReader *m_inputOperation;
SocketReader *m_inputXOperation;
@@ -32,9 +33,12 @@ class TranslateOperation : public NodeOperation {
bool m_isDeltaSet;
float m_factorX;
float m_factorY;
+ MemoryBufferExtend x_extend_mode_;
+ MemoryBufferExtend y_extend_mode_;
public:
TranslateOperation();
+ TranslateOperation(DataType data_type);
bool determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output) override;
@@ -55,16 +59,38 @@ class TranslateOperation : public NodeOperation {
inline void ensureDelta()
{
if (!this->m_isDeltaSet) {
- float tempDelta[4];
- this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
- this->m_deltaX = tempDelta[0];
- this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
- this->m_deltaY = tempDelta[0];
+ if (execution_model_ == eExecutionModel::Tiled) {
+ float tempDelta[4];
+ this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
+ this->m_deltaX = tempDelta[0];
+ this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
+ this->m_deltaY = tempDelta[0];
+ }
+ else {
+ this->m_deltaX = 0;
+ NodeOperation *x_op = getInputOperation(1);
+ if (x_op->get_flags().is_constant_operation) {
+ this->m_deltaX = ((ConstantOperation *)x_op)->get_constant_elem()[0];
+ }
+ this->m_deltaY = 0;
+ NodeOperation *y_op = getInputOperation(2);
+ if (y_op->get_flags().is_constant_operation) {
+ this->m_deltaY = ((ConstantOperation *)y_op)->get_constant_elem()[0];
+ }
+ }
+
this->m_isDeltaSet = true;
}
}
void setFactorXY(float factorX, float factorY);
+ void set_wrapping(int wrapping_type);
+
+ 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/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 27441c9a7ae..749b1bba871 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -159,7 +159,7 @@ void DEG_ids_restore_recalc(Depsgraph *depsgraph);
/* Graph Evaluation ----------------------------- */
/* Frame changed recalculation entry point. */
-void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime);
+void DEG_evaluate_on_framechange(Depsgraph *graph, float frame);
/* Data changed recalculation entry point. */
void DEG_evaluate_on_refresh(Depsgraph *graph);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 56168739fae..bd3bc5d5ee7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -114,6 +114,7 @@
#include "SEQ_iterator.h"
#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_rna.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_tag.h"
#include "intern/depsgraph_type.h"
@@ -1199,7 +1200,7 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path
if (prop == nullptr) {
return;
}
- if (!RNA_property_is_idprop(prop)) {
+ if (!rna_prop_affects_parameters_node(&ptr, prop)) {
return;
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
@@ -1495,7 +1496,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
add_operation_node(
&object->id,
NodeType::BATCH_CACHE,
- OperationCode::GEOMETRY_SELECT_UPDATE,
+ OperationCode::BATCH_UPDATE_SELECT,
[object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); });
}
@@ -1516,33 +1517,37 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
if (key) {
build_shapekeys(key);
}
- /* Nodes for result of obdata's evaluation, and geometry
- * evaluation on object. */
+
+ /* Geometry evaluation. */
+ /* Entry operation, takes care of initialization, and some other
+ * relations which needs to be run prior to actual geometry evaluation. */
+ op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
+ op_node->set_as_entry();
+
+ add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM);
+
const ID_Type id_type = GS(obdata->name);
switch (id_type) {
case ID_ME: {
- op_node = add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow);
- });
- op_node->set_as_entry();
+ add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_mesh_eval_geometry(depsgraph, (Mesh *)obdata_cow);
+ });
break;
}
case ID_MB: {
- op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
- op_node->set_as_entry();
+ add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
break;
}
case ID_CU: {
- op_node = add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
- });
- op_node->set_as_entry();
+ add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
+ });
/* Make sure objects used for bevel.taper are in the graph.
* NOTE: This objects might be not linked to the scene. */
Curve *cu = (Curve *)obdata;
@@ -1558,47 +1563,41 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
break;
}
case ID_LT: {
- op_node = add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow);
- });
- op_node->set_as_entry();
+ add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_lattice_eval_geometry(depsgraph, (Lattice *)obdata_cow);
+ });
break;
}
case ID_GD: {
/* GPencil evaluation operations. */
- op_node = add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_gpencil_frame_active_set(depsgraph,
- (bGPdata *)obdata_cow);
- });
- op_node->set_as_entry();
+ add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_gpencil_frame_active_set(depsgraph, (bGPdata *)obdata_cow);
+ });
break;
}
case ID_HA: {
- op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
- op_node->set_as_entry();
+ add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
break;
}
case ID_PT: {
- op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
- op_node->set_as_entry();
+ add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
break;
}
case ID_VO: {
/* Volume frame update. */
- op_node = add_operation_node(obdata,
- NodeType::GEOMETRY,
- OperationCode::GEOMETRY_EVAL,
- [obdata_cow](::Depsgraph *depsgraph) {
- BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow);
- });
- op_node->set_as_entry();
+ add_operation_node(obdata,
+ NodeType::GEOMETRY,
+ OperationCode::GEOMETRY_EVAL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_volume_eval_geometry(depsgraph, (Volume *)obdata_cow);
+ });
break;
}
default:
@@ -1612,10 +1611,22 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
/* Batch cache. */
add_operation_node(obdata,
NodeType::BATCH_CACHE,
- OperationCode::GEOMETRY_SELECT_UPDATE,
+ OperationCode::BATCH_UPDATE_SELECT,
[obdata_cow](::Depsgraph *depsgraph) {
BKE_object_data_select_update(depsgraph, obdata_cow);
});
+ add_operation_node(obdata,
+ NodeType::BATCH_CACHE,
+ OperationCode::BATCH_UPDATE_DEFORM,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_object_data_eval_batch_cache_deform_tag(depsgraph, obdata_cow);
+ });
+ add_operation_node(obdata,
+ NodeType::BATCH_CACHE,
+ OperationCode::BATCH_UPDATE_ALL,
+ [obdata_cow](::Depsgraph *depsgraph) {
+ BKE_object_data_eval_batch_cache_dirty_tag(depsgraph, obdata_cow);
+ });
}
void DepsgraphNodeBuilder::build_armature(bArmature *armature)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index c269ad16824..5650e95f55a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -647,7 +647,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
/* Only create geometry relations to child objects, if they have a geometry component. */
OperationKey object_geometry_key{
- &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL};
+ &cob->ob->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT};
if (find_node(object_geometry_key) != nullptr) {
add_relation(object_geometry_key, collection_geometry_key, "Collection Geometry");
}
@@ -1098,7 +1098,8 @@ void DepsgraphRelationBuilder::build_object_pointcache(Object *object)
}
else {
flag = FLAG_GEOMETRY;
- OperationKey geometry_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ OperationKey geometry_key(
+ &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
add_relation(point_cache_key, geometry_key, "Point Cache -> Geometry");
}
BLI_assert(flag != -1);
@@ -1610,7 +1611,7 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
}
}
}
- if (property_entry_key.prop != nullptr && RNA_property_is_idprop(property_entry_key.prop)) {
+ if (rna_prop_affects_parameters_node(&property_entry_key.ptr, property_entry_key.prop)) {
RNAPathKey property_exit_key(property_entry_key.id,
property_entry_key.ptr,
property_entry_key.prop,
@@ -1713,7 +1714,7 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_
if (prop == nullptr) {
return;
}
- if (!RNA_property_is_idprop(prop)) {
+ if (!rna_prop_affects_parameters_node(&ptr, prop)) {
return;
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
@@ -1868,7 +1869,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
void DepsgraphRelationBuilder::build_particle_systems(Object *object)
{
TimeSourceKey time_src_key;
- OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ OperationKey obdata_ubereval_key(
+ &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
OperationKey eval_init_key(
&object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT);
OperationKey eval_done_key(
@@ -2016,7 +2018,8 @@ void DepsgraphRelationBuilder::build_particle_system_visualization_object(Object
{
OperationKey psys_key(
&object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name);
- OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ OperationKey obdata_ubereval_key(
+ &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM);
add_relation(dup_ob_key, psys_key, "Particle Object Visualization");
if (draw_object->type == OB_MBALL) {
@@ -2073,15 +2076,15 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
/* Get nodes for result of obdata's evaluation, and geometry evaluation
* on object. */
ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY);
- ComponentKey geom_key(&object->id, NodeType::GEOMETRY);
- /* Link components to each other. */
- add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
+ /* Link components to each other. */
+ add_relation(obdata_geom_key, obdata_ubereval_key, "Object Geometry Base Data");
+
/* Special case: modifiers evaluation queries scene for various things like
* data mask to be used. We add relation here to ensure object is never
* evaluated prior to Scene's CoW is ready. */
OperationKey scene_key(&scene_->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL);
- Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
+ Relation *rel = add_relation(scene_key, geom_init_key, "CoW Relation");
rel->flag |= RELATION_FLAG_NO_FLUSH;
/* Modifiers */
if (object->modifiers.first != nullptr) {
@@ -2091,13 +2094,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ DepsNodeHandle handle = create_node_handle(geom_init_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
}
if (BKE_object_modifier_use_time(object, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ add_relation(time_src_key, geom_init_key, "Time Source");
}
}
}
@@ -2110,13 +2113,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(
(GpencilModifierType)md->type);
if (mti->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ DepsNodeHandle handle = create_node_handle(geom_init_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx, graph_->mode);
}
if (BKE_object_modifier_gpencil_use_time(object, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ add_relation(time_src_key, geom_init_key, "Time Source");
}
}
}
@@ -2128,13 +2131,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) {
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info((ShaderFxType)fx->type);
if (fxi->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ DepsNodeHandle handle = create_node_handle(geom_init_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
fxi->updateDepsgraph(fx, &ctx);
}
if (BKE_object_shaderfx_use_time(object, fx)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ add_relation(time_src_key, geom_init_key, "Time Source");
}
}
}
@@ -2160,6 +2163,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
add_relation(mom_transform_key, mom_geom_key, "Metaball Motherball Transform -> Geometry");
}
else {
+ ComponentKey geom_key(&object->id, NodeType::GEOMETRY);
ComponentKey transform_key(&object->id, NodeType::TRANSFORM);
add_relation(geom_key, mom_geom_key, "Metaball Motherball");
add_relation(transform_key, mom_geom_key, "Metaball Motherball");
@@ -2174,9 +2178,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
* Ideally we need to get rid of this relation. */
if (object_particles_depends_on_time(object)) {
TimeSourceKey time_key;
- OperationKey obdata_ubereval_key(
- &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
- add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
+ add_relation(time_key, geom_init_key, "Legacy particle time");
}
/* Object data data-block. */
build_object_data_geometry_datablock((ID *)object->data);
@@ -2198,12 +2200,33 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
add_relation(final_geometry_key, synchronize_key, "Synchronize to Original");
/* Batch cache. */
OperationKey object_data_select_key(
- obdata, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE);
+ obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT);
OperationKey object_select_key(
- &object->id, NodeType::BATCH_CACHE, OperationCode::GEOMETRY_SELECT_UPDATE);
+ &object->id, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_SELECT);
+
add_relation(object_data_select_key, object_select_key, "Data Selection -> Object Selection");
+ add_relation(final_geometry_key,
+ object_select_key,
+ "Object Geometry -> Select Update",
+ RELATION_FLAG_NO_FLUSH);
+
+ OperationKey object_data_geom_deform_key(
+ obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM);
+ OperationKey object_data_geom_init_key(
+ obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
+
+ OperationKey object_data_batch_deform_key(
+ obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_DEFORM);
+ OperationKey object_data_batch_all_key(
+ obdata, NodeType::BATCH_CACHE, OperationCode::BATCH_UPDATE_ALL);
+
+ add_relation(geom_init_key, object_data_batch_all_key, "Object Geometry -> Batch Update All");
+
add_relation(
- geom_key, object_select_key, "Object Geometry -> Select Update", RELATION_FLAG_NO_FLUSH);
+ object_data_geom_init_key, object_data_batch_all_key, "Data Init -> Batch Update All");
+ add_relation(object_data_geom_deform_key,
+ object_data_batch_deform_key,
+ "Data Deform -> Batch Update Deform");
}
void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
@@ -2221,8 +2244,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
build_shapekeys(key);
}
/* Link object data evaluation node to exit operation. */
+ OperationKey obdata_geom_deform_key(
+ obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DEFORM);
+ OperationKey obdata_geom_init_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT);
OperationKey obdata_geom_eval_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
OperationKey obdata_geom_done_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE);
+ add_relation(obdata_geom_init_key, obdata_geom_eval_key, "ObData Init -> Geom Eval");
+ add_relation(obdata_geom_deform_key, obdata_geom_eval_key, "ObData Deform -> Geom Eval");
add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done");
/* Type-specific links. */
const ID_Type id_type = GS(obdata->name);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 54c51adec66..8e3960e1a15 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -180,7 +180,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.operation_name = "";
node_identifier.operation_name_tag = -1;
/* Handling of commonly known scenarios. */
- if (prop != nullptr && RNA_property_is_idprop(prop)) {
+ if (rna_prop_affects_parameters_node(ptr, prop)) {
node_identifier.type = NodeType::PARAMETERS;
node_identifier.operation_code = OperationCode::ID_PROPERTY;
node_identifier.operation_name = RNA_property_identifier(
@@ -397,4 +397,12 @@ RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id)
return id_data.get();
}
+bool rna_prop_affects_parameters_node(const PointerRNA *ptr, const PropertyRNA *prop)
+{
+ return prop != nullptr && RNA_property_is_idprop(prop) &&
+ /* ID properties in the geometry nodes modifier don't affect that parameters node. Instead
+ they affect the modifier and therefore the geometry node directly. */
+ !RNA_struct_is_a(ptr->type, &RNA_NodesModifier);
+}
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
index d03903d508c..24d7f5f3a30 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
@@ -108,5 +108,7 @@ class RNANodeQuery {
static bool contains(const char *prop_identifier, const char *rna_path_component);
};
+bool rna_prop_affects_parameters_node(const PointerRNA *ptr, const PropertyRNA *prop);
+
} // namespace deg
} // namespace blender
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 6fe7d5f5d8b..076e15a3175 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -68,7 +68,8 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
scene(scene),
view_layer(view_layer),
mode(mode),
- ctime(BKE_scene_frame_get(scene)),
+ frame(BKE_scene_frame_get(scene)),
+ ctime(BKE_scene_ctime_get(scene)),
scene_cow(nullptr),
is_active(false),
is_evaluating(false),
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index ff536c19c05..913b61ca563 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -140,7 +140,9 @@ struct Depsgraph {
ViewLayer *view_layer;
eEvaluationMode mode;
- /* Time at which dependency graph is being or was last evaluated. */
+ /* Time at which dependency graph is being or was last evaluated.
+ * frame is the value before, and ctime the value after time remapping. */
+ float frame;
float ctime;
/* Evaluated version of datablocks we access a lot.
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 1ad3fdbc9da..cc7ce871419 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -51,7 +51,7 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph)
{
/* Update the time on the cow scene. */
if (deg_graph->scene_cow) {
- BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
+ BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->frame);
}
deg::deg_graph_flush_updates(deg_graph);
@@ -63,10 +63,12 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
const Scene *scene = DEG_get_input_scene(graph);
- const float ctime = BKE_scene_frame_get(scene);
+ const float frame = BKE_scene_frame_get(scene);
+ const float ctime = BKE_scene_ctime_get(scene);
- if (ctime != deg_graph->ctime) {
+ if (deg_graph->frame != frame || ctime != deg_graph->ctime) {
deg_graph->tag_time_source();
+ deg_graph->frame = frame;
deg_graph->ctime = ctime;
}
@@ -74,10 +76,13 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
}
/* Frame-change happened for root scene that graph belongs to. */
-void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime)
+void DEG_evaluate_on_framechange(Depsgraph *graph, float frame)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
+ const Scene *scene = DEG_get_input_scene(graph);
+
deg_graph->tag_time_source();
- deg_graph->ctime = ctime;
+ deg_graph->frame = frame;
+ deg_graph->ctime = BKE_scene_frame_to_ctime(scene, frame);
deg_flush_updates_and_refresh(deg_graph);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index b00cae87311..e879e8d0f23 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -117,7 +117,7 @@ void depsgraph_select_tag_to_component_opcode(const ID *id,
}
else if (is_selectable_data_id_type(id_type)) {
*component_type = NodeType::BATCH_CACHE;
- *operation_code = OperationCode::GEOMETRY_SELECT_UPDATE;
+ *operation_code = OperationCode::BATCH_UPDATE_SELECT;
}
else {
*component_type = NodeType::COPY_ON_WRITE;
@@ -168,6 +168,11 @@ void depsgraph_tag_to_component_opcode(const ID *id,
break;
case ID_RECALC_GEOMETRY:
depsgraph_geometry_tag_to_component(id, component_type);
+ *operation_code = OperationCode::GEOMETRY_EVAL_INIT;
+ break;
+ case ID_RECALC_GEOMETRY_DEFORM:
+ depsgraph_geometry_tag_to_component(id, component_type);
+ *operation_code = OperationCode::GEOMETRY_EVAL_DEFORM;
break;
case ID_RECALC_ANIMATION:
*component_type = NodeType::ANIMATION;
@@ -708,6 +713,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "GEOMETRY";
case ID_RECALC_GEOMETRY_ALL_MODES:
return "GEOMETRY_ALL_MODES";
+ case ID_RECALC_GEOMETRY_DEFORM:
+ return "GEOMETRY_DEFORM";
case ID_RECALC_ANIMATION:
return "ANIMATION";
case ID_RECALC_PSYS_REDO:
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 1b24e2b7ad2..2cbb0b52e34 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -144,7 +144,10 @@ inline void flush_handle_component_node(IDNode *id_node,
* special component where we don't want all operations to be tagged.
*
* TODO(sergey): Make this a more generic solution. */
- if (!ELEM(comp_node->type, NodeType::PARTICLE_SETTINGS, NodeType::PARTICLE_SYSTEM)) {
+ if (!ELEM(comp_node->type,
+ NodeType::PARTICLE_SETTINGS,
+ NodeType::PARTICLE_SYSTEM,
+ NodeType::BATCH_CACHE)) {
for (OperationNode *op : comp_node->operations) {
op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index 7e57467f905..62a3d65d1f4 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -98,6 +98,8 @@ const char *operationCodeAsString(OperationCode opcode)
/* Geometry. */
case OperationCode::GEOMETRY_EVAL_INIT:
return "GEOMETRY_EVAL_INIT";
+ case OperationCode::GEOMETRY_EVAL_DEFORM:
+ return "GEOMETRY_EVAL_DEFORM";
case OperationCode::GEOMETRY_EVAL:
return "GEOMETRY_EVAL";
case OperationCode::GEOMETRY_EVAL_DONE:
@@ -160,8 +162,12 @@ const char *operationCodeAsString(OperationCode opcode)
case OperationCode::FILE_CACHE_UPDATE:
return "FILE_CACHE_UPDATE";
/* Batch cache. */
- case OperationCode::GEOMETRY_SELECT_UPDATE:
- return "GEOMETRY_SELECT_UPDATE";
+ case OperationCode::BATCH_UPDATE_SELECT:
+ return "BATCH_UPDATE_SELECT";
+ case OperationCode::BATCH_UPDATE_DEFORM:
+ return "BATCH_UPDATE_DEFORM";
+ case OperationCode::BATCH_UPDATE_ALL:
+ return "BATCH_UPDATE_ALL";
/* Masks. */
case OperationCode::MASK_ANIMATION:
return "MASK_ANIMATION";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index a17186da941..b0130d03c69 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -100,7 +100,11 @@ enum class OperationCode {
/* Initialize evaluation of the geometry. Is an entry operation of geometry
* component. */
GEOMETRY_EVAL_INIT,
- /* Evaluate the whole geometry, including modifiers. */
+ /* Evaluate the geometry, including modifiers, and update only batches that
+ * are affected by deform operations. */
+ GEOMETRY_EVAL_DEFORM,
+ /* Evaluate the geometry, including modifiers, but don't update the batch
+ * cache. */
GEOMETRY_EVAL,
/* Evaluation of geometry is completely done. */
GEOMETRY_EVAL_DONE,
@@ -178,7 +182,9 @@ enum class OperationCode {
WORLD_UPDATE,
/* Batch caches. -------------------------------------------------------- */
- GEOMETRY_SELECT_UPDATE,
+ BATCH_UPDATE_SELECT,
+ BATCH_UPDATE_DEFORM,
+ BATCH_UPDATE_ALL,
/* Masks. --------------------------------------------------------------- */
MASK_ANIMATION,
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 1227f4db8e4..ad154704d2c 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -51,14 +51,14 @@ set(INC
set(SRC
intern/draw_cache.c
+ intern/draw_cache_extract_mesh.cc
intern/draw_cache_extract_mesh_extractors.c
intern/draw_cache_extract_mesh_render_data.c
- intern/draw_cache_extract_mesh.cc
intern/mesh_extractors/extract_mesh_ibo_edituv.cc
intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+ intern/mesh_extractors/extract_mesh_ibo_lines.cc
intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
- intern/mesh_extractors/extract_mesh_ibo_lines.cc
intern/mesh_extractors/extract_mesh_ibo_points.cc
intern/mesh_extractors/extract_mesh_ibo_tris.cc
intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -205,8 +205,8 @@ set(SRC
intern/draw_manager_profiling.h
intern/draw_manager_testing.h
intern/draw_manager_text.h
- intern/draw_view.h
intern/draw_shader.h
+ intern/draw_view.h
intern/smaa_textures.h
engines/basic/basic_engine.h
engines/eevee/eevee_engine.h
@@ -515,6 +515,8 @@ if(WITH_GTESTS)
set(TEST_SRC
tests/draw_testing.cc
tests/shaders_test.cc
+
+ tests/draw_testing.hh
)
set(TEST_INC
"../../../intern/ghost/"
diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c
index 2522a445d8e..b6fd73e76d1 100644
--- a/source/blender/draw/engines/image/image_engine.c
+++ b/source/blender/draw/engines/image/image_engine.c
@@ -31,6 +31,7 @@
#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
+#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "ED_image.h"
@@ -222,19 +223,30 @@ static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser
copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
}
else if ((sima_flag & SI_SHOW_R) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
}
else if ((sima_flag & SI_SHOW_G) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
}
else if ((sima_flag & SI_SHOW_B) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
}
else /* RGB */ {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
}
}
if (space_type == SPACE_NODE) {
@@ -248,19 +260,30 @@ static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser
copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f);
}
else if ((snode->flag & SNODE_SHOW_R) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
}
else if ((snode->flag & SNODE_SHOW_G) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
}
else if ((snode->flag & SNODE_SHOW_B) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA | IMAGE_DRAW_FLAG_SHUFFLING;
+ draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
}
else /* RGB */ {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index ec5d43683d1..1da682ff01b 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -37,6 +37,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_deform.h"
#include "BKE_modifier.h"
#include "DEG_depsgraph_query.h"
@@ -1293,10 +1294,9 @@ static void draw_axes(ArmatureDrawContext *ctx,
const bArmature *arm)
{
float final_col[4];
- const float *col = (ctx->const_color) ?
- ctx->const_color :
- (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? G_draw.block.colorTextHi :
- G_draw.block.colorText;
+ const float *col = (ctx->const_color) ? ctx->const_color :
+ (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? G_draw.block.colorTextHi :
+ G_draw.block.colorText;
copy_v4_v4(final_col, col);
/* Mix with axes color. */
final_col[3] = (ctx->const_color) ? 1.0 : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.1 : 0.65;
@@ -2040,7 +2040,8 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
const Object *obact_orig = DEG_get_original_object(draw_ctx->obact);
- LISTBASE_FOREACH (bDeformGroup *, dg, &obact_orig->defbase) {
+ const ListBase *defbase = BKE_object_defgroup_list(obact_orig);
+ LISTBASE_FOREACH (const bDeformGroup *, dg, defbase) {
if (dg->flag & DG_LOCK_WEIGHT) {
pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
index 7639911286f..a7ed6c777e8 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -26,6 +26,7 @@
#include "DNA_mesh_types.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "draw_cache_impl.h"
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index 01ab47ac1de..c2b130163e8 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -24,6 +24,7 @@
#include "draw_cache_impl.h"
#include "draw_manager_text.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_image.h"
#include "BKE_layer.h"
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 5c83047b18f..a2e8dc20907 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3274,8 +3274,8 @@ GPUBatch *DRW_cache_lattice_wire_get(Object *ob, bool use_weight)
Lattice *lt = ob->data;
int actdef = -1;
- if (use_weight && ob->defbase.first && lt->editlatt->latt->dvert) {
- actdef = ob->actdef - 1;
+ if (use_weight && !BLI_listbase_is_empty(&lt->vertex_group_names) && lt->editlatt->latt->dvert) {
+ actdef = lt->vertex_group_active_index - 1;
}
return DRW_lattice_batch_cache_get_all_edges(lt, use_weight, actdef);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index be61b0a9baf..a0694a08f0b 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -36,7 +36,7 @@ typedef struct DRW_MeshWeightState {
short flags;
char alert_mode;
- /* Set of all selected bones for Multipaint. */
+ /* Set of all selected bones for Multi-paint. */
bool *defgroup_sel; /* [defgroup_len] */
int defgroup_sel_count;
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 2424b0f9fee..5f670bdc5ec 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
@@ -30,6 +30,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "draw_cache_extract.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index 7fe543db01f..336ccd40d5c 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -844,8 +844,8 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in
int vert_len = GPU_vertbuf_get_vertex_len(cache->vbo);
gpEditIterData iter;
- iter.vgindex = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, iter.vgindex)) {
+ iter.vgindex = gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gpd->vertex_group_names, iter.vgindex)) {
iter.vgindex = -1;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 41047191efe..0c002ff09f2 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -544,8 +544,8 @@ static void drw_mesh_weight_state_extract(Object *ob,
/* Extract complete vertex weight group selection state and mode flags. */
memset(wstate, 0, sizeof(*wstate));
- wstate->defgroup_active = ob->actdef - 1;
- wstate->defgroup_len = BLI_listbase_count(&ob->defbase);
+ wstate->defgroup_active = me->vertex_group_active_index - 1;
+ wstate->defgroup_len = BLI_listbase_count(&me->vertex_group_names);
wstate->alert_mode = ts->weightuser;
@@ -821,6 +821,17 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
mesh_batch_cache_discard_shaded_tri(cache);
mesh_batch_cache_discard_uvedit(cache);
break;
+ case BKE_MESH_BATCH_DIRTY_DEFORM:
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_pos);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.tris);
+ }
+ batch_map = MDEPS_CREATE_MAP(vbo.pos_nor, vbo.lnor, vbo.fdots_pos, vbo.fdots_nor, ibo.tris);
+ mesh_batch_cache_discard_batch(cache, batch_map);
+ break;
case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL:
mesh_batch_cache_discard_uvedit(cache);
break;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 62742d082ca..6f5e041fa79 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1645,7 +1645,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
drw_engines_draw_scene();
- /* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */
+ /* Fix 3D view "lagging" on APPLE and WIN32+NVIDIA. (See T56996, T61474) */
GPU_flush();
DRW_stats_reset();
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 76b6ce54d29..8f8c1c067d4 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1283,6 +1283,9 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
else {
group_fcurves_last->next->prev = group_fcurves_first->prev;
}
+
+ /* Clear links pointing outside the per-group list. */
+ group_fcurves_first->prev = group_fcurves_last->next = NULL;
}
/* Initialize memory for temp-group */
@@ -1337,24 +1340,12 @@ static void join_groups_action_temp(bAction *act)
if (agrp->flag & AGRP_TEMP) {
LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) {
fcu->grp = NULL;
- if (fcu == agrp->channels.last) {
- break;
- }
}
BLI_remlink(&act->groups, agrp);
break;
}
}
-
- /* 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. */
- 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
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 16eb2f6b6f2..bfaa76b3bf9 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -80,7 +80,7 @@ FCurve *verify_driver_fcurve(ID *id,
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
- adt = BKE_animdata_add_id(id);
+ adt = BKE_animdata_ensure_id(id);
}
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 864d97c9ea9..0a499232ba9 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -142,7 +142,7 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if (adt == NULL) {
- adt = BKE_animdata_add_id(id);
+ adt = BKE_animdata_ensure_id(id);
}
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 034378399b9..6af033f3cf2 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -109,7 +109,7 @@ static void draw_current_frame(const Scene *scene,
if (draw_line) {
/* Draw vertical line to from the bottom of the current frame box to the bottom of the screen.
*/
- const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_frame_get(scene));
+ const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_ctime_get(scene));
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index fc9191967f8..ec5c665402b 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -478,7 +478,7 @@ void ED_object_vgroup_calc_from_armature(ReportList *reports,
bArmature *arm = par->data;
if (mode == ARM_GROUPS_NAME) {
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const int defbase_tot = BKE_object_defgroup_count(ob);
int defbase_add;
/* Traverse the bone list, trying to create empty vertex
* groups corresponding to the bone.
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 725945f8edc..832e75b2a8b 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -206,7 +206,7 @@ static void armature_undosys_step_decode(struct bContext *C,
}
undoarm_to_editarm(&elem->data, arm);
arm->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&arm->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 88f6398567d..210411c6eb5 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -267,7 +267,7 @@ static void curve_undosys_step_decode(struct bContext *C,
}
undocurve_to_editcurve(bmain, &elem->data, obedit->data, &obedit->shapenr);
cu->editnurb->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index b61506d9346..6eaf8971eb0 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -379,7 +379,7 @@ static void font_undosys_step_decode(struct bContext *C,
Curve *cu = obedit->data;
undofont_to_editfont(&us->data, cu);
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
ED_undo_object_set_active_or_warn(
CTX_data_scene(C), CTX_data_view_layer(C), obedit, us_p->name, &LOG);
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index d8734c4ae6b..8d60ef3ed12 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -39,6 +39,32 @@
#include "ED_gpencil.h"
+/**
+ * Populate stroke with point data from data buffers.
+ * \param gps: Grease pencil stroke
+ * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
+ * \param totpoints: Total of points
+ * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
+ */
+void ED_gpencil_stroke_init_data(bGPDstroke *gps,
+ const float *array,
+ const int totpoints,
+ const float mat[4][4])
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ const int x = GP_PRIM_DATABUF_SIZE * i;
+
+ pt->x = array[x];
+ pt->y = array[x + 1];
+ pt->z = array[x + 2];
+ mul_m4_v3(mat, &pt->x);
+
+ pt->pressure = array[x + 3];
+ pt->strength = array[x + 4];
+ }
+}
+
/* Definition of the most important info from a color */
typedef struct ColorTemplate {
const char *name;
@@ -847,115 +873,115 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
/* generate strokes */
gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false);
- BKE_gpencil_stroke_add_points(gps, data0, 270, mat);
+ ED_gpencil_stroke_init_data(gps, data0, 270, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data1, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data1, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 60, false);
- BKE_gpencil_stroke_add_points(gps, data2, 18, mat);
+ ED_gpencil_stroke_init_data(gps, data2, 18, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false);
- BKE_gpencil_stroke_add_points(gps, data3, 64, mat);
+ ED_gpencil_stroke_init_data(gps, data3, 64, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data4, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data4, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false);
- BKE_gpencil_stroke_add_points(gps, data5, 64, mat);
+ ED_gpencil_stroke_init_data(gps, data5, 64, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data6, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data6, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 18, 40, false);
- BKE_gpencil_stroke_add_points(gps, data7, 18, mat);
+ ED_gpencil_stroke_init_data(gps, data7, 18, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false);
- BKE_gpencil_stroke_add_points(gps, data8, 49, mat);
+ ED_gpencil_stroke_init_data(gps, data8, 49, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data9, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data9, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false);
- BKE_gpencil_stroke_add_points(gps, data10, 49, mat);
+ ED_gpencil_stroke_init_data(gps, data10, 49, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false);
- BKE_gpencil_stroke_add_points(gps, data11, 18, mat);
+ ED_gpencil_stroke_init_data(gps, data11, 18, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false);
- BKE_gpencil_stroke_add_points(gps, data12, 18, mat);
+ ED_gpencil_stroke_init_data(gps, data12, 18, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data13, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data13, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data14, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data14, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 65, 60, false);
- BKE_gpencil_stroke_add_points(gps, data15, 65, mat);
+ ED_gpencil_stroke_init_data(gps, data15, 65, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 60, false);
- BKE_gpencil_stroke_add_points(gps, data16, 34, mat);
+ ED_gpencil_stroke_init_data(gps, data16, 34, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data17, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data17, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 40, false);
- BKE_gpencil_stroke_add_points(gps, data18, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data18, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 40, false);
- BKE_gpencil_stroke_add_points(gps, data19, 34, mat);
+ ED_gpencil_stroke_init_data(gps, data19, 34, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data20, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data20, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 64, 60, false);
- BKE_gpencil_stroke_add_points(gps, data21, 64, mat);
+ ED_gpencil_stroke_init_data(gps, data21, 64, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false);
- BKE_gpencil_stroke_add_points(gps, data22, 26, mat);
+ ED_gpencil_stroke_init_data(gps, data22, 26, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false);
- BKE_gpencil_stroke_add_points(gps, data23, 26, mat);
+ ED_gpencil_stroke_init_data(gps, data23, 26, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data24, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data24, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false);
- BKE_gpencil_stroke_add_points(gps, data25, 18, mat);
+ ED_gpencil_stroke_init_data(gps, data25, 18, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false);
- BKE_gpencil_stroke_add_points(gps, data26, 18, mat);
+ ED_gpencil_stroke_init_data(gps, data26, 18, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
- BKE_gpencil_stroke_add_points(gps, data27, 33, mat);
+ ED_gpencil_stroke_init_data(gps, data27, 33, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
/* update depsgraph */
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index e95496b51ee..73c4e64dd9a 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -235,7 +235,7 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
/* generate stroke */
gps = BKE_gpencil_stroke_add(frame_lines, color_black, 175, 75, false);
- BKE_gpencil_stroke_add_points(gps, data0, 175, mat);
+ ED_gpencil_stroke_init_data(gps, data0, 175, mat);
BKE_gpencil_stroke_geometry_update(gpd, gps);
/* update depsgraph */
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index 24fb0873a86..c800851bb08 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -384,7 +384,7 @@ static void gpencil_add_verts_to_dgroups(
/* loop groups and assign weight */
for (j = 0; j < numbones; j++) {
- int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]);
+ int def_nr = BLI_findindex(&gpd->vertex_group_names, dgrouplist[j]);
if (def_nr < 0) {
continue;
}
@@ -454,7 +454,7 @@ static void gpencil_object_vgroup_calc_from_armature(const bContext *C,
bArmature *arm = ob_arm->data;
/* always create groups */
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const int defbase_tot = BKE_object_defgroup_count(ob);
int defbase_add;
/* Traverse the bone list, trying to create empty vertex
* groups corresponding to the bone.
diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.c b/source/blender/editors/gpencil/gpencil_bake_animation.c
index 1a5e2950e09..2d299230124 100644
--- a/source/blender/editors/gpencil/gpencil_bake_animation.c
+++ b/source/blender/editors/gpencil/gpencil_bake_animation.c
@@ -38,6 +38,7 @@
#include "BKE_duplilist.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -303,8 +304,12 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
float matrix[4][4];
BKE_gpencil_layer_transform_matrix_get(depsgraph, elem->ob, gpl_src, matrix);
+ /* Apply time modifier. */
+ int remap_cfra = BKE_gpencil_time_modifier_cfra(
+ depsgraph, scene, elem->ob, gpl_src, CFRA, false);
/* Duplicate frame. */
- bGPDframe *gpf_src = BKE_gpencil_layer_frame_get(gpl_src, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf_src = BKE_gpencil_layer_frame_get(
+ gpl_src, remap_cfra, GP_GETFRAME_USE_PREV);
if (gpf_src == NULL) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index e272f46d13d..b1e57079d28 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -2165,7 +2165,9 @@ static bool gpencil_vertex_group_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL)) {
- if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ const bGPdata *gpd = (const bGPdata *)ob->data;
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) &&
+ !BLI_listbase_is_empty(&gpd->vertex_group_names)) {
if (ELEM(ob->mode, OB_MODE_EDIT_GPENCIL, OB_MODE_SCULPT_GPENCIL)) {
return true;
}
@@ -2180,7 +2182,9 @@ static bool gpencil_vertex_group_weight_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL)) {
- if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ const bGPdata *gpd = (const bGPdata *)ob->data;
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) &&
+ !BLI_listbase_is_empty(&gpd->vertex_group_names)) {
if (ob->mode == OB_MODE_WEIGHT_GPENCIL) {
return true;
}
@@ -2333,6 +2337,7 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ob->data;
/* sanity checks */
if (ELEM(NULL, ts, ob, ob->data)) {
@@ -2340,8 +2345,9 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
}
MDeformVert *dvert;
- const int def_nr = ob->actdef - 1;
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
+ const int def_nr = gpd->vertex_group_active_index - 1;
+
+ bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, def_nr);
if (defgroup == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2373,7 +2379,6 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers */
- bGPdata *gpd = ob->data;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
@@ -2403,14 +2408,15 @@ static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ob->data;
/* sanity checks */
if (ELEM(NULL, ts, ob, ob->data)) {
return OPERATOR_CANCELLED;
}
- const int def_nr = ob->actdef - 1;
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, def_nr);
if (defgroup == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2470,7 +2476,6 @@ static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers */
- bGPdata *gpd = ob->data;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
@@ -2500,6 +2505,7 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ob->data;
/* sanity checks */
if (ELEM(NULL, ts, ob, ob->data)) {
@@ -2508,8 +2514,8 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
MDeformVert *dvert = NULL;
MDeformWeight *dw = NULL;
- const int def_nr = ob->actdef - 1;
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, def_nr);
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, def_nr);
if (defgroup == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2548,7 +2554,6 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers */
- bGPdata *gpd = ob->data;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
@@ -2576,6 +2581,7 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
+ bGPdata *gpd = ob->data;
/* sanity checks */
if (ELEM(NULL, ts, ob, ob->data)) {
@@ -2585,8 +2591,8 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
bDeformGroup *defgroup = NULL;
MDeformVert *dvert = NULL;
MDeformWeight *dw = NULL;
- const int def_nr = ob->actdef - 1;
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ const int defbase_tot = BLI_listbase_count(&gpd->vertex_group_names);
if (defbase_tot == 0) {
return OPERATOR_CANCELLED;
}
@@ -2603,7 +2609,7 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
for (int i = 0; i < gps->totpoints; i++) {
dvert = &gps->dvert[i];
for (int v = 0; v < defbase_tot; v++) {
- defgroup = BLI_findlink(&ob->defbase, v);
+ defgroup = BLI_findlink(&gpd->vertex_group_names, v);
/* skip NULL or locked groups */
if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
continue;
@@ -2629,7 +2635,7 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
dvert = &gps->dvert[i];
for (int v = 0; v < defbase_tot; v++) {
- defgroup = BLI_findlink(&ob->defbase, v);
+ defgroup = BLI_findlink(&gpd->vertex_group_names, v);
/* skip NULL or locked groups */
if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
continue;
@@ -2653,7 +2659,6 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers */
- bGPdata *gpd = ob->data;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
@@ -2769,7 +2774,6 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob_active = CTX_data_active_object(C);
- bGPdata *gpd_dst = NULL;
bool ok = false;
/* Ensure we're in right mode and that the active object is correct */
@@ -2807,7 +2811,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- gpd_dst = ob_active->data;
+ bGPdata *gpd_dst = ob_active->data;
Object *ob_dst = ob_active;
/* loop and join all data */
@@ -2828,11 +2832,11 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
/* copy vertex groups to the base one's */
int old_idx = 0;
- LISTBASE_FOREACH (bDeformGroup *, dg, &ob_iter->defbase) {
+ LISTBASE_FOREACH (bDeformGroup *, dg, &gpd_src->vertex_group_names) {
bDeformGroup *vgroup = MEM_dupallocN(dg);
- int idx = BLI_listbase_count(&ob_active->defbase);
+ int idx = BLI_listbase_count(&gpd_dst->vertex_group_names);
BKE_object_defgroup_unique_name(vgroup, ob_active);
- BLI_addtail(&ob_active->defbase, vgroup);
+ BLI_addtail(&gpd_dst->vertex_group_names, vgroup);
/* update vertex groups in strokes in original data */
LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_src->frames) {
@@ -2852,8 +2856,9 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
}
old_idx++;
}
- if (ob_active->defbase.first && ob_active->actdef == 0) {
- ob_active->actdef = 1;
+ if (!BLI_listbase_is_empty(&gpd_dst->vertex_group_names) &&
+ gpd_dst->vertex_group_active_index == 0) {
+ gpd_dst->vertex_group_active_index = 1;
}
/* add missing materials reading source materials and checking in destination object */
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 091ff2c16b0..67e1bd5294b 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1522,8 +1522,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
pt = gps->points;
point2D = (tGPspoint *)tgpf->sbuffer;
- const int def_nr = tgpf->ob->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
+ const int def_nr = tgpf->gpd->vertex_group_active_index - 1;
+ const bool have_weight = (bool)BLI_findlink(&tgpf->gpd->vertex_group_names, def_nr);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
BKE_gpencil_dvert_ensure(gps);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 67d4b7726b5..d6f6dbb2b10 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -938,8 +938,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
Depsgraph *depsgraph = p->depsgraph;
Object *obact = (Object *)p->ownerPtr.data;
RegionView3D *rv3d = p->region->regiondata;
- const int def_nr = obact->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ const bool have_weight = (bool)BLI_findlink(&gpd->vertex_group_names, def_nr);
const char align_flag = ts->gpencil_v3d_align;
const bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
const bool is_lock_axis_view = (bool)(ts->gp_sculpt.lock_axis == 0);
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index a2b4e5dee64..78eaab01b1a 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -1315,8 +1315,9 @@ static void gpencil_primitive_interaction_end(bContext *C,
Brush *brush = tgpi->brush;
BrushGpencilSettings *brush_settings = brush->gpencil_settings;
- const int def_nr = tgpi->ob->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
+ const int def_nr = tgpi->gpd->vertex_group_active_index - 1;
+ const ListBase *defbase = BKE_object_defgroup_list(tgpi->ob);
+ const bool have_weight = (bool)BLI_findlink(defbase, def_nr);
/* return to normal cursor and header status */
ED_workspace_status_text(C, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index efd0f86df03..462462cf341 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -1177,8 +1177,8 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->object = ob;
if (ob) {
invert_m4_m4(gso->inv_mat, ob->obmat);
- gso->vrgroup = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
+ gso->vrgroup = gso->gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup)) {
gso->vrgroup = -1;
}
/* Check if some modifier can transform the stroke. */
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index e6488cfe454..ba3d3b584d7 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -1600,8 +1600,8 @@ void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
return;
}
@@ -1654,8 +1654,8 @@ void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
return;
}
@@ -1707,8 +1707,8 @@ void ED_gpencil_vgroup_select(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
return;
}
@@ -1762,8 +1762,8 @@ void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const int def_nr = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const int def_nr = gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gpd->vertex_group_names, def_nr)) {
return;
}
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 6d953a4d8cf..d14322e12b5 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -252,7 +252,7 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso,
}
}
else {
- bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
+ bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup);
if (defgroup->flag & DG_LOCK_WEIGHT) {
return false;
}
@@ -308,8 +308,8 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op)
gso->scene = scene;
gso->object = ob;
if (ob) {
- gso->vrgroup = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
+ gso->vrgroup = gso->gpd->vertex_group_active_index - 1;
+ if (!BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup)) {
gso->vrgroup = -1;
}
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 59b5a1abaa6..8a8d91a570c 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -251,6 +251,13 @@ void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
/* ----------- Add Primitive Utilities -------------- */
+/* Number of values defining each point in the built-in data buffers for primitives. */
+#define GP_PRIM_DATABUF_SIZE 5
+void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
+ const float *array,
+ const int totpoints,
+ const float mat[4][4]);
+
void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]);
void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]);
void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 0493832c06f..673f629d6ef 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -468,7 +468,7 @@ bool fcurve_is_changed(struct PointerRNA ptr,
* Checks whether a keyframe exists for the given ID-block one the given frame.
* - It is recommended to call this method over the other keyframe-checkers directly,
* in case some detail of the implementation changes...
- * - frame: the value of this is quite often result of #BKE_scene_frame_get()
+ * - frame: the value of this is quite often result of #BKE_scene_ctime_get()
*/
bool id_frame_has_keyframe(struct ID *id, float frame, short filter);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 667540b8f63..2b73194afb2 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -86,7 +86,7 @@ void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
-void EDBM_mesh_free(struct BMEditMesh *em);
+void EDBM_mesh_free_data(struct BMEditMesh *em);
void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 6901176a587..802c175492f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -58,6 +58,7 @@ struct bNodeTree;
struct bScreen;
struct rctf;
struct rcti;
+struct uiBlockInteraction_Handle;
struct uiButSearch;
struct uiFontStyle;
struct uiList;
@@ -514,6 +515,54 @@ typedef int (*uiButPushedStateFunc)(struct uiBut *but, const void *arg);
typedef void (*uiBlockHandleFunc)(struct bContext *C, void *arg, int event);
+/* -------------------------------------------------------------------- */
+/** \name Custom Interaction
+ *
+ * Sometimes it's useful to create data that remains available
+ * while the user interacts with a button.
+ *
+ * A common case is dragging a number button or slider
+ * however this could be used in other cases too.
+ * \{ */
+
+struct uiBlockInteraction_Params {
+ /**
+ * When true, this interaction is not modal
+ * (user clicking on a number button arrows or pasting a value for example).
+ */
+ bool is_click;
+ /**
+ * Array of unique event ID's (values from #uiBut.retval).
+ * There may be more than one for multi-button editing (see #UI_BUT_DRAG_MULTI).
+ */
+ int *unique_retval_ids;
+ uint unique_retval_ids_len;
+};
+
+/** Returns 'user_data', freed by #uiBlockInteractionEndFn. */
+typedef void *(*uiBlockInteractionBeginFn)(struct bContext *C,
+ const struct uiBlockInteraction_Params *params,
+ void *arg1);
+typedef void (*uiBlockInteractionEndFn)(struct bContext *C,
+ const struct uiBlockInteraction_Params *params,
+ void *arg1,
+ void *user_data);
+typedef void (*uiBlockInteractionUpdateFn)(struct bContext *C,
+ const struct uiBlockInteraction_Params *params,
+ void *arg1,
+ void *user_data);
+
+typedef struct uiBlockInteraction_CallbackData {
+ uiBlockInteractionBeginFn begin_fn;
+ uiBlockInteractionEndFn end_fn;
+ uiBlockInteractionUpdateFn update_fn;
+ void *arg1;
+} uiBlockInteraction_CallbackData;
+
+void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks);
+
+/** \} */
+
/* Menu Callbacks */
typedef void (*uiMenuCreateFunc)(struct bContext *C, struct uiLayout *layout, void *arg1);
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index de0d5a4a3d7..2a7611eabb1 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -560,7 +560,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
/* Set the (button_pointer, button_prop)
- * and pointer data for Python access to the hovered ui element. */
+ * and pointer data for Python access to the hovered UI element. */
uiLayoutSetContextFromBut(layout, but);
/* Keyframes */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 743f646d4df..0e45970a165 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -35,10 +35,12 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "BLI_array_utils.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_sort_utils.h"
#include "BLI_string.h"
#include "BLI_string_cursor_utf8.h"
#include "BLI_string_utf8.h"
@@ -170,6 +172,20 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but
static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str);
static void button_tooltip_timer_reset(bContext *C, uiBut *but);
+static void ui_block_interaction_begin_ensure(bContext *C,
+ uiBlock *block,
+ struct uiHandleButtonData *data,
+ const bool is_click);
+static struct uiBlockInteraction_Handle *ui_block_interaction_begin(struct bContext *C,
+ uiBlock *block,
+ const bool is_click);
+static void ui_block_interaction_end(struct bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ struct uiBlockInteraction_Handle *interaction);
+static void ui_block_interaction_update(struct bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ struct uiBlockInteraction_Handle *interaction);
+
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -225,6 +241,19 @@ typedef enum uiMenuScrollType {
MENU_SCROLL_BOTTOM,
} uiMenuScrollType;
+typedef struct uiBlockInteraction_Handle {
+ struct uiBlockInteraction_Params params;
+ void *user_data;
+ /**
+ * This is shared between #uiHandleButtonData and #uiAfterFunc,
+ * the last user runs the end callback and frees the data.
+ *
+ * This is needed as the order of freeing changes depending on
+ * accepting/canceling the operation.
+ */
+ int user_count;
+} uiBlockInteraction_Handle;
+
#ifdef USE_ALLSELECT
/* Unfortunately there's no good way handle more generally:
@@ -430,6 +459,8 @@ typedef struct uiHandleButtonData {
uiSelectContextStore select_others;
#endif
+ struct uiBlockInteraction_Handle *custom_interaction_handle;
+
/* Text field undo. */
struct uiUndoStack_Text *undo_stack_text;
@@ -471,6 +502,9 @@ typedef struct uiAfterFunc {
void *search_arg;
uiFreeArgFunc search_arg_free_fn;
+ uiBlockInteraction_CallbackData custom_interaction_callbacks;
+ uiBlockInteraction_Handle *custom_interaction_handle;
+
bContextStore *context;
char undostr[BKE_UNDO_STR_MAX];
@@ -769,72 +803,95 @@ static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
(block->handle && block->handle->popup_op));
}
+/**
+ * These functions are postponed and only executed after all other
+ * handling is done, i.e. menus are closed, in order to avoid conflicts
+ * with these functions removing the buttons we are working with.
+ */
static void ui_apply_but_func(bContext *C, uiBut *but)
{
uiBlock *block = but->block;
+ if (!ui_afterfunc_check(block, but)) {
+ return;
+ }
- /* these functions are postponed and only executed after all other
- * handling is done, i.e. menus are closed, in order to avoid conflicts
- * with these functions removing the buttons we are working with */
-
- if (ui_afterfunc_check(block, but)) {
- uiAfterFunc *after = ui_afterfunc_new();
+ uiAfterFunc *after = ui_afterfunc_new();
- if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
- /* exception, this will crash due to removed button otherwise */
- but->func(C, but->func_arg1, but->func_arg2);
- }
- else {
- after->func = but->func;
- }
+ if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
+ /* exception, this will crash due to removed button otherwise */
+ but->func(C, but->func_arg1, but->func_arg2);
+ }
+ else {
+ after->func = but->func;
+ }
- after->func_arg1 = but->func_arg1;
- after->func_arg2 = but->func_arg2;
+ after->func_arg1 = but->func_arg1;
+ after->func_arg2 = but->func_arg2;
- after->funcN = but->funcN;
- after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : NULL;
+ after->funcN = but->funcN;
+ after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : NULL;
- after->rename_func = but->rename_func;
- after->rename_arg1 = but->rename_arg1;
- after->rename_orig = but->rename_orig; /* needs free! */
+ after->rename_func = but->rename_func;
+ after->rename_arg1 = but->rename_arg1;
+ after->rename_orig = but->rename_orig; /* needs free! */
- after->handle_func = block->handle_func;
- after->handle_func_arg = block->handle_func_arg;
- after->retval = but->retval;
+ after->handle_func = block->handle_func;
+ after->handle_func_arg = block->handle_func_arg;
+ after->retval = but->retval;
- if (but->type == UI_BTYPE_BUT_MENU) {
- after->butm_func = block->butm_func;
- after->butm_func_arg = block->butm_func_arg;
- after->a2 = but->a2;
- }
+ if (but->type == UI_BTYPE_BUT_MENU) {
+ after->butm_func = block->butm_func;
+ after->butm_func_arg = block->butm_func_arg;
+ after->a2 = but->a2;
+ }
- if (block->handle) {
- after->popup_op = block->handle->popup_op;
- }
+ if (block->handle) {
+ after->popup_op = block->handle->popup_op;
+ }
- after->optype = but->optype;
- after->opcontext = but->opcontext;
- after->opptr = but->opptr;
+ after->optype = but->optype;
+ after->opcontext = but->opcontext;
+ after->opptr = but->opptr;
- after->rnapoin = but->rnapoin;
- after->rnaprop = but->rnaprop;
+ after->rnapoin = but->rnapoin;
+ after->rnaprop = but->rnaprop;
- if (but->type == UI_BTYPE_SEARCH_MENU) {
- uiButSearch *search_but = (uiButSearch *)but;
- after->search_arg_free_fn = search_but->arg_free_fn;
- after->search_arg = search_but->arg;
- search_but->arg_free_fn = NULL;
- search_but->arg = NULL;
- }
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
+ uiButSearch *search_but = (uiButSearch *)but;
+ after->search_arg_free_fn = search_but->arg_free_fn;
+ after->search_arg = search_but->arg;
+ search_but->arg_free_fn = NULL;
+ search_but->arg = NULL;
+ }
- if (but->context) {
- after->context = CTX_store_copy(but->context);
+ if (but->active != NULL) {
+ uiHandleButtonData *data = but->active;
+ if (data->custom_interaction_handle != NULL) {
+ after->custom_interaction_callbacks = block->custom_interaction_callbacks;
+ after->custom_interaction_handle = data->custom_interaction_handle;
+
+ /* Ensure this callback runs once and last. */
+ uiAfterFunc *after_prev = after->prev;
+ if (after_prev &&
+ (after_prev->custom_interaction_handle == data->custom_interaction_handle)) {
+ after_prev->custom_interaction_handle = NULL;
+ memset(&after_prev->custom_interaction_callbacks,
+ 0x0,
+ sizeof(after_prev->custom_interaction_callbacks));
+ }
+ else {
+ after->custom_interaction_handle->user_count++;
+ }
}
+ }
- but->optype = NULL;
- but->opcontext = 0;
- but->opptr = NULL;
+ if (but->context) {
+ after->context = CTX_store_copy(but->context);
}
+
+ but->optype = NULL;
+ but->opcontext = 0;
+ but->opptr = NULL;
}
/* typically call ui_apply_but_undo(), ui_apply_but_autokey() */
@@ -997,6 +1054,18 @@ static void ui_apply_but_funcs_after(bContext *C)
after.search_arg_free_fn(after.search_arg);
}
+ if (after.custom_interaction_handle != NULL) {
+ after.custom_interaction_handle->user_count--;
+ BLI_assert(after.custom_interaction_handle->user_count >= 0);
+ if (after.custom_interaction_handle->user_count == 0) {
+ ui_block_interaction_update(
+ C, &after.custom_interaction_callbacks, after.custom_interaction_handle);
+ ui_block_interaction_end(
+ C, &after.custom_interaction_callbacks, after.custom_interaction_handle);
+ }
+ after.custom_interaction_handle = NULL;
+ }
+
ui_afterfunc_update_preferences_dirty(&after);
if (after.undostr[0]) {
@@ -2283,6 +2352,11 @@ static void ui_apply_but(
uiButCurveProfile *but_profile = (uiButCurveProfile *)but;
but_profile->edit_profile = editprofile;
}
+
+ if (data->custom_interaction_handle != NULL) {
+ ui_block_interaction_update(
+ C, &block->custom_interaction_callbacks, data->custom_interaction_handle);
+ }
}
/** \} */
@@ -4852,6 +4926,8 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but,
return changed;
}
+ ui_block_interaction_begin_ensure(but->block->evil_C, but->block, data, false);
+
if (ui_but_is_cursor_warp(but)) {
const float softmin = but->softmin;
const float softmax = but->softmax;
@@ -5362,6 +5438,8 @@ static bool ui_numedit_but_SLI(uiBut *but,
return changed;
}
+ ui_block_interaction_begin_ensure(but->block->evil_C, but->block, data, false);
+
const PropertyScaleType scale_type = ui_but_scale_type(but);
softmin = but->softmin;
@@ -8239,6 +8317,16 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
but->flag &= ~UI_SELECT;
}
+ if (state == BUTTON_STATE_TEXT_EDITING) {
+ ui_block_interaction_begin_ensure(C, but->block, data, true);
+ }
+ else if (state == BUTTON_STATE_EXIT) {
+ if (data->state == BUTTON_STATE_NUM_EDITING) {
+ /* This happens on pasting values for example. */
+ ui_block_interaction_begin_ensure(C, but->block, data, true);
+ }
+ }
+
data->state = state;
if (state != BUTTON_STATE_EXIT) {
@@ -8467,6 +8555,21 @@ static void button_activate_exit(
ED_region_tag_redraw_no_rebuild(data->region);
ED_region_tag_refresh_ui(data->region);
+ if ((but->flag & UI_BUT_DRAG_MULTI) == 0) {
+ if (data->custom_interaction_handle != NULL) {
+ /* Should only set when the button is modal. */
+ BLI_assert(but->active != NULL);
+ data->custom_interaction_handle->user_count--;
+
+ BLI_assert(data->custom_interaction_handle->user_count >= 0);
+ if (data->custom_interaction_handle->user_count == 0) {
+ ui_block_interaction_end(
+ C, &but->block->custom_interaction_callbacks, data->custom_interaction_handle);
+ }
+ data->custom_interaction_handle = NULL;
+ }
+ }
+
/* clean up button */
if (but->active) {
MEM_freeN(but->active);
@@ -11314,3 +11417,100 @@ bool UI_but_active_drop_color(bContext *C)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Block Interaction API
+ * \{ */
+
+void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks)
+{
+ block->custom_interaction_callbacks = *callbacks;
+}
+
+static uiBlockInteraction_Handle *ui_block_interaction_begin(bContext *C,
+ uiBlock *block,
+ const bool is_click)
+{
+ BLI_assert(block->custom_interaction_callbacks.begin_fn != NULL);
+ uiBlockInteraction_Handle *interaction = MEM_callocN(sizeof(*interaction), __func__);
+
+ int unique_retval_ids_len = 0;
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) {
+ unique_retval_ids_len++;
+ }
+ }
+
+ int *unique_retval_ids = MEM_mallocN(sizeof(*unique_retval_ids) * unique_retval_ids_len,
+ __func__);
+ unique_retval_ids_len = 0;
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) {
+ unique_retval_ids[unique_retval_ids_len++] = but->retval;
+ }
+ }
+
+ if (unique_retval_ids_len > 1) {
+ qsort(unique_retval_ids, unique_retval_ids_len, sizeof(int), BLI_sortutil_cmp_int);
+ unique_retval_ids_len = BLI_array_deduplicate_ordered(unique_retval_ids,
+ unique_retval_ids_len);
+ unique_retval_ids = MEM_reallocN(unique_retval_ids,
+ sizeof(*unique_retval_ids) * unique_retval_ids_len);
+ }
+
+ interaction->params.is_click = is_click;
+ interaction->params.unique_retval_ids = unique_retval_ids;
+ interaction->params.unique_retval_ids_len = unique_retval_ids_len;
+
+ interaction->user_data = block->custom_interaction_callbacks.begin_fn(
+ C, &interaction->params, block->custom_interaction_callbacks.arg1);
+ return interaction;
+}
+
+static void ui_block_interaction_end(bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ uiBlockInteraction_Handle *interaction)
+{
+ BLI_assert(callbacks->end_fn != NULL);
+ callbacks->end_fn(C, &interaction->params, callbacks->arg1, interaction->user_data);
+ MEM_freeN(interaction->params.unique_retval_ids);
+ MEM_freeN(interaction);
+}
+
+static void ui_block_interaction_update(bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ uiBlockInteraction_Handle *interaction)
+{
+ BLI_assert(callbacks->update_fn != NULL);
+ callbacks->update_fn(C, &interaction->params, callbacks->arg1, interaction->user_data);
+}
+
+/**
+ * \note #ui_block_interaction_begin cannot be called when setting the button state
+ * (e.g. #BUTTON_STATE_NUM_EDITING) for the following reasons.
+ *
+ * - Other buttons may still be activated using #UI_BUT_DRAG_MULTI
+ * which is necessary before gathering all the #uiBut.retval values to initialize
+ * #uiBlockInteraction_Params.unique_retval_ids.
+ * - When clicking on a number button it's not known if the event is a click or a drag.
+ *
+ * Instead, it must be called immediately before the drag action begins.
+ */
+static void ui_block_interaction_begin_ensure(bContext *C,
+ uiBlock *block,
+ uiHandleButtonData *data,
+ const bool is_click)
+{
+ if (data->custom_interaction_handle) {
+ return;
+ }
+ if (block->custom_interaction_callbacks.begin_fn == NULL) {
+ return;
+ }
+
+ uiBlockInteraction_Handle *interaction = ui_block_interaction_begin(C, block, is_click);
+ interaction->user_count = 1;
+ data->custom_interaction_handle = interaction;
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index a05afb6e542..40a9c67c630 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -511,6 +511,9 @@ struct uiBlock {
uiBlockHandleFunc handle_func;
void *handle_func_arg;
+ /** Custom interaction data. */
+ uiBlockInteraction_CallbackData custom_interaction_callbacks;
+
/** Custom extra event handling. */
int (*block_event_func)(const struct bContext *C, struct uiBlock *, const struct wmEvent *);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index abebc09ace2..8b9539f1d33 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1411,7 +1411,7 @@ BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
}
/**
- * Create ui items for enum items in \a item_array.
+ * Create UI items for enum items in \a item_array.
*
* A version of #uiItemsFullEnumO that takes pre-calculated item array.
*/
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index e3608684114..9c17486aea4 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2399,8 +2399,8 @@ static eAutoPropButsReturn template_operator_property_buts_draw_single(
op->type->ui((bContext *)C, op);
op->layout = NULL;
- /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could
- * allow ot.ui callback to return this, but not needed right now. */
+ /* #UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too.
+ * We could allow #wmOperatorType.ui callback to return this, but not needed right now. */
}
else {
wmWindowManager *wm = CTX_wm_manager(C);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 7b2e0fec1d0..72847fb2476 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1377,8 +1377,6 @@ static int ui_but_draw_menu_icon(const uiBut *but)
static void widget_draw_icon(
const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const uchar mono_color[4])
{
- float xs = 0.0f, ys = 0.0f;
-
if (but->flag & UI_BUT_ICON_PREVIEW) {
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(icon, alpha, rect);
@@ -1420,6 +1418,7 @@ static void widget_draw_icon(
if (icon && icon != ICON_BLANK1) {
const float ofs = 1.0f / aspect;
+ float xs, ys;
if (but->drawflag & UI_BUT_ICON_LEFT) {
/* special case - icon_only pie buttons */
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index e73a02840c9..e6f190f335b 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -514,7 +514,7 @@ static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
BPoint *bp;
int a, tot;
- if (BLI_listbase_is_empty(&obedit->defbase) || lt->dvert == NULL) {
+ if (BLI_listbase_is_empty(&lt->vertex_group_names) || lt->dvert == NULL) {
continue;
}
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index d92a81179cc..23eaf991fd3 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -240,7 +240,7 @@ static void lattice_undosys_step_decode(struct bContext *C,
}
undolatt_to_editlatt(&elem->data, lt->editlatt);
lt->editlatt->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&lt->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 942fe143787..09b17acf56d 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -30,6 +30,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 993905462db..cccfc7e934c 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -126,7 +126,7 @@ static int geometry_extract_apply(bContext *C,
.calc_face_normal = true,
}));
- BMEditMesh *em = BKE_editmesh_create(bm, false);
+ BMEditMesh *em = BKE_editmesh_create(bm);
/* Generate the tags for deleting geometry in the extracted object. */
tag_fn(bm, params);
@@ -206,7 +206,7 @@ static int geometry_extract_apply(bContext *C,
}),
mesh);
- BKE_editmesh_free(em);
+ BKE_editmesh_free_data(em);
MEM_freeN(em);
if (new_mesh->totvert == 0) {
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 593545ddcef..30a453a32ee 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -29,6 +29,7 @@
#include "DNA_windowmanager_types.h"
#ifdef WITH_FREESTYLE
+# include "BKE_customdata.h"
# include "DNA_meshdata_types.h"
#endif
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 6753c235a8d..830c9abb41e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -35,6 +35,8 @@
#include "BLI_utildefines_stack.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_report.h"
@@ -4739,10 +4741,11 @@ static bool edbm_select_ungrouped_poll(bContext *C)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ const ListBase *defbase = BKE_object_defgroup_list(obedit);
if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
CTX_wm_operator_poll_msg_set(C, "Must be in vertex selection mode");
}
- else if (BLI_listbase_is_empty(&obedit->defbase) || cd_dvert_offset == -1) {
+ else if (BLI_listbase_is_empty(defbase) || cd_dvert_offset == -1) {
CTX_wm_operator_poll_msg_set(C, "No weights/vertex groups on object");
}
else {
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index ff4db96061f..c452f7a7487 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -29,6 +29,8 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_material.h"
@@ -1041,7 +1043,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
if (cd_dvert_offset == -1) {
continue;
}
- defbase_len = BLI_listbase_count(&ob->defbase);
+ defbase_len = BKE_object_defgroup_count(ob);
if (defbase_len == 0) {
continue;
}
@@ -1090,8 +1092,10 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
/* We store the names of the vertex groups, so we can select
* vertex groups with the same name in different objects. */
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
int i = 0;
- LISTBASE_FOREACH (bDeformGroup *, dg, &ob->defbase) {
+ LISTBASE_FOREACH (bDeformGroup *, dg, defbase) {
if (BLI_BITMAP_TEST(defbase_selected, i)) {
BLI_gset_add(gset, dg->name);
}
@@ -1128,7 +1132,8 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
if (cd_dvert_offset == -1) {
continue;
}
- defbase_len = BLI_listbase_count(&ob->defbase);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ defbase_len = BLI_listbase_count(defbase);
if (defbase_len == 0) {
continue;
}
@@ -1141,7 +1146,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
GSetIterator gs_iter;
GSET_ITER (gs_iter, gset) {
const char *name = BLI_gsetIterator_getKey(&gs_iter);
- int vgroup_id = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
+ int vgroup_id = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
if (vgroup_id != -1) {
BLI_BITMAP_ENABLE(defbase_selected, vgroup_id);
found_any = true;
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 627d67a5254..41a9f426798 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -44,6 +44,7 @@
#include "BLI_string.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
@@ -5739,7 +5740,7 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op)
float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
{
const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- const int defbase_act = obedit->actdef - 1;
+ const int defbase_act = BKE_object_defgroup_active_index_get(obedit) - 1;
if (use_vertex_group && (cd_dvert_offset == -1)) {
BKE_report(op->reports, RPT_WARNING, "No active vertex group");
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 112de68b52c..fc9e1aa8b1a 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -33,6 +33,7 @@
#include "BLI_listbase.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -671,7 +672,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
em->bm->shapenr = um->shapenr;
- EDBM_mesh_free(em);
+ EDBM_mesh_free_data(em);
bm = BM_mesh_create(&allocsize,
&((struct BMeshCreateParams){
@@ -681,13 +682,21 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
BM_mesh_bm_from_me(bm,
&um->me,
(&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
+ /* Handled with tessellation. */
+ .calc_face_normal = false,
.active_shapekey = um->shapenr,
}));
- em_tmp = BKE_editmesh_create(bm, true);
+ em_tmp = BKE_editmesh_create(bm);
*em = *em_tmp;
+ /* Calculate face normals and tessellation at once since it's multi-threaded.
+ * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */
+ BKE_editmesh_looptri_calc_ex(em,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = true,
+ });
+
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
@@ -865,7 +874,7 @@ static void mesh_undosys_step_decode(struct bContext *C,
BMEditMesh *em = me->edit_mesh;
undomesh_to_editmesh(&elem->data, obedit, em, me->key);
em->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 4f416c94f62..85c646d689c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -305,17 +305,13 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
if (me->edit_mesh) {
/* this happens when switching shape keys */
- EDBM_mesh_free(me->edit_mesh);
+ EDBM_mesh_free_data(me->edit_mesh);
MEM_freeN(me->edit_mesh);
}
- /* currently executing operators re-tessellates, so we can avoid doing here
- * but at some point it may need to be added back. */
-#if 0
- me->edit_mesh = BKE_editmesh_create(bm, true);
-#else
- me->edit_mesh = BKE_editmesh_create(bm, false);
-#endif
+ /* Executing operators re-tessellates,
+ * so we can avoid doing here but at some point it may need to be added back. */
+ me->edit_mesh = BKE_editmesh_create(bm);
me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode;
me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
@@ -326,7 +322,8 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
/**
* \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
- * Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913
+ * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
+ * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
*/
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
@@ -346,25 +343,6 @@ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
.calc_object_remap = true,
.update_shapekey_indices = !free_data,
}));
-
- /* Free derived mesh. usually this would happen through depsgraph but there
- * are exceptions like file save that will not cause this, and we want to
- * avoid ending up with an invalid derived mesh then.
- *
- * Do it for all objects which shares the same mesh datablock, since their
- * derived meshes might also be referencing data which was just freed,
- *
- * Annoying enough, but currently seems most efficient way to avoid access
- * of freed data on scene update, especially in cases when there are dependency
- * cycles.
- */
-#if 0
- for (Object *other_object = bmain->objects.first; other_object != NULL; other_object = other_object->id.next) {
- if (other_object->data == ob->data) {
- BKE_object_free_derived_caches(other_object);
- }
- }
-#endif
}
void EDBM_mesh_clear(BMEditMesh *em)
@@ -372,8 +350,8 @@ void EDBM_mesh_clear(BMEditMesh *em)
/* clear bmesh */
BM_mesh_clear(em->bm);
- /* free derived meshes */
- BKE_editmesh_free_derivedmesh(em);
+ /* Free evaluated meshes & cache. */
+ BKE_editmesh_free_derived_caches(em);
/* free tessellation data */
em->tottri = 0;
@@ -389,9 +367,9 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
}
/**
- * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
+ * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
*/
-void EDBM_mesh_free(BMEditMesh *em)
+void EDBM_mesh_free_data(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
* to 'end' them but if someone tries to start using them,
@@ -399,7 +377,7 @@ void EDBM_mesh_free(BMEditMesh *em)
ED_mesh_mirror_spatial_table_end(NULL);
ED_mesh_mirror_topo_table_end(NULL);
- BKE_editmesh_free(em);
+ BKE_editmesh_free_data(em);
}
/** \} */
@@ -1471,8 +1449,8 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
BM_lnorspace_invalidate(em->bm, false);
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
}
- /* don't keep stale derivedMesh data around, see: T38872. */
- BKE_editmesh_free_derivedmesh(em);
+ /* Don't keep stale evaluated mesh data around, see: T38872. */
+ BKE_editmesh_free_derived_caches(em);
#ifdef DEBUG
{
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 2b78d83a9f5..73b3fb9724e 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -34,6 +34,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index ca68c47cf8e..27fb21e1dfb 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -475,16 +475,17 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
me = ob_iter->data;
/* Join this object's vertex groups to the base one's */
- for (dg = ob_iter->defbase.first; dg; dg = dg->next) {
+ for (dg = me->vertex_group_names.first; dg; dg = dg->next) {
/* See if this group exists in the object (if it doesn't, add it to the end) */
if (!BKE_object_defgroup_find_name(ob, dg->name)) {
odg = MEM_mallocN(sizeof(bDeformGroup), "join deformGroup");
memcpy(odg, dg, sizeof(bDeformGroup));
- BLI_addtail(&ob->defbase, odg);
+ BLI_addtail(&mesh_active->vertex_group_names, odg);
}
}
- if (ob->defbase.first && ob->actdef == 0) {
- ob->actdef = 1;
+ if (!BLI_listbase_is_empty(&mesh_active->vertex_group_names) &&
+ me->vertex_group_active_index == 0) {
+ me->vertex_group_active_index = 1;
}
/* Join this object's face maps to the base one's. */
@@ -1473,19 +1474,21 @@ bool ED_mesh_pick_vert(
MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
{
- if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH && ob->defbase.first) {
+ if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) {
Mesh *me = ob->data;
- BMesh *bm = me->edit_mesh->bm;
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ if (!BLI_listbase_is_empty(&me->vertex_group_names)) {
+ BMesh *bm = me->edit_mesh->bm;
+ const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- if (cd_dvert_offset != -1) {
- BMVert *eve = BM_mesh_active_vert_get(bm);
+ if (cd_dvert_offset != -1) {
+ BMVert *eve = BM_mesh_active_vert_get(bm);
- if (eve) {
- if (r_eve) {
- *r_eve = eve;
+ if (eve) {
+ if (r_eve) {
+ *r_eve = eve;
+ }
+ return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
}
- return BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
}
}
}
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index a8b471a7c92..f7b53b5513f 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -215,7 +215,7 @@ static void mball_undosys_step_decode(struct bContext *C,
}
undomball_to_editmball(&elem->data, mb);
mb->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&mb->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 6d22da2c2bc..8ae74fbfafa 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1845,7 +1845,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
* ready to be moved around to re-time the sound and/or make new sound clips. */
{
/* create new data for NLA hierarchy */
- AnimData *adt = BKE_animdata_add_id(&ob->id);
+ AnimData *adt = BKE_animdata_ensure_id(&ob->id);
NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data);
strip->start = CFRA;
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 742c7abb7ff..2109fe2a822 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -33,6 +33,7 @@
#include "BKE_context.h"
#include "BKE_data_transfer.h"
+#include "BKE_deform.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_mesh_runtime.h"
@@ -133,12 +134,13 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C,
}
if (ob_src) {
- bDeformGroup *dg;
+ const bDeformGroup *dg;
int i;
RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob_src);
+ for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
tmp_item.value = i;
tmp_item.identifier = tmp_item.name = dg->name;
RNA_enum_item_add(&item, &totitem, &tmp_item);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 1cb6a5c8ff5..6108691b2f1 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -557,7 +557,7 @@ static bool ED_object_editmode_load_free_ex(Main *bmain,
}
if (free_data) {
- EDBM_mesh_free(me->edit_mesh);
+ EDBM_mesh_free_data(me->edit_mesh);
MEM_freeN(me->edit_mesh);
me->edit_mesh = NULL;
}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index fcee2818b22..5065a2c00f0 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -105,14 +105,13 @@ static int return_editmesh_indexar(BMEditMesh *em, int *r_tot, int **r_indexar,
static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, float r_cent[3])
{
- const int cd_dvert_offset = obedit->actdef ?
+ const int active_index = BKE_object_defgroup_active_index_get(obedit);
+ const int cd_dvert_offset = active_index ?
CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) :
-1;
- zero_v3(r_cent);
-
if (cd_dvert_offset != -1) {
- const int defgrp_index = obedit->actdef - 1;
+ const int defgrp_index = active_index - 1;
int totvert = 0;
MDeformVert *dvert;
@@ -129,7 +128,8 @@ static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name,
}
}
if (totvert) {
- bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index);
+ const ListBase *defbase = BKE_object_defgroup_list(obedit);
+ bDeformGroup *dg = BLI_findlink(defbase, defgrp_index);
BLI_strncpy(r_name, dg->name, sizeof(dg->name));
mul_v3_fl(r_cent, 1.0f / (float)totvert);
return true;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 5bf04e195fe..5a3a28b5a3f 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -247,7 +247,6 @@ void OBJECT_OT_vertex_group_assign_new(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_remove_from(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_select(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_deselect(struct wmOperatorType *ot);
-void OBJECT_OT_vertex_group_copy_to_linked(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_copy_to_selected(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_copy(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_normalize(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index dc60d4df7d1..a438c760d3b 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -201,7 +201,6 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_group_remove_from);
WM_operatortype_append(OBJECT_OT_vertex_group_select);
WM_operatortype_append(OBJECT_OT_vertex_group_deselect);
- WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_linked);
WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_selected);
WM_operatortype_append(OBJECT_OT_vertex_group_copy);
WM_operatortype_append(OBJECT_OT_vertex_group_normalize);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 30f75e9a150..d7177eabcba 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2061,6 +2061,23 @@ static void single_object_action_users(
FOREACH_OBJECT_FLAG_END;
}
+static void single_objectdata_action_users(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag)
+{
+ FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
+ if (!ID_IS_LINKED(ob) && ob->data != NULL) {
+ ID *id_obdata = (ID *)ob->data;
+ AnimData *adt = BKE_animdata_from_id(id_obdata);
+ ID *id_act = (ID *)adt->action;
+ if (id_act && id_act->us > 1) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_animdata_copy_id_action(bmain, id_obdata);
+ }
+ }
+ }
+ FOREACH_OBJECT_FLAG_END;
+}
+
static void single_mat_users(
Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag)
{
@@ -2643,6 +2660,10 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
single_object_action_users(bmain, scene, view_layer, v3d, flag);
}
+ if (RNA_boolean_get(op->ptr, "obdata_animation")) {
+ single_objectdata_action_users(bmain, scene, view_layer, v3d, flag);
+ }
+
BKE_main_id_newptr_and_tag_clear(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -2684,8 +2705,16 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block");
- RNA_def_boolean(
- ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
+ RNA_def_boolean(ot->srna,
+ "animation",
+ 0,
+ "Object Animation",
+ "Make object animation data local to each object");
+ RNA_def_boolean(ot->srna,
+ "obdata_animation",
+ 0,
+ "Object Data Animation",
+ "Make object data (mesh, curve etc.) animation data local to each object");
}
/** \} */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index e350653e178..4c4727f51ee 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1152,51 +1152,53 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
+ if (ob->flag & OB_DONE) {
+ continue;
+ }
- if ((ob->flag & OB_DONE) == 0) {
- bool do_inverse_offset = false;
- ob->flag |= OB_DONE;
+ bool do_inverse_offset = false;
+ ob->flag |= OB_DONE;
- if (centermode == ORIGIN_TO_CURSOR) {
- copy_v3_v3(cent, cursor);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
- if (ob->data == NULL) {
- /* special support for dupligroups */
- if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection &&
- (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) {
- if (ID_IS_LINKED(ob->instance_collection)) {
- tot_lib_error++;
+ if (ob->data == NULL) {
+ /* special support for dupligroups */
+ if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection &&
+ (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) {
+ if (ID_IS_LINKED(ob->instance_collection)) {
+ tot_lib_error++;
+ }
+ else {
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
}
else {
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else {
- float min[3], max[3];
- /* only bounds support */
- INIT_MINMAX(min, max);
- BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true);
- mid_v3_v3v3(cent, min, max);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
+ float min[3], max[3];
+ /* only bounds support */
+ INIT_MINMAX(min, max);
+ BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true);
+ mid_v3_v3v3(cent, min, max);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
- add_v3_v3(ob->instance_collection->instance_offset, cent);
+ add_v3_v3(ob->instance_collection->instance_offset, cent);
- tot_change++;
- ob->instance_collection->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
- }
+ tot_change++;
+ ob->instance_collection->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
}
}
- else if (ID_IS_LINKED(ob->data)) {
- tot_lib_error++;
- }
-
- if (obedit == NULL && ob->type == OB_MESH) {
+ }
+ else if (ID_IS_LINKED(ob->data)) {
+ tot_lib_error++;
+ }
+ else if (ob->type == OB_MESH) {
+ if (obedit == NULL) {
Mesh *me = ob->data;
if (centermode == ORIGIN_TO_CURSOR) {
@@ -1222,265 +1224,265 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
me->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = ob->data;
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else if (around == V3D_AROUND_CENTER_BOUNDS) {
- BKE_curve_center_bounds(cu, cent);
- }
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- BKE_curve_center_median(cu, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (around == V3D_AROUND_CENTER_BOUNDS) {
+ BKE_curve_center_bounds(cu, cent);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ BKE_curve_center_median(cu, cent);
+ }
- /* don't allow Z change if curve is 2D */
- if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) {
- cent[2] = 0.0;
- }
+ /* don't allow Z change if curve is 2D */
+ if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) {
+ cent[2] = 0.0;
+ }
- negate_v3_v3(cent_neg, cent);
- BKE_curve_translate(cu, cent_neg, 1);
+ negate_v3_v3(cent_neg, cent);
+ BKE_curve_translate(cu, cent_neg, 1);
- tot_change++;
- cu->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
+ tot_change++;
+ cu->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
- if (obedit) {
- if (centermode == GEOMETRY_TO_ORIGIN) {
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
- }
- break;
+ if (obedit) {
+ if (centermode == GEOMETRY_TO_ORIGIN) {
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
}
+ break;
}
- else if (ob->type == OB_FONT) {
- /* Get from bounding-box. */
+ }
+ else if (ob->type == OB_FONT) {
+ /* Get from bounding-box. */
- Curve *cu = ob->data;
+ Curve *cu = ob->data;
- if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) {
- /* Do nothing. */
+ if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) {
+ /* Do nothing. */
+ }
+ else {
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* Done. */
}
else {
- if (centermode == ORIGIN_TO_CURSOR) {
- /* Done. */
- }
- else {
- /* extra 0.5 is the height o above line */
- cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]);
- cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]);
- }
+ /* extra 0.5 is the height o above line */
+ cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]);
+ cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]);
+ }
- cent[2] = 0.0f;
+ cent[2] = 0.0f;
- cu->xof = cu->xof - cent[0];
- cu->yof = cu->yof - cent[1];
+ cu->xof = cu->xof - cent[0];
+ cu->yof = cu->yof - cent[1];
- tot_change++;
- cu->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
- }
+ tot_change++;
+ cu->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
}
- else if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
+ }
+ else if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
- if (ID_REAL_USERS(arm) > 1) {
+ if (ID_REAL_USERS(arm) > 1) {
#if 0
BKE_report(op->reports, RPT_ERROR, "Cannot apply to a multi user armature");
return;
#endif
- tot_multiuser_arm_error++;
- }
- else {
- /* Function to recenter armatures in editarmature.c
- * Bone + object locations are handled there.
- */
- ED_armature_origin_set(bmain, ob, cursor, centermode, around);
+ tot_multiuser_arm_error++;
+ }
+ else {
+ /* Function to recenter armatures in editarmature.c
+ * Bone + object locations are handled there.
+ */
+ ED_armature_origin_set(bmain, ob, cursor, centermode, around);
- tot_change++;
- arm->id.tag |= LIB_TAG_DOIT;
- /* do_inverse_offset = true; */ /* docenter_armature() handles this */
+ tot_change++;
+ arm->id.tag |= LIB_TAG_DOIT;
+ /* do_inverse_offset = true; */ /* docenter_armature() handles this */
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- BKE_object_transform_copy(ob_eval, ob);
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
- BKE_object_where_is_calc(depsgraph, scene, ob_eval);
- BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_object_transform_copy(ob_eval, ob);
+ BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_object_where_is_calc(depsgraph, scene, ob_eval);
+ BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */
- ignore_parent_tx(bmain, depsgraph, scene, ob);
+ ignore_parent_tx(bmain, depsgraph, scene, ob);
- if (obedit) {
- break;
- }
+ if (obedit) {
+ break;
}
}
- else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
+ }
+ else if (ob->type == OB_MBALL) {
+ MetaBall *mb = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else if (around == V3D_AROUND_CENTER_BOUNDS) {
- BKE_mball_center_bounds(mb, cent);
- }
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- BKE_mball_center_median(mb, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (around == V3D_AROUND_CENTER_BOUNDS) {
+ BKE_mball_center_bounds(mb, cent);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ BKE_mball_center_median(mb, cent);
+ }
- negate_v3_v3(cent_neg, cent);
- BKE_mball_translate(mb, cent_neg);
+ negate_v3_v3(cent_neg, cent);
+ BKE_mball_translate(mb, cent_neg);
- tot_change++;
- mb->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
+ tot_change++;
+ mb->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
- if (obedit) {
- if (centermode == GEOMETRY_TO_ORIGIN) {
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
- }
- break;
+ if (obedit) {
+ if (centermode == GEOMETRY_TO_ORIGIN) {
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
}
+ break;
}
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else if (around == V3D_AROUND_CENTER_BOUNDS) {
- BKE_lattice_center_bounds(lt, cent);
- }
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- BKE_lattice_center_median(lt, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (around == V3D_AROUND_CENTER_BOUNDS) {
+ BKE_lattice_center_bounds(lt, cent);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ BKE_lattice_center_median(lt, cent);
+ }
- negate_v3_v3(cent_neg, cent);
- BKE_lattice_translate(lt, cent_neg, 1);
+ negate_v3_v3(cent_neg, cent);
+ BKE_lattice_translate(lt, cent_neg, 1);
- tot_change++;
- lt->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
- }
- else if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
- float gpcenter[3];
- if (gpd) {
- if (centermode == ORIGIN_TO_GEOMETRY) {
- zero_v3(gpcenter);
- BKE_gpencil_centroid_3d(gpd, gpcenter);
- add_v3_v3(gpcenter, ob->obmat[3]);
- }
- if (centermode == ORIGIN_TO_CURSOR) {
- copy_v3_v3(gpcenter, cursor);
- }
- if (ELEM(centermode, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR)) {
- bGPDspoint *pt;
- float imat[3][3], bmat[3][3];
- float offset_global[3];
- float offset_local[3];
- int i;
-
- sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]);
- copy_m3_m4(bmat, obact->obmat);
- invert_m3_m3(imat, bmat);
- mul_m3_v3(imat, offset_global);
- mul_v3_m3v3(offset_local, imat, offset_global);
-
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
-
- /* recalculate all strokes
- * (all layers are considered without evaluating lock attributes) */
- LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
- /* calculate difference matrix */
- BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
- /* undo matrix */
- invert_m4_m4(inverse_diff_mat, diff_mat);
- LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float mpt[3];
- mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
- sub_v3_v3(mpt, offset_local);
- mul_v3_m4v3(&pt->x, diff_mat, mpt);
- }
+ tot_change++;
+ lt->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
+ }
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ float gpcenter[3];
+ if (gpd) {
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ zero_v3(gpcenter);
+ BKE_gpencil_centroid_3d(gpd, gpcenter);
+ add_v3_v3(gpcenter, ob->obmat[3]);
+ }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(gpcenter, cursor);
+ }
+ if (ELEM(centermode, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR)) {
+ bGPDspoint *pt;
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+ int i;
+
+ sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]);
+ copy_m3_m4(bmat, obact->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all strokes
+ * (all layers are considered without evaluating lock attributes) */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* calculate difference matrix */
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
}
}
}
- tot_change++;
- if (centermode == ORIGIN_TO_GEOMETRY) {
- copy_v3_v3(ob->loc, gpcenter);
- }
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
-
- ob->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
}
- else {
- BKE_report(op->reports,
- RPT_WARNING,
- "Grease Pencil Object does not support this set origin option");
+ tot_change++;
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ copy_v3_v3(ob->loc, gpcenter);
}
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+
+ ob->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
+ }
+ else {
+ BKE_report(op->reports,
+ RPT_WARNING,
+ "Grease Pencil Object does not support this set origin option");
}
}
+ }
- /* offset other selected objects */
- if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
- float obmat[4][4];
+ /* offset other selected objects */
+ if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
+ float obmat[4][4];
- /* was the object data modified
- * NOTE: the functions above must set 'cent'. */
+ /* was the object data modified
+ * NOTE: the functions above must set 'cent'. */
- /* convert the offset to parent space */
- BKE_object_to_mat4(ob, obmat);
- mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
+ /* convert the offset to parent space */
+ BKE_object_to_mat4(ob, obmat);
+ mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
- add_v3_v3(ob->loc, centn);
+ add_v3_v3(ob->loc, centn);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- BKE_object_transform_copy(ob_eval, ob);
- BKE_object_where_is_calc(depsgraph, scene, ob_eval);
- if (ob->type == OB_ARMATURE) {
- /* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
- BKE_pose_where_is(depsgraph, scene, ob_eval);
- }
-
- ignore_parent_tx(bmain, depsgraph, scene, ob);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_object_transform_copy(ob_eval, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob_eval);
+ if (ob->type == OB_ARMATURE) {
+ /* needed for bone parents */
+ BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_pose_where_is(depsgraph, scene, ob_eval);
+ }
- /* other users? */
- // CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects)
- //{
-
- /* use existing context looper */
- for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
- Object *ob_other = objects[other_object_index];
-
- if ((ob_other->flag & OB_DONE) == 0 &&
- ((ob->data && (ob->data == ob_other->data)) ||
- (ob->instance_collection == ob_other->instance_collection &&
- (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) {
- ob_other->flag |= OB_DONE;
- DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
- add_v3_v3(ob_other->loc, centn);
-
- Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other);
- BKE_object_transform_copy(ob_other_eval, ob_other);
- BKE_object_where_is_calc(depsgraph, scene, ob_other_eval);
- if (ob_other->type == OB_ARMATURE) {
- /* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
- BKE_pose_where_is(depsgraph, scene, ob_other_eval);
- }
- ignore_parent_tx(bmain, depsgraph, scene, ob_other);
+ ignore_parent_tx(bmain, depsgraph, scene, ob);
+
+ /* other users? */
+ // CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects)
+ //{
+
+ /* use existing context looper */
+ for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
+ Object *ob_other = objects[other_object_index];
+
+ if ((ob_other->flag & OB_DONE) == 0 &&
+ ((ob->data && (ob->data == ob_other->data)) ||
+ (ob->instance_collection == ob_other->instance_collection &&
+ (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) {
+ ob_other->flag |= OB_DONE;
+ DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
+ add_v3_v3(ob_other->loc, centn);
+
+ Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other);
+ BKE_object_transform_copy(ob_other_eval, ob_other);
+ BKE_object_where_is_calc(depsgraph, scene, ob_other_eval);
+ if (ob_other->type == OB_ARMATURE) {
+ /* needed for bone parents */
+ BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_pose_where_is(depsgraph, scene, ob_other_eval);
}
+ ignore_parent_tx(bmain, depsgraph, scene, ob_other);
}
- // CTX_DATA_END;
}
+ // CTX_DATA_END;
}
}
MEM_freeN(objects);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 37075a29b92..4ea599fd30e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -130,7 +130,7 @@ bool ED_vgroup_sync_from_pose(Object *ob)
if (arm->act_bone) {
int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name);
if (def_num != -1) {
- ob->actdef = def_num + 1;
+ BKE_object_defgroup_active_index_set(ob, def_num + 1);
return true;
}
}
@@ -389,11 +389,16 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
int dvert_tot_from;
int dvert_tot;
int i;
- int defbase_tot_from = BLI_listbase_count(&ob_from->defbase);
- int defbase_tot = BLI_listbase_count(&ob->defbase);
+ ListBase *defbase_dst = BKE_object_defgroup_list_mutable(ob);
+ const ListBase *defbase_src = BKE_object_defgroup_list(ob_from);
+
+ int defbase_tot_from = BLI_listbase_count(defbase_src);
+ int defbase_tot = BLI_listbase_count(defbase_dst);
bool new_vgroup = false;
- if (ob == ob_from) {
+ BLI_assert(ob != ob_from);
+
+ if (ob->data == ob_from->data) {
return true;
}
@@ -429,9 +434,9 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
}
/* do the copy */
- BLI_freelistN(&ob->defbase);
- BLI_duplicatelist(&ob->defbase, &ob_from->defbase);
- ob->actdef = ob_from->actdef;
+ BLI_freelistN(defbase_dst);
+ BLI_duplicatelist(defbase_dst, defbase_src);
+ BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_active_index_get(ob_from));
if (defbase_tot_from < defbase_tot) {
/* correct vgroup indices because the number of vgroups is being reduced. */
@@ -882,7 +887,8 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
/* add the vert to the deform group with the
* specified assign mode
*/
- const int def_nr = BLI_findindex(&ob->defbase, dg);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const int def_nr = BLI_findindex(defbase, dg);
MDeformVert *dv = NULL;
int tot;
@@ -913,7 +919,8 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
/* TODO(campbell): This is slow in a loop, better pass def_nr directly,
* but leave for later. */
- const int def_nr = BLI_findindex(&ob->defbase, dg);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const int def_nr = BLI_findindex(defbase, dg);
if (def_nr != -1) {
MDeformVert *dvert = NULL;
@@ -989,7 +996,8 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
{
- const int def_nr = BLI_findindex(&ob->defbase, dg);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const int def_nr = BLI_findindex(defbase, dg);
if (def_nr == -1) {
return -1;
@@ -1000,9 +1008,9 @@ float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
void ED_vgroup_select_by_name(Object *ob, const char *name)
{
- /* NOTE: ob->actdef==0 signals on painting to create a new one,
+ /* NOTE: actdef==0 signals on painting to create a new one,
* if a bone in posemode is selected */
- ob->actdef = BKE_object_defgroup_name_index(ob, name) + 1;
+ BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_name_index(ob, name) + 1);
}
/** \} */
@@ -1014,9 +1022,10 @@ void ED_vgroup_select_by_name(Object *ob, const char *name)
/* only in editmode */
static void vgroup_select_verts(Object *ob, int select)
{
- const int def_nr = ob->actdef - 1;
+ const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ if (!BLI_findlink(defbase, def_nr)) {
return;
}
@@ -1111,7 +1120,9 @@ static void vgroup_duplicate(Object *ob)
MDeformVert **dvert_array = NULL;
int i, idg, icdg, dvert_tot = 0;
- dg = BLI_findlink(&ob->defbase, (ob->actdef - 1));
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
+ dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
if (!dg) {
return;
}
@@ -1127,11 +1138,11 @@ static void vgroup_duplicate(Object *ob)
BLI_strncpy(cdg->name, name, sizeof(cdg->name));
BKE_object_defgroup_unique_name(cdg, ob);
- BLI_addtail(&ob->defbase, cdg);
+ BLI_addtail(defbase, cdg);
- idg = (ob->actdef - 1);
- ob->actdef = BLI_listbase_count(&ob->defbase);
- icdg = (ob->actdef - 1);
+ idg = BKE_object_defgroup_active_index_get(ob) - 1;
+ BKE_object_defgroup_active_index_set(ob, BLI_listbase_count(defbase));
+ icdg = BKE_object_defgroup_active_index_get(ob) - 1;
/* TODO(campbell): we might want to allow only copy selected verts here? */
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
@@ -1157,11 +1168,12 @@ static bool vgroup_normalize(Object *ob)
MDeformWeight *dw;
MDeformVert *dv, **dvert_array = NULL;
int dvert_tot = 0;
- const int def_nr = ob->actdef - 1;
+ const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ if (!BLI_findlink(defbase, def_nr)) {
return false;
}
@@ -1639,7 +1651,7 @@ static bool vgroup_normalize_all(Object *ob,
{
MDeformVert *dv, **dvert_array = NULL;
int i, dvert_tot = 0;
- const int def_nr = ob->actdef - 1;
+ const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
@@ -1651,7 +1663,8 @@ static bool vgroup_normalize_all(Object *ob,
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const int defbase_tot = BLI_listbase_count(defbase);
bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
bool changed = false;
@@ -1742,7 +1755,7 @@ static const EnumPropertyItem vgroup_lock_mask[] = {
static bool *vgroup_selected_get(Object *ob)
{
- int sel_count = 0, defbase_tot = BLI_listbase_count(&ob->defbase);
+ int sel_count = 0, defbase_tot = BKE_object_defgroup_count(ob);
bool *mask;
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
@@ -1759,8 +1772,9 @@ static bool *vgroup_selected_get(Object *ob)
mask = MEM_callocN(defbase_tot * sizeof(bool), __func__);
}
- if (sel_count == 0 && ob->actdef >= 1 && ob->actdef <= defbase_tot) {
- mask[ob->actdef - 1] = true;
+ const int actdef = BKE_object_defgroup_active_index_get(ob);
+ if (sel_count == 0 && actdef >= 1 && actdef <= defbase_tot) {
+ mask[actdef - 1] = true;
}
return mask;
@@ -1775,11 +1789,12 @@ static void vgroup_lock_all(Object *ob, int action, int mask)
if (mask != VGROUP_MASK_ALL) {
selected = vgroup_selected_get(ob);
}
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
if (action == VGROUP_TOGGLE) {
action = VGROUP_LOCK;
- for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
+ for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
switch (mask) {
case VGROUP_MASK_INVERT_UNSELECTED:
case VGROUP_MASK_SELECTED:
@@ -1802,7 +1817,7 @@ static void vgroup_lock_all(Object *ob, int action, int mask)
}
}
- for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
+ for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
switch (mask) {
case VGROUP_MASK_SELECTED:
if (!selected[i]) {
@@ -2379,13 +2394,15 @@ void ED_vgroup_mirror(Object *ob,
MDeformVert *dvert, *dvert_mirr;
char sel, sel_mirr;
int *flip_map = NULL, flip_map_len;
- const int def_nr = ob->actdef - 1;
+ const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
int totmirr = 0, totfail = 0;
*r_totmirr = *r_totfail = 0;
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
if ((mirror_weights == false && flip_vgroups == false) ||
- (BLI_findlink(&ob->defbase, def_nr) == NULL)) {
+ (BLI_findlink(defbase, def_nr) == NULL)) {
return;
}
@@ -2569,7 +2586,8 @@ cleanup:
static void vgroup_delete_active(Object *ob)
{
- bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
if (!dg) {
return;
}
@@ -2580,9 +2598,10 @@ static void vgroup_delete_active(Object *ob)
/* only in editmode */
static void vgroup_assign_verts(Object *ob, const float weight)
{
- const int def_nr = ob->actdef - 1;
+ const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
- if (!BLI_findlink(&ob->defbase, def_nr)) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ if (!BLI_findlink(defbase, def_nr)) {
return;
}
@@ -2700,7 +2719,8 @@ static bool vertex_group_poll_ex(bContext *C, Object *ob)
return false;
}
- if (BLI_listbase_is_empty(&ob->defbase)) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ if (BLI_listbase_is_empty(defbase)) {
CTX_wm_operator_poll_msg_set(C, "Object has no vertex groups");
return false;
}
@@ -2823,8 +2843,10 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C)
return false;
}
- if (ob->actdef != 0) {
- bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1);
+ const int def_nr = BKE_object_defgroup_active_index_get(ob);
+ if (def_nr != 0) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const bDeformGroup *dg = BLI_findlink(defbase, def_nr - 1);
if (dg) {
return !(dg->flag & DG_LOCK_WEIGHT);
}
@@ -3025,8 +3047,8 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
}
}
else {
- bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1);
-
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) {
return OPERATOR_CANCELLED;
}
@@ -3860,55 +3882,6 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Group Copy to Linked Operator
- * \{ */
-
-static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob_active = ED_object_context(C);
- int retval = OPERATOR_CANCELLED;
-
- FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) {
- if (ob_iter->type == ob_active->type) {
- if (ob_iter != ob_active && ob_iter->data == ob_active->data) {
- BLI_freelistN(&ob_iter->defbase);
- BLI_duplicatelist(&ob_iter->defbase, &ob_active->defbase);
- ob_iter->actdef = ob_active->actdef;
-
- DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
- WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_iter->data);
-
- retval = OPERATOR_FINISHED;
- }
- }
- }
- FOREACH_SCENE_OBJECT_END;
-
- return retval;
-}
-
-void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Copy Vertex Groups to Linked";
- ot->idname = "OBJECT_OT_vertex_group_copy_to_linked";
- ot->description =
- "Replace vertex groups of all users of the same geometry data by vertex groups of active "
- "object";
-
- /* api callbacks */
- ot->poll = vertex_group_poll;
- ot->exec = vertex_group_copy_to_linked_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Vertex Group Copy to Selected Operator
* \{ */
@@ -3972,7 +3945,7 @@ static int set_active_group_exec(bContext *C, wmOperator *op)
int nr = RNA_enum_get(op->ptr, "group");
BLI_assert(nr + 1 >= 0);
- ob->actdef = nr + 1;
+ BKE_object_defgroup_active_index_set(ob, nr + 1);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
@@ -3999,7 +3972,8 @@ static const EnumPropertyItem *vgroup_itemf(bContext *C,
return DummyRNA_NULL_items;
}
- for (a = 0, def = ob->defbase.first; def; def = def->next, a++) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ for (a = 0, def = defbase->first; def; def = def->next, a++) {
tmp.value = a;
tmp.icon = ICON_GROUP_VERTEX;
tmp.identifier = def->name;
@@ -4048,13 +4022,13 @@ void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
* with the order of vgroups then call vgroup_do_remap after */
static char *vgroup_init_remap(Object *ob)
{
- bDeformGroup *def;
- int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ int defbase_tot = BLI_listbase_count(defbase);
char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups");
char *name;
name = name_array;
- for (def = ob->defbase.first; def; def = def->next) {
+ for (const bDeformGroup *def = defbase->first; def; def = def->next) {
BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
name += MAX_VGROUP_NAME;
}
@@ -4065,8 +4039,9 @@ static char *vgroup_init_remap(Object *ob)
static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
{
MDeformVert *dvert = NULL;
- bDeformGroup *def;
- int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const bDeformGroup *def;
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ int defbase_tot = BLI_listbase_count(defbase);
/* Needs a dummy index at the start. */
int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups");
@@ -4076,8 +4051,8 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
int i;
name = name_array;
- for (def = ob->defbase.first, i = 0; def; def = def->next, i++) {
- sort_map[i] = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
+ for (def = defbase->first, i = 0; def; def = def->next, i++) {
+ sort_map[i] = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
name += MAX_VGROUP_NAME;
BLI_assert(sort_map[i] != -1);
@@ -4130,8 +4105,9 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
sort_map_update[0] = 0;
BKE_object_defgroup_remap_update_users(ob, sort_map_update);
- BLI_assert(sort_map_update[ob->actdef] >= 0);
- ob->actdef = sort_map_update[ob->actdef];
+ BLI_assert(sort_map_update[BKE_object_defgroup_active_index_get(ob)] >= 0);
+ BKE_object_defgroup_active_index_set(ob,
+ sort_map_update[BKE_object_defgroup_active_index_get(ob)]);
MEM_freeN(sort_map_update);
@@ -4159,6 +4135,7 @@ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
bonebase = &armature->bonebase;
}
}
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
if (bonebase != NULL) {
Bone *bone;
@@ -4167,8 +4144,8 @@ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
vgroup_sort_bone_hierarchy(ob, &bone->childbase);
if (dg != NULL) {
- BLI_remlink(&ob->defbase, dg);
- BLI_addhead(&ob->defbase, dg);
+ BLI_remlink(defbase, dg);
+ BLI_addhead(defbase, dg);
}
}
}
@@ -4189,10 +4166,12 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op)
/* Init remapping. */
name_array = vgroup_init_remap(ob);
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
/* Sort vgroup names. */
switch (sort_type) {
case SORT_TYPE_NAME:
- BLI_listbase_sort(&ob->defbase, vgroup_sort_name);
+ BLI_listbase_sort(defbase, vgroup_sort_name);
break;
case SORT_TYPE_BONEHIERARCHY:
vgroup_sort_bone_hierarchy(ob, NULL);
@@ -4250,14 +4229,16 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
int dir = RNA_enum_get(op->ptr, "direction");
int ret = OPERATOR_FINISHED;
- def = BLI_findlink(&ob->defbase, ob->actdef - 1);
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
+ def = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
if (!def) {
return OPERATOR_CANCELLED;
}
name_array = vgroup_init_remap(ob);
- if (BLI_listbase_link_move(&ob->defbase, def, dir)) {
+ if (BLI_listbase_link_move(defbase, def, dir)) {
ret = vgroup_do_remap(ob, name_array, op);
if (ret != OPERATOR_CANCELLED) {
@@ -4376,7 +4357,8 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr)
{
- bDeformGroup *dg = BLI_findlink(&ob->defbase, def_nr);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *dg = BLI_findlink(defbase, def_nr);
if (!dg) {
BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index");
@@ -4498,7 +4480,7 @@ static int vertex_weight_set_active_exec(bContext *C, wmOperator *op)
const int wg_index = RNA_int_get(op->ptr, "weight_group");
if (wg_index != -1) {
- ob->actdef = wg_index + 1;
+ BKE_object_defgroup_active_index_set(ob, wg_index + 1);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 2484f382ed4..709e04d807d 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -752,7 +752,7 @@ static int vert_select_ungrouped_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
- if (BLI_listbase_is_empty(&ob->defbase) || (me->dvert == NULL)) {
+ if (BLI_listbase_is_empty(&me->vertex_group_names) || (me->dvert == NULL)) {
BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 5c1cc6cadcf..9387b84f437 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1607,13 +1607,13 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* check if we are attempting to paint onto a locked vertex group,
* and other options disallow it from doing anything useful */
bDeformGroup *dg;
- dg = BLI_findlink(&ob->defbase, vgroup_index.active);
+ dg = BLI_findlink(&me->vertex_group_names, vgroup_index.active);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
return false;
}
if (vgroup_index.mirror != -1) {
- dg = BLI_findlink(&ob->defbase, vgroup_index.mirror);
+ dg = BLI_findlink(&me->vertex_group_names, vgroup_index.mirror);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
return false;
@@ -1622,7 +1622,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
}
/* check that multipaint groups are unlocked */
- defbase_tot = BLI_listbase_count(&ob->defbase);
+ defbase_tot = BLI_listbase_count(&me->vertex_group_names);
defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel);
if (ts->multipaint && defbase_tot_sel > 1) {
@@ -1636,7 +1636,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
for (i = 0; i < defbase_tot; i++) {
if (defbase_sel[i]) {
- dg = BLI_findlink(&ob->defbase, i);
+ dg = BLI_findlink(&me->vertex_group_names, i);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
MEM_freeN(defbase_sel);
@@ -2498,7 +2498,7 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
for (i = 0; i < PSYS_TOT_VG; i++) {
- if (psys->vgroup[i] == ob->actdef) {
+ if (psys->vgroup[i] == BKE_object_defgroup_active_index_get(ob)) {
psys->recalc |= ID_RECALC_PSYS_RESET;
break;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 96d22fe4a21..9f023dd6e63 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -149,7 +149,7 @@ static bool vertex_paint_from_weight(Object *ob)
/* TODO: respect selection. */
/* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway. */
mp = me->mpoly;
- vgroup_active = ob->actdef - 1;
+ vgroup_active = me->vertex_group_active_index - 1;
for (int i = 0; i < me->totpoly; i++, mp++) {
MLoopCol *lcol = &me->mloopcol[mp->loopstart];
uint j = 0;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 5e047283534..cb8dc838422 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -183,7 +183,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
- if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
+ if (me && me->dvert && vc.v3d && vc.rv3d && (me->vertex_group_active_index != 0)) {
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int v_idx_best = -1;
uint index;
@@ -213,9 +213,9 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
if (v_idx_best != -1) { /* should always be valid */
ToolSettings *ts = vc.scene->toolsettings;
Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
- const int vgroup_active = vc.obact->actdef - 1;
+ const int vgroup_active = me->vertex_group_active_index - 1;
float vgroup_weight = BKE_defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
- const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ const int defbase_tot = BLI_listbase_count(&me->vertex_group_names);
bool use_lock_relative = ts->wpaint_lock_relative;
bool *defbase_locked = NULL, *defbase_unlocked = NULL;
@@ -331,8 +331,8 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
- if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
- const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ if (me && me->dvert && vc.v3d && vc.rv3d && me->vertex_group_names.first) {
+ const int defbase_tot = BLI_listbase_count(&me->vertex_group_names);
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
bool found = false;
@@ -372,7 +372,7 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
int totitem = 0;
int i = 0;
bDeformGroup *dg;
- for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) {
+ for (dg = me->vertex_group_names.first; dg && i < defbase_tot; i++, dg = dg->next) {
if (groups[i]) {
item_tmp.identifier = item_tmp.name = dg->name;
item_tmp.value = i;
@@ -401,7 +401,7 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_assert(type + 1 >= 0);
- vc.obact->actdef = type + 1;
+ BKE_object_defgroup_active_index_set(vc.obact, type + 1);
DEG_id_tag_update(&vc.obact->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
@@ -458,7 +458,7 @@ static bool weight_paint_set(Object *ob, float paintweight)
return false;
}
- vgroup_active = ob->actdef - 1;
+ vgroup_active = BKE_object_defgroup_active_index_get(ob) - 1;
/* if mirror painting, find the other group */
if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) {
@@ -815,7 +815,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.sco_start = sco_start;
data.sco_end = sco_end;
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
- data.def_nr = ob->actdef - 1;
+ data.def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
data.vert_cache = vert_cache;
data.vert_visit = NULL;
@@ -863,7 +863,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
}
if (scene->toolsettings->auto_normalize) {
- const int vgroup_num = BLI_listbase_count(&ob->defbase);
+ const int vgroup_num = BLI_listbase_count(&me->vertex_group_names);
bool *vgroup_validmap = BKE_object_defgroup_validmap_get(ob, vgroup_num);
if (vgroup_validmap != NULL) {
MDeformVert *dvert = me->dvert;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index d6a118bbd59..19ffa0c952d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -79,8 +79,10 @@ bool ED_wpaint_ensure_data(bContext *C,
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
/* this happens on a Bone select, when no vgroup existed yet */
- if (ob->actdef <= 0) {
+ if (me->vertex_group_active_index <= 0) {
Object *modob;
if ((modob = BKE_modifiers_is_deformed_by_armature(ob))) {
Bone *actbone = ((bArmature *)modob->data)->act_bone;
@@ -94,32 +96,33 @@ bool ED_wpaint_ensure_data(bContext *C,
DEG_relations_tag_update(CTX_data_main(C));
}
else {
- int actdef = 1 + BLI_findindex(&ob->defbase, dg);
+
+ int actdef = 1 + BLI_findindex(defbase, dg);
BLI_assert(actdef >= 0);
- ob->actdef = actdef;
+ me->vertex_group_active_index = actdef;
}
}
}
}
}
- if (BLI_listbase_is_empty(&ob->defbase)) {
+ if (BLI_listbase_is_empty(defbase)) {
BKE_object_defgroup_add(ob);
DEG_relations_tag_update(CTX_data_main(C));
}
/* ensure we don't try paint onto an invalid group */
- if (ob->actdef <= 0) {
+ if (me->vertex_group_active_index <= 0) {
BKE_report(reports, RPT_WARNING, "No active vertex group for painting, aborting");
return false;
}
if (vgroup_index) {
- vgroup_index->active = ob->actdef - 1;
+ vgroup_index->active = me->vertex_group_active_index - 1;
}
if (flag & WPAINT_ENSURE_MIRROR) {
if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) {
- int mirror = ED_wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1);
+ int mirror = ED_wpaint_mirror_vgroup_ensure(ob, me->vertex_group_active_index - 1);
if (vgroup_index) {
vgroup_index->mirror = mirror;
}
@@ -133,7 +136,8 @@ bool ED_wpaint_ensure_data(bContext *C,
/* mirror_vgroup is set to -1 when invalid */
int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
{
- bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *defgroup = BLI_findlink(defbase, vgroup_active);
if (defgroup) {
int mirrdef;
@@ -143,7 +147,7 @@ int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
mirrdef = BKE_object_defgroup_name_index(ob, name_flip);
if (mirrdef == -1) {
if (BKE_object_defgroup_new(ob, name_flip)) {
- mirrdef = BLI_listbase_count(&ob->defbase) - 1;
+ mirrdef = BLI_listbase_count(defbase) - 1;
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index fe7029c7457..f21c900941b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1608,7 +1608,7 @@ void ED_sculpt_undosys_type(UndoType *ut)
ut->step_decode = sculpt_undosys_step_decode;
ut->step_free = sculpt_undosys_step_free;
- ut->flags = 0;
+ ut->flags = UNDOTYPE_FLAG_DECODE_ACTIVE_STEP;
ut->step_size = sizeof(SculptUndoStep);
}
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 9e69b0a72db..d69c7ab8d48 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -813,7 +813,7 @@ static int action_layer_next_exec(bContext *C, wmOperator *op)
NlaTrack *act_track;
Scene *scene = CTX_data_scene(C);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
/* Get active track */
act_track = BKE_nlatrack_find_tweaked(adt);
@@ -925,7 +925,7 @@ static int action_layer_prev_exec(bContext *C, wmOperator *op)
NlaTrack *nlt;
Scene *scene = CTX_data_scene(C);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
/* Sanity Check */
if (adt == NULL) {
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 4d568017b4f..faa4b3cc9cc 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -523,6 +523,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
char orgname[FILE_MAX + 12];
char filename[FILE_MAX + 12];
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
ARegion *region = CTX_wm_region(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -542,12 +543,16 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
else {
/* If rename is successful, scroll to newly renamed entry. */
BLI_strncpy(params->renamefile, filename, sizeof(params->renamefile));
- file_params_invoke_rename_postscroll(wm, CTX_wm_window(C), sfile);
+ file_params_invoke_rename_postscroll(wm, win, sfile);
}
/* to make sure we show what is on disk */
ED_fileselect_clear(wm, sfile);
}
+ else {
+ /* Renaming failed, reset the name for further renaming handling. */
+ BLI_strncpy(params->renamefile, oldname, sizeof(params->renamefile));
+ }
ED_region_tag_redraw(region);
}
@@ -812,6 +817,8 @@ static void draw_details_columns(const FileSelectParams *params,
void file_draw_list(const bContext *C, ARegion *region)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
FileLayout *layout = ED_fileselect_get_layout(sfile, region);
@@ -882,12 +889,12 @@ void file_draw_list(const bContext *C, ARegion *region)
// printf("%s: preview task: %d\n", __func__, previews_running);
if (previews_running && !sfile->previews_timer) {
sfile->previews_timer = WM_event_add_timer_notifier(
- CTX_wm_manager(C), CTX_wm_window(C), NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01);
+ wm, win, NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01);
}
if (!previews_running && sfile->previews_timer) {
/* Preview is not running, no need to keep generating update events! */
// printf("%s: Inactive preview task, sleeping!\n", __func__);
- WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer);
+ WM_event_remove_timer_notifier(wm, win, sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
@@ -998,8 +1005,19 @@ void file_draw_list(const bContext *C, ARegion *region)
UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */
UI_but_flag_disable(but, UI_BUT_UNDO);
if (false == UI_but_active_only(C, region, block, but)) {
- file_selflag = filelist_entry_select_set(
- sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
+ /* Note that this is the only place where we can also handle a cancelled renaming. */
+
+ file_params_rename_end(wm, win, sfile, file);
+
+ /* After the rename button is removed, we need to make sure the view is redrawn once more,
+ * in case selection changed. Usually UI code would trigger that redraw, but the rename
+ * operator may have been called from a different region.
+ * Tagging regions for redrawing while drawing is rightfully prevented. However, this
+ * active button removing basically introduces handling logic to drawing code. So a
+ * notifier should be an acceptable workaround. */
+ WM_event_add_notifier_ex(wm, win, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL);
}
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index b2182c45f2a..0bbed65671c 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -109,6 +109,7 @@ FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
float file_string_width(const char *str);
float file_font_pointsize(void);
+void file_select_deselect_all(SpaceFile *sfile, uint flag);
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file);
int autocomplete_directory(struct bContext *C, char *str, void *arg_v);
int autocomplete_file(struct bContext *C, char *str, void *arg_v);
@@ -120,6 +121,10 @@ void file_params_renamefile_clear(struct FileSelectParams *params);
void file_params_invoke_rename_postscroll(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
+void file_params_rename_end(struct wmWindowManager *wm,
+ struct wmWindow *win,
+ SpaceFile *sfile,
+ struct FileDirEntry *rename_file);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
typedef void *onReloadFnData;
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d91cc0f0b54..995383d9d0e 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -104,15 +104,6 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile,
return sel;
}
-static void file_deselect_all(SpaceFile *sfile, uint flag)
-{
- FileSelection sel;
- sel.first = 0;
- sel.last = filelist_files_ensure(sfile->files) - 1;
-
- filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
-}
-
typedef enum FileSelect {
FILE_SELECT_NOTHING = 0,
FILE_SELECT_DIR = 1,
@@ -444,7 +435,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
int idx;
- file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ file_select_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
filelist_entries_select_index_range_set(
sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -472,7 +463,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
params->highlight_file = -1;
params->sel_first = params->sel_last = -1;
fileselect_file_set(sfile, params->active_file);
- file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ file_select_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -491,7 +482,7 @@ static int file_box_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
}
ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
@@ -573,7 +564,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if ((idx >= 0) && (idx < numfiles)) {
/* single select, deselect all selected first */
if (!extend) {
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
}
}
}
@@ -588,7 +579,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ret == FILE_SELECT_NOTHING) {
if (deselect_all) {
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
}
}
else if (ret == FILE_SELECT_DIR) {
@@ -721,7 +712,7 @@ static bool file_walk_select_selection_set(wmWindow *win,
}
else {
/* deselect all first */
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
/* highlight file under mouse pos */
params->highlight_file = -1;
@@ -2349,6 +2340,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op)
/* If we don't enter the directory directly, remember file to jump into editing. */
if (do_diropen == false) {
+ BLI_assert(params->rename_id == NULL || !"File rename handling should immediately clear rename_id when done, because otherwise it will keep taking precedence over renamefile.");
BLI_strncpy(params->renamefile, name, FILE_MAXFILE);
rename_flag = FILE_PARAMS_RENAME_PENDING;
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index fe545aa5bf2..0e15538e03b 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2016,19 +2016,21 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index)
return filelist_file_ex(filelist, index, true);
}
-int filelist_file_findpath(struct FileList *filelist, const char *filename)
+/**
+ * Find a file from a file name, or more precisely, its file-list relative path, inside the
+ * filtered items. \return The index of the found file or -1.
+ */
+int filelist_file_find_path(struct FileList *filelist, const char *filename)
{
- int fidx = -1;
-
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
- return fidx;
+ return -1;
}
/* XXX TODO: Cache could probably use a ghash on paths too? Not really urgent though.
* This is only used to find again renamed entry,
* annoying but looks hairy to get rid of it currently. */
- for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
if (STREQ(entry->relpath, filename)) {
return fidx;
@@ -2039,6 +2041,26 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename)
}
/**
+ * Find a file representing \a id.
+ * \return The index of the found file or -1.
+ */
+int filelist_file_find_id(const FileList *filelist, const ID *id)
+{
+ if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
+ return -1;
+ }
+
+ for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
+ if (entry->local_data.id == id) {
+ return fidx;
+ }
+ }
+
+ return -1;
+}
+
+/**
* Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
*/
ID *filelist_file_get_id(const FileDirEntry *file)
@@ -2068,9 +2090,6 @@ void filelist_uid_unset(FileUID *r_uid)
*r_uid = FILE_UID_UNSET;
}
-/**
- * \warning The UID will only be valid for the current session. Use as runtime data only!
- */
void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
{
/* Always keep it power of 2, in [256, 8192] range for now,
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index e6c4b8e1a07..0aace74e621 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -97,7 +97,8 @@ int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
-int filelist_file_findpath(struct FileList *filelist, const char *file);
+int filelist_file_find_path(struct FileList *filelist, const char *file);
+int filelist_file_find_id(const struct FileList *filelist, const struct ID *id);
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
bool filelist_uid_is_set(const FileUID uid);
void filelist_uid_unset(FileUID *r_uid);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 4e59e4ba06e..b7accbf71e5 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -1086,6 +1086,15 @@ void ED_file_change_dir(bContext *C)
ED_file_change_dir_ex(C, area);
}
+void file_select_deselect_all(SpaceFile *sfile, uint flag)
+{
+ FileSelection sel;
+ sel.first = 0;
+ sel.last = filelist_files_ensure(sfile->files) - 1;
+
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
+}
+
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file)
{
int match = 0;
@@ -1237,7 +1246,7 @@ void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, Sp
* Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
* timer. To be used right after a file was renamed.
* Note that the caller is responsible for setting the correct rename-file info
- * (#FileSelectParams.renamefile or #FileSelectParams.renamefile_uuid).
+ * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
*/
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
{
@@ -1252,12 +1261,40 @@ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, Sp
sfile->scroll_offset = 0;
}
+/**
+ * To be executed whenever renaming ends (successfully or not).
+ */
+void file_params_rename_end(wmWindowManager *wm,
+ wmWindow *win,
+ SpaceFile *sfile,
+ FileDirEntry *rename_file)
+{
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ filelist_entry_select_set(
+ sfile->files, rename_file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
+
+ /* Ensure smooth-scroll timer is active, even if not needed, because that way rename state is
+ * handled properly. */
+ file_params_invoke_rename_postscroll(wm, win, sfile);
+ /* Also always activate the rename file, even if renaming was cancelled. */
+ file_params_renamefile_activate(sfile, params);
+}
+
void file_params_renamefile_clear(FileSelectParams *params)
{
params->renamefile[0] = '\0';
+ params->rename_id = NULL;
params->rename_flag = 0;
}
+static int file_params_find_renamed(const FileSelectParams *params, struct FileList *filelist)
+{
+ /* Find the file either through the local ID/asset it represents or its relative path. */
+ return (params->rename_id != NULL) ? filelist_file_find_id(filelist, params->rename_id) :
+ filelist_file_find_path(filelist, params->renamefile);
+}
+
/**
* Helper used by both main update code, and smooth-scroll timer,
* to try to enable rename editing from #FileSelectParams.renamefile name.
@@ -1271,20 +1308,26 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
return;
}
- BLI_assert(params->renamefile[0] != '\0');
+ BLI_assert(params->renamefile[0] != '\0' || params->rename_id != NULL);
- const int idx = filelist_file_findpath(sfile->files, params->renamefile);
+ const int idx = file_params_find_renamed(params, sfile->files);
if (idx >= 0) {
FileDirEntry *file = filelist_file(sfile->files, idx);
BLI_assert(file != NULL);
+ params->active_file = idx;
+ filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+
if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
- filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
- params->renamefile[0] = '\0';
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
+ filelist_entry_select_set(
+ sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED, CHECK_ALL);
+ params->active_file = idx;
+ file_params_renamefile_clear(params);
params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE;
}
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 64b43ac74a5..05d484d8e2e 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -32,6 +32,7 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -469,10 +470,19 @@ static void file_listener(const wmSpaceTypeListenerParams *listener_params)
break;
case NC_ID: {
switch (wmn->action) {
- case NA_RENAME:
+ case NA_RENAME: {
+ const ID *active_file_id = ED_fileselect_active_asset_get(sfile);
+ /* If a renamed ID is active in the file browser, update scrolling to keep it in view. */
+ if (active_file_id && (wmn->reference == active_file_id)) {
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ params->rename_id = active_file_id;
+ file_params_invoke_rename_postscroll(G_MAIN->wm.first, listener_params->window, sfile);
+ }
+
/* Force list to update sorting (with a full reset for now). */
file_reset_filelist_showing_main_data(area, sfile);
break;
+ }
}
break;
}
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 082f66b57af..cc6effd0f71 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -1006,7 +1006,7 @@ void ED_image_undosys_type(UndoType *ut)
* specific case, see `image_undosys_step_encode` code. We cannot specify
* `UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE` though, as it can be called with a NULL context by
* current code. */
- ut->flags = 0;
+ ut->flags = UNDOTYPE_FLAG_DECODE_ACTIVE_STEP;
ut->step_size = sizeof(ImageUndoStep);
}
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index aaf9852e212..94e53958524 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -564,12 +564,11 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
/** \name Report Box Operator
* \{ */
-/* Hard to decide whether to keep this as an operator,
- * or turn it into a hardcoded ui control feature,
- * handling TIMER events for all regions in interface_handlers.c
+/* NOTE(matt): Hard to decide whether to keep this as an operator,
+ * or turn it into a hard_coded UI control feature,
+ * handling TIMER events for all regions in `interface_handlers.c`.
* Not sure how good that is to be accessing UI data from
- * inactive regions, so use this for now. --matt
- */
+ * inactive regions, so use this for now. */
#define INFO_TIMEOUT 5.0f
#define ERROR_TIMEOUT 10.0f
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 51b897ce5a3..0498964c549 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -874,7 +874,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
/* operate on selected objects... */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
/* ensure that object has AnimData... that's all */
- BKE_animdata_add_id(&ob->id);
+ BKE_animdata_ensure_id(&ob->id);
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 6e234c5b2ce..80d3b43bf6b 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../compositor
../../depsgraph
../../draw
+ ../../functions
../../gpu
../../imbuf
../../makesdna
@@ -39,7 +40,6 @@ set(INC
set(SRC
drawnode.cc
node_add.cc
- node_buttons.c
node_draw.cc
node_edit.cc
node_geometry_attribute_search.cc
@@ -78,4 +78,20 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
+endif()
+
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
deleted file mode 100644
index a55cc21fb16..00000000000
--- a/source/blender/editors/space_node/node_buttons.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup spnode
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_node_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_node.h"
-#include "BKE_screen.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-
-#include "ED_screen.h"
-
-#include "UI_resources.h"
-
-#include "node_intern.h" /* own include */
-
-/* ******************* node space & buttons ************** */
-
-#if 0
-/* poll for active nodetree */
-static bool active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->nodetree);
-}
-#endif
-
-static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->nodetree && G.debug_value == 777);
-}
-
-static void node_sockets_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
- bNode *node = nodeGetActive(ntree);
- if (node == NULL) {
- return;
- }
-
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- char name[UI_MAX_NAME_STR];
- BLI_snprintf(name, sizeof(name), "%s:", socket->name);
-
- uiLayout *split = uiLayoutSplit(panel->layout, 0.35f, false);
- uiItemL(split, name, ICON_NONE);
- uiTemplateNodeLink(split, (bContext *)C, ntree, node, socket);
- }
-}
-
-static bool node_tree_interface_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->edittree &&
- (snode->edittree->inputs.first || snode->edittree->outputs.first));
-}
-
-static bNodeSocket *node_tree_find_active_socket(bNodeTree *ntree, const eNodeSocketInOut in_out)
-{
- ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs;
- LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
- if (socket->flag & SELECT) {
- return socket;
- }
- }
- return NULL;
-}
-
-static void draw_socket_list(const bContext *C,
- uiLayout *layout,
- bNodeTree *ntree,
- const eNodeSocketInOut in_out)
-{
- PointerRNA tree_ptr;
- RNA_id_pointer_create((ID *)ntree, &tree_ptr);
-
- uiLayout *split = uiLayoutRow(layout, false);
- uiLayout *list_col = uiLayoutColumn(split, true);
- uiTemplateList(list_col,
- (bContext *)C,
- "NODE_UL_interface_sockets",
- (in_out == SOCK_IN) ? "inputs" : "outputs",
- &tree_ptr,
- (in_out == SOCK_IN) ? "inputs" : "outputs",
- &tree_ptr,
- (in_out == SOCK_IN) ? "active_input" : "active_output",
- NULL,
- 0,
- 0,
- 0,
- 0,
- false,
- false);
- PointerRNA opptr;
- uiLayout *ops_col = uiLayoutColumn(split, false);
- uiLayout *add_remove_col = uiLayoutColumn(ops_col, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_tree_socket_add", false);
- uiItemFullO_ptr(add_remove_col, ot, "", ICON_ADD, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "in_out", in_out);
- ot = WM_operatortype_find("NODE_OT_tree_socket_remove", false);
- uiItemFullO_ptr(add_remove_col, ot, "", ICON_REMOVE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "in_out", in_out);
-
- uiItemS(ops_col);
-
- uiLayout *up_down_col = uiLayoutColumn(ops_col, true);
- ot = WM_operatortype_find("NODE_OT_tree_socket_move", false);
- uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "direction", 1);
- RNA_enum_set(&opptr, "in_out", in_out);
- uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "direction", 2);
- RNA_enum_set(&opptr, "in_out", in_out);
-
- bNodeSocket *socket = node_tree_find_active_socket(ntree, in_out);
- if (socket != NULL) {
- PointerRNA socket_ptr;
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, socket, &socket_ptr);
-
- {
- /* Mimicking property split */
- uiLayoutSetPropSep(layout, false);
- uiLayoutSetPropDecorate(layout, false);
- uiLayout *layout_row = uiLayoutRow(layout, true);
- uiLayout *layout_split = uiLayoutSplit(layout_row, 0.4f, true);
-
- uiLayout *label_column = uiLayoutColumn(layout_split, true);
- uiLayoutSetAlignment(label_column, UI_LAYOUT_ALIGN_RIGHT);
- /* Menu to change the socket type. */
- uiItemL(label_column, "Type", ICON_NONE);
-
- uiLayout *property_row = uiLayoutRow(layout_split, true);
-
- PointerRNA props_ptr;
- uiItemMenuEnumFullO(property_row,
- (bContext *)C,
- "NODE_OT_tree_socket_change_type",
- "socket_type",
- nodeSocketTypeLabel(socket->typeinfo),
- ICON_NONE,
- &props_ptr);
- RNA_enum_set(&props_ptr, "in_out", in_out);
- }
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- uiItemR(layout, &socket_ptr, "name", 0, NULL, ICON_NONE);
-
- /* Display descriptions only for Geometry Nodes, since it's only used in the modifier panel. */
- if (ntree->type == NTREE_GEOMETRY) {
- uiItemR(layout, &socket_ptr, "description", 0, NULL, ICON_NONE);
- }
-
- if (socket->typeinfo->interface_draw) {
- socket->typeinfo->interface_draw((bContext *)C, layout, &socket_ptr);
- }
- }
-}
-
-static void node_tree_interface_inputs_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
-
- draw_socket_list(C, panel->layout, ntree, SOCK_IN);
-}
-
-static void node_tree_interface_outputs_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
-
- draw_socket_list(C, panel->layout, ntree, SOCK_OUT);
-}
-
-/* ******************* node buttons registration ************** */
-
-void node_buttons_register(ARegionType *art)
-{
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_sockets");
- strcpy(pt->category, N_("Node"));
- strcpy(pt->label, N_("Sockets"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_sockets_panel;
- pt->poll = node_sockets_poll;
- pt->flag |= PANEL_TYPE_DEFAULT_CLOSED;
- BLI_addtail(&art->paneltypes, pt);
- }
-
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_node_tree_interface_inputs");
- strcpy(pt->category, N_("Group"));
- strcpy(pt->label, N_("Inputs"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_tree_interface_inputs_panel;
- pt->poll = node_tree_interface_poll;
- BLI_addtail(&art->paneltypes, pt);
- }
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_node_tree_interface_outputs");
- strcpy(pt->category, N_("Group"));
- strcpy(pt->label, N_("Outputs"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_tree_interface_outputs_panel;
- pt->poll = node_tree_interface_poll;
- BLI_addtail(&art->paneltypes, pt);
- }
-}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 8a341da0b5c..7eca5c0c933 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -45,10 +45,10 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -76,6 +76,8 @@
#include "RNA_access.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "node_intern.h" /* own include */
#ifdef WITH_COMPOSITOR
@@ -86,6 +88,9 @@ using blender::Map;
using blender::Set;
using blender::Span;
using blender::Vector;
+using blender::fn::CPPType;
+using blender::fn::GPointer;
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
extern "C" {
/* XXX interface.h */
@@ -822,6 +827,149 @@ void node_socket_color_get(
}
}
+struct SocketTooltipData {
+ bNodeTree *ntree;
+ bNode *node;
+ bNodeSocket *socket;
+};
+
+static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log,
+ std::stringstream &ss)
+{
+ auto id_to_inspection_string = [&](ID *id) {
+ ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(GS(id->name))
+ << ")";
+ };
+
+ const GPointer value = value_log.value();
+ if (value.is_type<int>()) {
+ ss << *value.get<int>() << TIP_(" (Integer)");
+ }
+ else if (value.is_type<float>()) {
+ ss << *value.get<float>() << TIP_(" (Float)");
+ }
+ else if (value.is_type<blender::float3>()) {
+ ss << *value.get<blender::float3>() << TIP_(" (Vector)");
+ }
+ else if (value.is_type<bool>()) {
+ ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (value.is_type<std::string>()) {
+ ss << *value.get<std::string>() << TIP_(" (String)");
+ }
+ else if (value.is_type<Object *>()) {
+ id_to_inspection_string((ID *)*value.get<Object *>());
+ }
+ else if (value.is_type<Material *>()) {
+ id_to_inspection_string((ID *)*value.get<Material *>());
+ }
+ else if (value.is_type<Tex *>()) {
+ id_to_inspection_string((ID *)*value.get<Tex *>());
+ }
+ else if (value.is_type<Collection *>()) {
+ id_to_inspection_string((ID *)*value.get<Collection *>());
+ }
+}
+
+static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
+ std::stringstream &ss)
+{
+ Span<GeometryComponentType> component_types = value_log.component_types();
+ if (component_types.is_empty()) {
+ ss << TIP_("Empty Geometry");
+ return;
+ }
+
+ auto to_string = [](int value) {
+ char str[16];
+ BLI_str_format_int_grouped(str, value);
+ return std::string(str);
+ };
+
+ ss << TIP_("Geometry:\n");
+ for (GeometryComponentType type : component_types) {
+ const char *line_end = (type == component_types.last()) ? "" : ".\n";
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const geo_log::GeometryValueLog::MeshInfo &mesh_info = *value_log.mesh_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"),
+ to_string(mesh_info.tot_verts).c_str(),
+ to_string(mesh_info.tot_edges).c_str(),
+ to_string(mesh_info.tot_faces).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const geo_log::GeometryValueLog::PointCloudInfo &pointcloud_info =
+ *value_log.pointcloud_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Point Cloud: %s points"),
+ to_string(pointcloud_info.tot_points).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const geo_log::GeometryValueLog::CurveInfo &curve_info = *value_log.curve_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Curve: %s splines"),
+ to_string(curve_info.tot_splines).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const geo_log::GeometryValueLog::InstancesInfo &instances_info = *value_log.instances_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Instances: %s"),
+ to_string(instances_info.tot_instances).c_str());
+ ss << line << line_end;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ ss << TIP_("\u2022 Volume") << line_end;
+ break;
+ }
+ }
+ }
+}
+
+static std::optional<std::string> create_socket_inspection_string(bContext *C,
+ bNodeTree &UNUSED(ntree),
+ bNode &node,
+ bNodeSocket &socket)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::SocketLog *socket_log = geo_log::ModifierLog::find_socket_by_node_editor_context(
+ *snode, node, socket);
+ if (socket_log == nullptr) {
+ return {};
+ }
+ const geo_log::ValueLog *value_log = socket_log->value();
+ if (value_log == nullptr) {
+ return {};
+ }
+
+ std::stringstream ss;
+ if (const geo_log::GenericValueLog *generic_value_log =
+ dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
+ create_inspection_string_for_generic_value(*generic_value_log, ss);
+ }
+ else if (const geo_log::GeometryValueLog *geo_value_log =
+ dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
+ create_inspection_string_for_geometry(*geo_value_log, ss);
+ }
+
+ return ss.str();
+}
+
static void node_socket_draw_nested(const bContext *C,
bNodeTree *ntree,
PointerRNA *node_ptr,
@@ -851,6 +999,55 @@ static void node_socket_draw_nested(const bContext *C,
shape_id,
size_id,
outline_col_id);
+
+ if (ntree->type != NTREE_GEOMETRY) {
+ /* Only geometry nodes has socket value tooltips currently. */
+ return;
+ }
+
+ bNode *node = (bNode *)node_ptr->data;
+ uiBlock *block = node->block;
+
+ /* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
+ * button on top of them for the tooltip. */
+ const eUIEmbossType old_emboss = UI_block_emboss_get(block);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_NONE,
+ sock->locx - size / 2,
+ sock->locy - size / 2,
+ size,
+ size,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+
+ SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
+ data->ntree = ntree;
+ data->node = (bNode *)node_ptr->data;
+ data->socket = sock;
+
+ UI_but_func_tooltip_set(
+ but,
+ [](bContext *C, void *argN, const char *UNUSED(tip)) {
+ SocketTooltipData *data = (SocketTooltipData *)argN;
+ std::optional<std::string> str = create_socket_inspection_string(
+ C, *data->ntree, *data->node, *data->socket);
+ if (str.has_value()) {
+ return BLI_strdup(str->c_str());
+ }
+ return BLI_strdup(TIP_("The socket value has not been computed yet"));
+ },
+ data,
+ MEM_freeN);
+ /* Disable the button so that clicks on it are ignored the the link operator still works. */
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ UI_block_emboss_set(block, old_emboss);
}
/**
@@ -1185,14 +1382,14 @@ void node_draw_sockets(const View2D *v2d,
}
}
-static int node_error_type_to_icon(const NodeWarningType type)
+static int node_error_type_to_icon(const geo_log::NodeWarningType type)
{
switch (type) {
- case NodeWarningType::Error:
+ case geo_log::NodeWarningType::Error:
return ICON_ERROR;
- case NodeWarningType::Warning:
+ case geo_log::NodeWarningType::Warning:
return ICON_ERROR;
- case NodeWarningType::Info:
+ case geo_log::NodeWarningType::Info:
return ICON_INFO;
}
@@ -1200,14 +1397,14 @@ static int node_error_type_to_icon(const NodeWarningType type)
return ICON_ERROR;
}
-static uint8_t node_error_type_priority(const NodeWarningType type)
+static uint8_t node_error_type_priority(const geo_log::NodeWarningType type)
{
switch (type) {
- case NodeWarningType::Error:
+ case geo_log::NodeWarningType::Error:
return 3;
- case NodeWarningType::Warning:
+ case geo_log::NodeWarningType::Warning:
return 2;
- case NodeWarningType::Info:
+ case geo_log::NodeWarningType::Info:
return 1;
}
@@ -1215,11 +1412,11 @@ static uint8_t node_error_type_priority(const NodeWarningType type)
return 0;
}
-static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
+static geo_log::NodeWarningType node_error_highest_priority(Span<geo_log::NodeWarning> warnings)
{
uint8_t highest_priority = 0;
- NodeWarningType highest_priority_type = NodeWarningType::Info;
- for (const NodeWarning &warning : warnings) {
+ geo_log::NodeWarningType highest_priority_type = geo_log::NodeWarningType::Info;
+ for (const geo_log::NodeWarning &warning : warnings) {
const uint8_t priority = node_error_type_priority(warning.type);
if (priority > highest_priority) {
highest_priority = priority;
@@ -1229,15 +1426,17 @@ static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
return highest_priority_type;
}
+struct NodeErrorsTooltipData {
+ Span<geo_log::NodeWarning> warnings;
+};
+
static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
{
- const NodeUIStorage **storage_pointer_alloc = static_cast<const NodeUIStorage **>(argN);
- const NodeUIStorage *node_ui_storage = *storage_pointer_alloc;
- Span<NodeWarning> warnings = node_ui_storage->warnings;
+ NodeErrorsTooltipData &data = *(NodeErrorsTooltipData *)argN;
std::string complete_string;
- for (const NodeWarning &warning : warnings.drop_back(1)) {
+ for (const geo_log::NodeWarning &warning : data.warnings.drop_back(1)) {
complete_string += warning.message;
/* Adding the period is not ideal for multi-line messages, but it is consistent
* with other tooltip implementations in Blender, so it is added here. */
@@ -1246,7 +1445,7 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
}
/* Let the tooltip system automatically add the last period. */
- complete_string += warnings.last().message;
+ complete_string += data.warnings.last().message;
return BLI_strdupn(complete_string.c_str(), complete_string.size());
}
@@ -1254,20 +1453,26 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
#define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
static void node_add_error_message_button(
- const bContext *C, bNodeTree &ntree, bNode &node, const rctf &rect, float &icon_offset)
+ const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset)
{
- const NodeUIStorage *node_ui_storage = BKE_node_tree_ui_storage_get_from_context(C, ntree, node);
- if (node_ui_storage == nullptr || node_ui_storage->warnings.is_empty()) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode,
+ node);
+ if (node_log == nullptr) {
+ return;
+ }
+
+ Span<geo_log::NodeWarning> warnings = node_log->warnings();
+
+ if (warnings.is_empty()) {
return;
}
- /* The UI API forces us to allocate memory for each error button, because the
- * ownership of #UI_but_func_tooltip_set's argument is transferred to the button. */
- const NodeUIStorage **storage_pointer_alloc = (const NodeUIStorage **)MEM_mallocN(
- sizeof(NodeUIStorage *), __func__);
- *storage_pointer_alloc = node_ui_storage;
+ NodeErrorsTooltipData *tooltip_data = (NodeErrorsTooltipData *)MEM_mallocN(
+ sizeof(NodeErrorsTooltipData), __func__);
+ tooltip_data->warnings = warnings;
- const NodeWarningType display_type = node_error_highest_priority(node_ui_storage->warnings);
+ const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
icon_offset -= NODE_HEADER_ICON_SIZE;
UI_block_emboss_set(node.block, UI_EMBOSS_NONE);
@@ -1285,7 +1490,7 @@ static void node_add_error_message_button(
0,
0,
nullptr);
- UI_but_func_tooltip_set(but, node_errors_tooltip_fn, storage_pointer_alloc, MEM_freeN);
+ UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN);
UI_block_emboss_set(node.block, UI_EMBOSS);
}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 94080a7b616..a6901c21862 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -27,7 +27,6 @@
#include "DNA_space_types.h"
#include "BKE_context.h"
-#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "RNA_access.h"
@@ -40,17 +39,21 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "node_intern.h"
using blender::IndexRange;
using blender::Map;
using blender::Set;
using blender::StringRef;
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+using geo_log::GeometryAttributeInfo;
struct AttributeSearchData {
- AvailableAttributeInfo &dummy_info_for_search;
- const NodeUIStorage &ui_storage;
- bNodeSocket &socket;
+ const bNodeTree *tree;
+ const bNode *node;
+ bNodeSocket *socket;
};
/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
@@ -73,7 +76,7 @@ static StringRef attribute_domain_string(const AttributeDomain domain)
/* Unicode arrow. */
#define MENU_SEP "\xe2\x96\xb6"
-static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttributeInfo &item)
+static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
{
const StringRef data_type_name = attribute_data_type_string(item.data_type);
const StringRef domain_name = attribute_domain_string(item.domain);
@@ -84,31 +87,47 @@ static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttri
items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
}
-static void attribute_search_update_fn(const bContext *UNUSED(C),
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first)
+static GeometryAttributeInfo &get_dummy_item_info()
+{
+ static GeometryAttributeInfo info;
+ return info;
+}
+
+static void attribute_search_update_fn(
+ const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
- const Set<AvailableAttributeInfo> &attribute_hints = data->ui_storage.attribute_hints;
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(
+ *snode, *data->node);
+ if (node_log == nullptr) {
+ return;
+ }
+ blender::Vector<const GeometryAttributeInfo *> infos = node_log->lookup_available_attributes();
+
+ GeometryAttributeInfo &dummy_info = get_dummy_item_info();
/* Any string may be valid, so add the current search string along with the hints. */
if (str[0] != '\0') {
- /* Note that the attribute domain and data type are dummies, since
- * #AvailableAttributeInfo equality is only based on the string. */
- if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) {
- data->dummy_info_for_search.name = std::string(str);
- UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_ADD, 0, 0);
+ bool contained = false;
+ for (const GeometryAttributeInfo *attribute_info : infos) {
+ if (attribute_info->name == str) {
+ contained = true;
+ break;
+ }
+ }
+ if (!contained) {
+ dummy_info.name = str;
+ UI_search_item_add(items, str, &dummy_info, ICON_ADD, 0, 0);
}
}
if (str[0] == '\0' && !is_first) {
/* Allow clearing the text field when the string is empty, but not on the first pass,
* or opening an attribute field for the first time would show this search item. */
- data->dummy_info_for_search.name = std::string(str);
- UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_X, 0, 0);
+ dummy_info.name = str;
+ UI_search_item_add(items, str, &dummy_info, ICON_X, 0, 0);
}
/* Don't filter when the menu is first opened, but still run the search
@@ -116,15 +135,15 @@ static void attribute_search_update_fn(const bContext *UNUSED(C),
const char *string = is_first ? "" : str;
StringSearch *search = BLI_string_search_new();
- for (const AvailableAttributeInfo &item : attribute_hints) {
- BLI_string_search_add(search, item.name.c_str(), (void *)&item);
+ for (const GeometryAttributeInfo *item : infos) {
+ BLI_string_search_add(search, item->name.c_str(), (void *)item);
}
- AvailableAttributeInfo **filtered_items;
+ GeometryAttributeInfo **filtered_items;
const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
for (const int i : IndexRange(filtered_amount)) {
- const AvailableAttributeInfo *item = filtered_items[i];
+ const GeometryAttributeInfo *item = filtered_items[i];
if (!attribute_search_item_add(items, *item)) {
break;
}
@@ -136,32 +155,25 @@ static void attribute_search_update_fn(const bContext *UNUSED(C),
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
{
+ if (item_v == nullptr) {
+ return;
+ }
AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v);
- AvailableAttributeInfo *item = static_cast<AvailableAttributeInfo *>(item_v);
+ GeometryAttributeInfo *item = (GeometryAttributeInfo *)item_v;
- bNodeSocket &socket = data->socket;
+ bNodeSocket &socket = *data->socket;
bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket.default_value);
BLI_strncpy(value->value, item->name.c_str(), MAX_NAME);
ED_undo_push(C, "Assign Attribute Name");
}
-void node_geometry_add_attribute_search_button(const bContext *C,
+void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
const bNodeTree *node_tree,
const bNode *node,
PointerRNA *socket_ptr,
uiLayout *layout)
{
- const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context(
- C, *node_tree, *node);
-
- if (ui_storage == nullptr) {
- uiItemR(layout, socket_ptr, "default_value", 0, "", 0);
- return;
- }
-
- const NodeTreeUIStorage *tree_ui_storage = node_tree->ui_storage;
-
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but = uiDefIconTextButR(block,
UI_BTYPE_SEARCH_MENU,
@@ -181,10 +193,8 @@ void node_geometry_add_attribute_search_button(const bContext *C,
0.0f,
"");
- AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData,
- {tree_ui_storage->dummy_info_for_search,
- *ui_storage,
- *static_cast<bNodeSocket *>(socket_ptr->data)});
+ AttributeSearchData *data = OBJECT_GUARDED_NEW(
+ AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, MENU_SEP);
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index fe550242dbe..09e5a110a45 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -140,9 +140,6 @@ void node_to_view(const struct bNode *node, float x, float y, float *rx, float *
void node_to_updated_rect(const struct bNode *node, rctf *r_rect);
void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry);
-/* node_buttons.c */
-void node_buttons_register(struct ARegionType *art);
-
/* node_toolbar.c */
void node_toolbar_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index d7e16dd69f1..ff848a7bb95 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -651,6 +651,10 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region)
lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
WM_event_add_dropbox_handler(&region->handlers, lb);
+
+ /* The backdrop image gizmo needs to change together with the view. So always refresh gizmos on
+ * region size changes. */
+ WM_gizmomap_tag_refresh(region->gizmo_map);
}
static void node_main_region_draw(const bContext *C, ARegion *region)
@@ -1094,8 +1098,6 @@ void ED_spacetype_node(void)
art->draw = node_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
- node_buttons_register(art);
-
/* regions: toolbar */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index d1fb36979b4..db37c8c1c8c 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2964,7 +2964,8 @@ static void outliner_draw_iconrow(bContext *C,
te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
/* object hierarchy always, further constrained on level */
- if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
+ if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
+ ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) {
/* active blocks get white circle */
if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index f248711633e..35015356f0b 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -42,6 +42,7 @@
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_layer.h"
@@ -450,7 +451,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto
/* id in tselem is object */
Object *ob = (Object *)tselem->id;
BLI_assert(te->index + 1 >= 0);
- ob->actdef = te->index + 1;
+ BKE_object_defgroup_active_index_set(ob, te->index + 1);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
@@ -830,7 +831,7 @@ static eOLDrawState tree_element_defgroup_state_get(const ViewLayer *view_layer,
{
const Object *ob = (const Object *)tselem->id;
if (ob == OBACT(view_layer)) {
- if (ob->actdef == te->index + 1) {
+ if (BKE_object_defgroup_active_index_get(ob) == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 334c901b6d3..c08707b7a6a 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1,4 +1,4 @@
-/*
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -62,6 +62,7 @@
#include "BLT_translation.h"
#include "BKE_armature.h"
+#include "BKE_deform.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -552,17 +553,20 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
/* vertex groups */
- if (!BLI_listbase_is_empty(&ob->defbase)) {
- TreeElement *tenla = outliner_add_element(
- space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
- tenla->name = IFACE_("Vertex Groups");
+ if (ELEM(ob->type, OB_MESH, OB_GPENCIL, OB_LATTICE)) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ if (!BLI_listbase_is_empty(defbase)) {
+ TreeElement *tenla = outliner_add_element(
+ space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
+ tenla->name = IFACE_("Vertex Groups");
- int index;
- LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, &ob->defbase, index) {
- TreeElement *ten = outliner_add_element(
- space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index);
- ten->name = defgroup->name;
- ten->directdata = defgroup;
+ int index;
+ LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, defbase, index) {
+ TreeElement *ten = outliner_add_element(
+ space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index);
+ ten->name = defgroup->name;
+ ten->directdata = defgroup;
+ }
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index f089a149805..96af8258010 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -86,7 +86,7 @@ class TreeDisplayViewLayer final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- void add_view_layer(ListBase &, TreeElement &);
+ void add_view_layer(Scene &, ListBase &, TreeElement *);
void add_layer_collections_recursive(ListBase &, ListBase &, TreeElement &);
void add_layer_collection_objects(ListBase &, LayerCollection &, TreeElement &);
void add_layer_collection_objects_children(TreeElement &);
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
index 3059f8bfe0c..a17bf174a74 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
@@ -150,27 +150,25 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
}
/* Create data-block list parent element on demand. */
- if (id != nullptr) {
- TreeElement *ten;
+ TreeElement *ten;
- if (filter_id_type) {
- ten = tenlib;
- }
- else {
- ten = outliner_add_element(
- &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
- ten->name = outliner_idcode_to_plural(GS(id->name));
- }
+ if (filter_id_type) {
+ ten = tenlib;
+ }
+ else {
+ ten = outliner_add_element(
+ &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+ ten->name = outliner_idcode_to_plural(GS(id->name));
+ }
- for (ID *id : List<ID>(lbarray[a])) {
- if (override_library_id_filter_poll(lib, id)) {
- TreeElement *override_tree_element = outliner_add_element(
- &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0);
+ for (ID *id : List<ID>(lbarray[a])) {
+ if (override_library_id_filter_poll(lib, id)) {
+ TreeElement *override_tree_element = outliner_add_element(
+ &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0);
- if (BLI_listbase_is_empty(&override_tree_element->subtree)) {
- outliner_free_tree_element(override_tree_element, &ten->subtree);
- }
+ if (BLI_listbase_is_empty(&override_tree_element->subtree)) {
+ outliner_free_tree_element(override_tree_element, &ten->subtree);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index 402526bbe8d..c3d0aecd3cb 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -70,74 +70,69 @@ TreeDisplayViewLayer::TreeDisplayViewLayer(SpaceOutliner &space_outliner)
ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
-
Scene *scene = source_data.scene;
show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT);
- const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
-
for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene->view_layers)) {
+ view_layer_ = view_layer;
+
if (space_outliner_.filter & SO_FILTER_NO_VIEW_LAYERS) {
if (view_layer != source_data.view_layer) {
continue;
}
- }
- TreeElement &te_view_layer = *outliner_add_element(
- &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0);
- TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED;
- te_view_layer.name = view_layer->name;
- te_view_layer.directdata = view_layer;
- view_layer_ = view_layer;
-
- if (space_outliner_.filter & SO_FILTER_NO_COLLECTION) {
- /* Show objects in the view layer. */
- for (Base *base : List<Base>(view_layer_->object_bases)) {
- TreeElement *te_object = outliner_add_element(&space_outliner_,
- &te_view_layer.subtree,
- base->object,
- &te_view_layer,
- TSE_SOME_ID,
- 0);
- te_object->directdata = base;
- }
-
- if (show_children) {
- outliner_make_object_parent_hierarchy(&tree);
- }
+ add_view_layer(*scene, tree, (TreeElement *)nullptr);
}
else {
- /* Show collections in the view layer. */
- TreeElement &ten = *outliner_add_element(&space_outliner_,
- &te_view_layer.subtree,
- source_data.scene,
- &te_view_layer,
- TSE_VIEW_COLLECTION_BASE,
- 0);
- ten.name = IFACE_("Scene Collection");
- TREESTORE(&ten)->flag &= ~TSE_CLOSED;
-
- add_view_layer(ten.subtree, ten);
- if (show_children) {
- add_layer_collection_objects_children(ten);
- }
+ TreeElement &te_view_layer = *outliner_add_element(
+ &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0);
+ TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED;
+ te_view_layer.name = view_layer->name;
+ te_view_layer.directdata = view_layer;
+
+ add_view_layer(*scene, te_view_layer.subtree, &te_view_layer);
}
}
return tree;
}
-void TreeDisplayViewLayer::add_view_layer(ListBase &tree, TreeElement &parent)
+void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent)
{
- /* First layer collection is for master collection, don't show it. */
- LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
- if (lc == nullptr) {
- return;
+ const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
+
+ if (space_outliner_.filter & SO_FILTER_NO_COLLECTION) {
+ /* Show objects in the view layer. */
+ for (Base *base : List<Base>(view_layer_->object_bases)) {
+ TreeElement *te_object = outliner_add_element(
+ &space_outliner_, &tree, base->object, parent, TSE_SOME_ID, 0);
+ te_object->directdata = base;
+ }
+
+ if (show_children) {
+ outliner_make_object_parent_hierarchy(&tree);
+ }
}
+ else {
+ /* Show collections in the view layer. */
+ TreeElement &ten = *outliner_add_element(
+ &space_outliner_, &tree, &scene, parent, TSE_VIEW_COLLECTION_BASE, 0);
+ ten.name = IFACE_("Scene Collection");
+ TREESTORE(&ten)->flag &= ~TSE_CLOSED;
+
+ /* First layer collection is for master collection, don't show it. */
+ LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
+ if (lc == nullptr) {
+ return;
+ }
- add_layer_collections_recursive(tree, lc->layer_collections, parent);
- if (show_objects_) {
- add_layer_collection_objects(tree, *lc, parent);
+ add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten);
+ if (show_objects_) {
+ add_layer_collection_objects(ten.subtree, *lc, ten);
+ }
+ if (show_children) {
+ add_layer_collection_objects_children(ten);
+ }
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ac31e0e7c37..1239286d4da 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -260,7 +260,7 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
BLI_strncpy(load_data->name, filename, sizeof(load_data->name));
- BLI_snprintf(load_data->path, sizeof(load_data->path), "%s%s", directory, filename);
+ BLI_join_dirfile(load_data->path, sizeof(load_data->path), directory, filename);
MEM_freeN(filename);
break;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 82283b03fc8..8371a634a78 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2479,13 +2479,14 @@ void draw_timeline_seq_display(const bContext *C, ARegion *region)
const SpaceSeq *sseq = CTX_wm_space_seq(C);
View2D *v2d = &region->v2d;
- UI_view2d_view_ortho(v2d);
- draw_cache_view(C);
-
- if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
- draw_overlap_frame_indicator(scene, v2d);
+ if (scene->ed != NULL) {
+ UI_view2d_view_ortho(v2d);
+ draw_cache_view(C);
+ if (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
+ draw_overlap_frame_indicator(scene, v2d);
+ }
+ UI_view2d_view_restore(C);
}
- 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 45c6931364d..75cf8542f67 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -2414,6 +2414,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
(LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_MAIN));
seqbase_clipboard_frame = scene->r.cfra;
+ SEQ_clipboard_active_seq_name_store(scene);
/* Remove anything that references the current scene. */
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
@@ -2504,6 +2505,10 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(ed->seqbasep, &nseqbase);
for (iseq = iseq_first; iseq; iseq = iseq->next) {
+ if (SEQ_clipboard_pasted_seq_was_active(iseq)) {
+ SEQ_select_active_set(scene, iseq);
+ }
+
/* Make sure, that pasted strips have unique names. */
SEQ_ensure_unique_name(iseq, scene);
/* Translate after name has been changed, otherwise this will affect animdata of original
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 8cc8b4a007b..5d857f62b47 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -624,8 +624,6 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, i
{
float rgb[3], yuv[3];
char *p;
- int x = 0;
- int y = 0;
rgb[0] = (float)r / 255.0f;
rgb[1] = (float)g / 255.0f;
@@ -638,8 +636,8 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, i
r = 255;
}
- for (y = -size; y <= size; y++) {
- for (x = -size; x <= size; x++) {
+ for (int y = -size; y <= size; y++) {
+ for (int x = -size; x <= size; x++) {
char *q = p + 4 * (y * w + x);
q[0] = r;
q[1] = g;
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 1ea6593588a..e903feeec1b 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../gpu
../../makesdna
../../makesrna
+ ../../nodes
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
@@ -34,8 +35,8 @@ set(INC
set(SRC
space_spreadsheet.cc
- spreadsheet_context.cc
spreadsheet_column.cc
+ spreadsheet_context.cc
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
spreadsheet_dataset_draw.cc
@@ -46,10 +47,10 @@ set(SRC
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
- spreadsheet_context.hh
spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
+ spreadsheet_context.hh
spreadsheet_data_source.hh
spreadsheet_data_source_geometry.hh
spreadsheet_dataset_draw.hh
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 f730f199ca4..e38c70afd0f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -31,11 +31,15 @@
#include "ED_spreadsheet.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "bmesh.h"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+
namespace blender::ed::spreadsheet {
void GeometryDataSource::foreach_default_column_ids(
@@ -410,7 +414,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
Mesh *mesh = (Mesh *)object_orig->data;
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
}
- mesh_component.copy_vertex_group_names_from_object(*object_orig);
}
else if (object_orig->type == OB_POINTCLOUD) {
PointCloud *pointcloud = (PointCloud *)object_orig->data;
@@ -428,7 +431,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
BKE_mesh_wrapper_ensure_mdata(mesh);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
- mesh_component.copy_vertex_group_names_from_object(*object_eval);
}
else {
if (BLI_listbase_count(&sspreadsheet->context_path) == 1) {
@@ -438,13 +440,18 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
- if (object_eval->runtime.geometry_set_previews != nullptr) {
- GHash *ghash = (GHash *)object_eval->runtime.geometry_set_previews;
- const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
- GeometrySet *geometry_set_preview = (GeometrySet *)BLI_ghash_lookup_default(
- ghash, POINTER_FROM_UINT(key), nullptr);
- if (geometry_set_preview != nullptr) {
- geometry_set = *geometry_set_preview;
+ const geo_log::NodeLog *node_log =
+ geo_log::ModifierLog::find_node_by_spreadsheet_editor_context(*sspreadsheet);
+ if (node_log != nullptr) {
+ for (const geo_log::SocketLog &input_log : node_log->input_logs()) {
+ if (const geo_log::GeometryValueLog *geo_value_log =
+ dynamic_cast<const geo_log::GeometryValueLog *>(input_log.value())) {
+ const GeometrySet *full_geometry = geo_value_log->full_geometry();
+ if (full_geometry != nullptr) {
+ geometry_set = *full_geometry;
+ break;
+ }
+ }
}
}
}
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index f55db8c3cc9..80af7d8c9f6 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -265,7 +265,7 @@ void ED_text_undosys_type(UndoType *ut)
ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref;
- ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE;
+ ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE | UNDOTYPE_FLAG_DECODE_ACTIVE_STEP;
ut->step_size = sizeof(TextUndoStep);
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 60e1c780b9e..3428a738dde 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -39,6 +39,8 @@
#include "BLT_translation.h"
+#include "BLI_array_utils.h"
+#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -112,10 +114,94 @@ typedef struct {
float ob_dims[3];
/* Floats only (treated as an array). */
TransformMedian ve_median, median;
+ bool tag_for_update;
} TransformProperties;
#define TRANSFORM_MEDIAN_ARRAY_LEN (sizeof(TransformMedian) / sizeof(float))
+static TransformProperties *v3d_transform_props_ensure(View3D *v3d);
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mesh Partial Updates
+ * \{ */
+
+static void *editmesh_partial_update_begin_fn(struct bContext *UNUSED(C),
+ const struct uiBlockInteraction_Params *params,
+ void *arg1)
+{
+ const int retval_test = B_TRANSFORM_PANEL_MEDIAN;
+ if (BLI_array_findindex(
+ params->unique_retval_ids, params->unique_retval_ids_len, &retval_test) == -1) {
+ return NULL;
+ }
+
+ BMEditMesh *em = arg1;
+
+ int verts_mask_count = 0;
+ BMIter iter;
+ BMVert *eve;
+ int i;
+
+ BLI_bitmap *verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(verts_mask, i);
+ verts_mask_count += 1;
+ }
+
+ BMPartialUpdate *bmpinfo = BM_mesh_partial_create_from_verts_group_single(
+ em->bm,
+ &(BMPartialUpdate_Params){
+ .do_tessellate = true,
+ .do_normals = true,
+ },
+ verts_mask,
+ verts_mask_count);
+
+ MEM_freeN(verts_mask);
+
+ return bmpinfo;
+}
+
+static void editmesh_partial_update_end_fn(struct bContext *UNUSED(C),
+ const struct uiBlockInteraction_Params *UNUSED(params),
+ void *UNUSED(arg1),
+ void *user_data)
+{
+ BMPartialUpdate *bmpinfo = user_data;
+ if (bmpinfo == NULL) {
+ return;
+ }
+ BM_mesh_partial_destroy(bmpinfo);
+}
+
+static void editmesh_partial_update_update_fn(
+ struct bContext *C,
+ const struct uiBlockInteraction_Params *UNUSED(params),
+ void *arg1,
+ void *user_data)
+{
+ BMPartialUpdate *bmpinfo = user_data;
+ if (bmpinfo == NULL) {
+ return;
+ }
+
+ View3D *v3d = CTX_wm_view3d(C);
+ TransformProperties *tfp = v3d_transform_props_ensure(v3d);
+ if (tfp->tag_for_update == false) {
+ return;
+ }
+ tfp->tag_for_update = false;
+
+ BMEditMesh *em = arg1;
+
+ BKE_editmesh_looptri_and_normals_calc_with_partial(em, bmpinfo);
+}
+
+/** \} */
+
/* Helper function to compute a median changed value,
* when the value should be clamped in [0.0, 1.0].
* Returns either 0.0, 1.0 (both can be applied directly), a positive scale factor
@@ -840,6 +926,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
UI_block_align_end(block);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL) {
+ UI_block_interaction_set(block,
+ &(uiBlockInteraction_CallbackData){
+ .begin_fn = editmesh_partial_update_begin_fn,
+ .end_fn = editmesh_partial_update_end_fn,
+ .update_fn = editmesh_partial_update_update_fn,
+ .arg1 = em,
+ });
+ }
+ }
}
else { /* apply */
memcpy(&ve_median_basis, &tfp->ve_median, sizeof(tfp->ve_median));
@@ -927,9 +1027,8 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (apply_vcos) {
- /* 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);
+ /* Tell the update callback to run. */
+ tfp->tag_for_update = true;
}
/* Edges */
@@ -1152,7 +1251,7 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = view_layer->basact->object;
ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
@@ -1211,7 +1310,9 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel)
vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
ob, subset_type, &vgroup_tot, &subset_count);
- for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
+ for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0;
if (vgroup_validmap[i]) {
MDeformWeight *dw = BKE_defvert_find_index(dv, i);
@@ -1237,7 +1338,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel)
but_ptr = UI_but_operator_ptr_get(but);
RNA_int_set(but_ptr, "weight_group", i);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
- if (ob->actdef != i + 1) {
+ if (BKE_object_defgroup_active_index_get(ob) != i + 1) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
xco += x;
@@ -1464,7 +1565,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
/* XXX: RNA buts show data in native types (i.e. quats, 4-component axis/angle, etc.)
* but old-school UI shows in eulers always. Do we want to be able to still display in Eulers?
- * Maybe needs RNA/ui options to display rotations as different types... */
+ * Maybe needs RNA/UI options to display rotations as different types. */
v3d_transform_butsR(col, &pchanptr);
}
@@ -1568,7 +1669,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
case B_TRANSFORM_PANEL_MEDIAN:
if (ob) {
v3d_editvertex_buts(NULL, v3d, ob, 1.0);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
break;
case B_TRANSFORM_PANEL_DIMS:
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index ea9d9a8c010..c97ba7ba7e9 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1404,7 +1404,7 @@ static void draw_selected_name(
/* color depends on whether there is a keyframe */
if (id_frame_has_keyframe(
- (ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) {
+ (ID *)ob, /* BKE_scene_ctime_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) {
UI_FontThemeColor(font_id, TH_TIME_KEYFRAME);
}
else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) {
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index e2fa0fdc6a5..5752837c40f 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -122,7 +122,7 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
{FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
{FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"},
- {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"},
+ {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction (toggle)"},
{FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision", ""},
{FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision (Off)", ""},
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 435d74aa591..09936b41a74 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -98,9 +98,10 @@ enum {
WALK_MODAL_JUMP,
WALK_MODAL_JUMP_STOP,
WALK_MODAL_TELEPORT,
- WALK_MODAL_TOGGLE,
+ WALK_MODAL_GRAVITY_TOGGLE,
WALK_MODAL_ACCELERATE,
WALK_MODAL_DECELERATE,
+ WALK_MODAL_AXIS_LOCK_Z,
};
enum {
@@ -129,6 +130,18 @@ typedef enum eWalkGravityState {
WALK_GRAVITY_STATE_ON,
} eWalkGravityState;
+/* Relative view axis z axis locking. */
+typedef enum eWalkLockState {
+ /* Disabled. */
+ WALK_AXISLOCK_STATE_OFF = 0,
+
+ /* Moving. */
+ WALK_AXISLOCK_STATE_ACTIVE = 2,
+
+ /* Done moving, it cannot be activated again. */
+ WALK_AXISLOCK_STATE_DONE = 3,
+} eWalkLockState;
+
/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
@@ -164,7 +177,9 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"},
{WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump (Off)", "Stop pushing jump"},
- {WALK_MODAL_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+ {WALK_MODAL_GRAVITY_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+
+ {WALK_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction"},
{0, NULL, 0, NULL, NULL},
};
@@ -292,6 +307,10 @@ typedef struct WalkInfo {
/** To use for fast/slow speeds. */
float speed_factor;
+ eWalkLockState zlock;
+ /** Nicer dynamics. */
+ float zlock_momentum;
+
struct SnapObjectContext *snap_context;
struct View3DCameraControl *v3d_camera_control;
@@ -540,6 +559,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->jump_height = U.walk_navigation.jump_height;
walk->speed = U.walk_navigation.walk_speed;
walk->speed_factor = U.walk_navigation.walk_speed_factor;
+ walk->zlock = WALK_AXISLOCK_STATE_OFF;
walk->gravity_state = WALK_GRAVITY_STATE_OFF;
@@ -708,8 +728,6 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk->is_cursor_absolute = true;
copy_v2_v2_int(walk->prev_mval, event->mval);
copy_v2_v2_int(walk->center_mval, event->mval);
- /* Without this we can't turn 180d with the default speed of 1.0. */
- walk->mouse_speed *= 4.0f;
}
#endif /* USE_TABLET_SUPPORT */
@@ -941,7 +959,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
#undef JUMP_TIME_MAX
#undef JUMP_SPEED_MIN
- case WALK_MODAL_TOGGLE:
+ case WALK_MODAL_GRAVITY_TOGGLE:
if (walk->navigation_mode == WALK_MODE_GRAVITY) {
walk_navigation_mode_set(walk, WALK_MODE_FREE);
}
@@ -949,6 +967,13 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk_navigation_mode_set(walk, WALK_MODE_GRAVITY);
}
break;
+
+ case WALK_MODAL_AXIS_LOCK_Z:
+ if (walk->zlock != WALK_AXISLOCK_STATE_DONE) {
+ walk->zlock = WALK_AXISLOCK_STATE_ACTIVE;
+ walk->zlock_momentum = 0.0f;
+ }
+ break;
}
}
}
@@ -982,12 +1007,14 @@ static float getVelocityZeroTime(const float gravity, const float velocity)
static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
{
-#define WALK_ROTATE_RELATIVE_FAC 2.2f /* More is faster, relative to region size. */
-#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* More is faster, radians per-pixel. */
+#define WALK_ROTATE_TABLET_FAC 8.8f /* Higher is faster, relative to region size. */
+#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* Higher is faster, radians per-pixel. */
#define WALK_TOP_LIMIT DEG2RADF(85.0f)
#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
#define WALK_MOVE_SPEED base_speed
#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
+#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */
+#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */
RegionView3D *rv3d = walk->rv3d;
ARegion *region = walk->region;
@@ -1022,20 +1049,25 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* Should we redraw? */
if ((walk->active_directions) || moffset[0] || moffset[1] ||
- walk->teleport.state == WALK_TELEPORT_STATE_ON ||
- walk->gravity_state != WALK_GRAVITY_STATE_OFF || is_confirm) {
+ walk->zlock == WALK_AXISLOCK_STATE_ACTIVE ||
+ walk->gravity_state != WALK_GRAVITY_STATE_OFF ||
+ walk->teleport.state == WALK_TELEPORT_STATE_ON || is_confirm) {
float dvec_tmp[3];
/* time how fast it takes for us to redraw,
* this is so simple scenes don't walk too fast */
double time_current;
float time_redraw;
+ float time_redraw_clamped;
#ifdef NDOF_WALK_DRAW_TOOMUCH
walk->redraw = 1;
#endif
time_current = PIL_check_seconds_timer();
time_redraw = (float)(time_current - walk->time_lastdraw);
+ /* Clamp redraw time to avoid jitter in roll correction. */
+ time_redraw_clamped = min_ff(0.05f, time_redraw);
+
walk->time_lastdraw = time_current;
/* base speed in m/s */
@@ -1064,7 +1096,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
y /= region->winy;
- y *= WALK_ROTATE_RELATIVE_FAC;
+ y *= WALK_ROTATE_TABLET_FAC;
}
else
#endif
@@ -1113,7 +1145,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
x /= region->winx;
- x *= WALK_ROTATE_RELATIVE_FAC;
+ x *= WALK_ROTATE_TABLET_FAC;
}
else
#endif
@@ -1128,6 +1160,32 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
axis_angle_to_quat_single(tmp_quat, 'Z', x);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
}
+
+ if (walk->zlock == WALK_AXISLOCK_STATE_ACTIVE) {
+ float upvec[3];
+ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
+ mul_m3_v3(mat, upvec);
+
+ /* Make sure we have some z rolling. */
+ if (fabsf(upvec[2]) > 0.00001f) {
+ float roll = upvec[2] * 5.0f;
+ /* Rotate the view about this axis. */
+ copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
+ mul_m3_v3(mat, upvec);
+ /* Rotate about the relative up vec. */
+ axis_angle_to_quat(tmp_quat,
+ upvec,
+ roll * time_redraw_clamped * walk->zlock_momentum *
+ WALK_ZUP_CORRECT_FAC);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+ walk->zlock_momentum += WALK_ZUP_CORRECT_ACCEL;
+ }
+ else {
+ /* Lock fixed, don't need to check it ever again. */
+ walk->zlock = WALK_AXISLOCK_STATE_DONE;
+ }
+ }
}
/* WASD - 'move' translation code */
@@ -1318,7 +1376,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
add_v3_v3(rv3d->ofs, dvec_tmp);
if (rv3d->persp == RV3D_CAMOB) {
- walk->need_rotation_keyframe |= (moffset[0] || moffset[1]);
+ walk->need_rotation_keyframe |= (moffset[0] || moffset[1] ||
+ walk->zlock == WALK_AXISLOCK_STATE_ACTIVE);
walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
walkMoveCamera(
C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
@@ -1333,7 +1392,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
}
return OPERATOR_FINISHED;
-#undef WALK_ROTATE_RELATIVE_FAC
+#undef WALK_ROTATE_TABLET_FAC
#undef WALK_TOP_LIMIT
#undef WALK_BOTTOM_LIMIT
#undef WALK_MOVE_SPEED
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index a19e92f229a..4482e5897ca 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -511,47 +511,47 @@ static int snap_selected_to_location(bContext *C,
for (int ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
+ if (ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) {
+ continue;
+ }
- if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) {
-
- float cursor_parent[3]; /* parent-relative */
-
- if (use_offset) {
- add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
- }
- else {
- copy_v3_v3(cursor_parent, snap_target_global);
- }
+ float cursor_parent[3]; /* parent-relative */
- sub_v3_v3(cursor_parent, ob->obmat[3]);
+ if (use_offset) {
+ add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
+ }
+ else {
+ copy_v3_v3(cursor_parent, snap_target_global);
+ }
- if (ob->parent) {
- float originmat[3][3], parentmat[4][4];
- /* Use the evaluated object here because sometimes
- * `ob->parent->runtime.curve_cache` is required. */
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ sub_v3_v3(cursor_parent, ob->obmat[3]);
- BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
- mul_m3_m4m4(originmat, parentmat, ob->parentinv);
- invert_m3_m3(imat, originmat);
- mul_m3_v3(imat, cursor_parent);
- }
- if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
- ob->loc[0] += cursor_parent[0];
- }
- if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
- ob->loc[1] += cursor_parent[1];
- }
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
- ob->loc[2] += cursor_parent[2];
- }
+ if (ob->parent) {
+ float originmat[3][3], parentmat[4][4];
+ /* Use the evaluated object here because sometimes
+ * `ob->parent->runtime.curve_cache` is required. */
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
+ mul_m3_m4m4(originmat, parentmat, ob->parentinv);
+ invert_m3_m3(imat, originmat);
+ mul_m3_v3(imat, cursor_parent);
+ }
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] += cursor_parent[0];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] += cursor_parent[1];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] += cursor_parent[2];
+ }
- /* auto-keyframing */
- ED_autokeyframe_object(C, scene, ob, ks);
+ /* auto-keyframing */
+ ED_autokeyframe_object(C, scene, ob, ks);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- }
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
if (objects) {
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index c1ee6edfef6..383f9870714 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -2067,6 +2067,27 @@ static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc)
}
}
+static bool tc_mesh_is_deform_only_update(TransInfo *t, TransDataContainer *tc)
+{
+ if (tc->custom.type.data &&
+ ((struct TransCustomDataMesh *)tc->custom.type.data)->cd_layer_correct) {
+ return false;
+ }
+
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(t->depsgraph, (ID *)tc->obedit->data);
+ Mesh *mesh_eval_cage = me_eval->edit_mesh->mesh_eval_cage;
+ Mesh *mesh_eval_final = me_eval->edit_mesh->mesh_eval_final;
+ if (mesh_eval_cage && !mesh_eval_cage->runtime.is_original) {
+ return false;
+ }
+ if (mesh_eval_final && mesh_eval_final != mesh_eval_cage &&
+ !mesh_eval_final->runtime.is_original) {
+ return false;
+ }
+
+ return me_eval->runtime.deformed_only;
+}
+
void recalcData_mesh(TransInfo *t)
{
bool is_canceling = t->state == TRANS_CANCEL;
@@ -2094,7 +2115,10 @@ void recalcData_mesh(TransInfo *t)
tc_mesh_partial_types_calc(t, &partial_state);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
+ const bool is_deform_only = tc_mesh_is_deform_only_update(t, tc);
+
+ DEG_id_tag_update(tc->obedit->data,
+ is_deform_only ? ID_RECALC_GEOMETRY_DEFORM : ID_RECALC_GEOMETRY);
tc_mesh_partial_update(t, tc, &partial_state);
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 3b1191a3401..2db3e259153 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -28,6 +28,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index d91a2a8be4b..61397b6ef4b 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -30,6 +30,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh_mapping.h"
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index c217478bd04..ee6cb391fdc 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -153,7 +153,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
float rot[3][3], scale[3];
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
/* only use rigid body transform if simulation is running,
* avoids problems with initial setup of rigid bodies */
@@ -978,7 +978,7 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
/* restore rigid body transform */
if (ob->rigidbody_object && canceled) {
- float ctime = BKE_scene_frame_get(t->scene);
+ float ctime = BKE_scene_ctime_get(t->scene);
if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
BKE_rigidbody_aftertrans_update(ob,
td->ext->oloc,
diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
index fe853440c96..a8f7fc43b5e 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -129,7 +129,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
transform_convert_sequencer_channel_clamp(t, values_final);
if (t->con.mode & CON_APPLY) {
- t->con.applyVec(t, NULL, NULL, t->values, values_final);
+ t->con.applyVec(t, NULL, NULL, values_final, values_final);
}
}
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index d9395e5e960..d0b730383d5 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -236,6 +236,11 @@ void transform_snap_sequencer_data_free(TransSeqSnapData *data)
bool transform_snap_sequencer_calc(TransInfo *t)
{
+ /* Prevent snapping when constrained to Y axis. */
+ if (t->con.mode & CON_APPLY && t->con.mode & CON_AXIS1) {
+ return false;
+ }
+
const TransSeqSnapData *snap_data = t->tsnap.seq_context;
int best_dist = MAXFRAME, best_target_frame = 0, best_source_frame = 0;
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index 93948b5ae1b..56bcbc63de1 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 9593a1364e7..fcc44aab583 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -205,11 +205,18 @@ static void bakeModifier(Main *UNUSED(bmain),
}
if (!gpd->runtime.lineart_cache) {
+ /* Only calculate for this modifier, thus no need to get maximum values from all line art
+ * modifiers in the stack. */
+ lmd->edge_types_override = lmd->edge_types;
+ lmd->level_end_override = lmd->level_end;
+
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_clear_cache(&gpd->runtime.lineart_cache);
}
static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
@@ -331,7 +338,7 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
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_cached_result");
+ 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);
uiLayoutSetEnabled(layout, !is_baked);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 3f722f33946..9899d889c56 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1696,7 +1696,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
}
if (rb->remove_doubles) {
- BMEditMesh *em = BKE_editmesh_create(bm, false);
+ BMEditMesh *em = BKE_editmesh_create(bm);
BMOperator findop, weldop;
/* See bmesh_opdefines.c and bmesh_operators.c for op names and argument formatting. */
@@ -4217,9 +4217,6 @@ static void lineart_gpencil_generate(LineartCache *cache,
/* (!orig_col && !orig_ob) means the whole scene is selected. */
- float mat[4][4];
- unit_m4(mat);
-
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;
@@ -4271,29 +4268,20 @@ static void lineart_gpencil_generate(LineartCache *cache,
/* Preserved: If we ever do asynchronous generation, this picked flag should be set here. */
// ec->picked = 1;
- int array_idx = 0;
- int count = MOD_lineart_chain_count(ec);
+ const int count = MOD_lineart_chain_count(ec);
bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, color_idx, count, thickness, false);
- float *stroke_data = MEM_callocN(sizeof(float) * count * GP_PRIM_DATABUF_SIZE,
- "line art add stroke");
-
- LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
- stroke_data[array_idx] = eci->gpos[0];
- stroke_data[array_idx + 1] = eci->gpos[1];
- stroke_data[array_idx + 2] = eci->gpos[2];
- mul_m4_v3(gp_obmat_inverse, &stroke_data[array_idx]);
- stroke_data[array_idx + 3] = 1; /* thickness. */
- stroke_data[array_idx + 4] = opacity; /* hardness?. */
- array_idx += 5;
+ int i;
+ LISTBASE_FOREACH_INDEX (LineartEdgeChainItem *, eci, &ec->chain, i) {
+ bGPDspoint *point = &gps->points[i];
+ mul_v3_m4v3(&point->x, gp_obmat_inverse, eci->gpos);
+ point->pressure = 1.0f;
+ point->strength = opacity;
}
- BKE_gpencil_stroke_add_points(gps, stroke_data, count, mat);
BKE_gpencil_dvert_ensure(gps);
gps->mat_nr = max_ii(material_nr, 0);
- MEM_freeN(stroke_data);
-
if (source_vgname && vgname) {
Object *eval_ob = DEG_get_evaluated_object(depsgraph, ec->object_ref);
int gpdg = -1;
@@ -4302,7 +4290,7 @@ static void lineart_gpencil_generate(LineartCache *cache,
int dindex = 0;
Mesh *me = (Mesh *)eval_ob->data;
if (me->dvert) {
- LISTBASE_FOREACH (bDeformGroup *, db, &eval_ob->defbase) {
+ LISTBASE_FOREACH (bDeformGroup *, db, &me->vertex_group_names) {
if ((!source_vgname) || strstr(db->name, source_vgname) == db->name) {
if (match_output) {
gpdg = BKE_object_defgroup_name_index(gpencil_object, db->name);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index abb7330d292..b7dc3210c41 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -82,8 +82,8 @@ set(SRC
intern/gpu_select_sample_query.cc
intern/gpu_shader.cc
intern/gpu_shader_builtin.c
- intern/gpu_shader_log.cc
intern/gpu_shader_interface.cc
+ intern/gpu_shader_log.cc
intern/gpu_state.cc
intern/gpu_texture.cc
intern/gpu_uniform_buffer.cc
@@ -103,8 +103,8 @@ set(SRC
opengl/gl_index_buffer.cc
opengl/gl_query.cc
opengl/gl_shader.cc
- opengl/gl_shader_log.cc
opengl/gl_shader_interface.cc
+ opengl/gl_shader_log.cc
opengl/gl_state.cc
opengl/gl_texture.cc
opengl/gl_uniform_buffer.cc
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index ad72f373d12..70bb70ec4fa 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -395,9 +395,8 @@ bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
}
}
}
- if (ofile) {
- fflush(ofile);
- fclose(ofile);
- }
+
+ fflush(ofile);
+ fclose(ofile);
return 1;
}
diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp
index 6f0d422dbe2..e61ed47adee 100644
--- a/source/blender/io/collada/ControllerExporter.cpp
+++ b/source/blender/io/collada/ControllerExporter.cpp
@@ -29,6 +29,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
@@ -194,9 +195,9 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
add_bind_shape_mat(ob);
- std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
- std::string inv_bind_mat_source_id = add_inv_bind_mats_source(
- ob_arm, &ob->defbase, controller_id);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ std::string joints_source_id = add_joints_source(ob_arm, defbase, controller_id);
+ std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, defbase, controller_id);
std::list<int> vcounts;
std::list<int> joints;
@@ -207,9 +208,9 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
/* def group index -> joint index */
std::vector<int> joint_index_by_def_index;
- bDeformGroup *def;
+ const bDeformGroup *def;
- for (def = (bDeformGroup *)ob->defbase.first, i = 0, j = 0; def; def = def->next, i++) {
+ for (def = (const bDeformGroup *)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
if (is_bone_defgroup(ob_arm, def)) {
joint_index_by_def_index.push_back(j++);
}
@@ -269,7 +270,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
}
std::string weights_source_id = add_weights_source(me, controller_id, weights);
- add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
+ add_joints_element(defbase, joints_source_id, inv_bind_mat_source_id);
add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
BKE_id_free(nullptr, me);
@@ -392,7 +393,7 @@ void ControllerExporter::add_weight_extras(Key *key)
}
}
-void ControllerExporter::add_joints_element(ListBase *defbase,
+void ControllerExporter::add_joints_element(const ListBase *defbase,
const std::string &joints_source_id,
const std::string &inv_bind_mat_source_id)
{
@@ -431,7 +432,7 @@ void ControllerExporter::add_bind_shape_mat(Object *ob)
}
std::string ControllerExporter::add_joints_source(Object *ob_arm,
- ListBase *defbase,
+ const ListBase *defbase,
const std::string &controller_id)
{
std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
@@ -468,7 +469,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm,
}
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm,
- ListBase *defbase,
+ const ListBase *defbase,
const std::string &controller_id)
{
std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
@@ -568,13 +569,13 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm,
return source_id;
}
-Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def)
+Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, def->name);
return pchan ? pchan->bone : nullptr;
}
-bool ControllerExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup *def)
+bool ControllerExporter::is_bone_defgroup(Object *ob_arm, const bDeformGroup *def)
{
return get_bone_from_defgroup(ob_arm, def) != nullptr;
}
diff --git a/source/blender/io/collada/ControllerExporter.h b/source/blender/io/collada/ControllerExporter.h
index 6a377a4119e..0aec9e8d179 100644
--- a/source/blender/io/collada/ControllerExporter.h
+++ b/source/blender/io/collada/ControllerExporter.h
@@ -97,7 +97,7 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
void export_morph_controller(Object *ob, Key *key);
- void add_joints_element(ListBase *defbase,
+ void add_joints_element(const ListBase *defbase,
const std::string &joints_source_id,
const std::string &inv_bind_mat_source_id);
@@ -110,16 +110,16 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
void add_weight_extras(Key *key);
std::string add_joints_source(Object *ob_arm,
- ListBase *defbase,
+ const ListBase *defbase,
const std::string &controller_id);
std::string add_inv_bind_mats_source(Object *ob_arm,
- ListBase *defbase,
+ const ListBase *defbase,
const std::string &controller_id);
- Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup *def);
+ Bone *get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def);
- bool is_bone_defgroup(Object *ob_arm, bDeformGroup *def);
+ bool is_bone_defgroup(Object *ob_arm, const bDeformGroup *def);
std::string add_weights_source(Mesh *me,
const std::string &controller_id,
diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp
index c2f17174d75..f0e1c5e4c26 100644
--- a/source/blender/io/collada/SkinInfo.cpp
+++ b/source/blender/io/collada/SkinInfo.cpp
@@ -36,6 +36,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
+#include "BKE_deform.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
@@ -289,7 +290,8 @@ void SkinInfo::link_armature(bContext *C,
/* -1 means "weight towards the bind shape", we just don't assign it to any group */
if (joint != -1) {
- bDeformGroup *def = (bDeformGroup *)BLI_findlink(&ob->defbase, joint);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *def = (bDeformGroup *)BLI_findlink(defbase, joint);
ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE);
}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index c9d652ad03d..43969bf0768 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -621,9 +621,9 @@ typedef enum IDRecalcFlag {
* When a collection gets tagged with this flag, all objects depending on the geometry and
* transforms on any of the objects in the collection are updated. */
ID_RECALC_GEOMETRY = (1 << 1),
-
- /* ** Animation or time changed and animation is to be re-evaluated. ** */
- ID_RECALC_ANIMATION = (1 << 2),
+ /* Same as #ID_RECALC_GEOMETRY, but instead of tagging the batch cache as `dirty_all`, just tags
+ what matches the deform cache. */
+ ID_RECALC_GEOMETRY_DEFORM = (1 << 2),
/* ** Particle system changed. ** */
/* Only do pathcache etc. */
@@ -683,6 +683,9 @@ typedef enum IDRecalcFlag {
* have to be copied on every update. */
ID_RECALC_PARAMETERS = (1 << 21),
+ /* ** Animation or time changed and animation is to be re-evaluated. ** */
+ ID_RECALC_ANIMATION = (1 << 22),
+
/* Input has changed and datablock is to be reload from disk.
* Applies to movie clips to inform that copy-on-written version is to be refreshed for the new
* input file or for color space changes. */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index c573de6b54e..0952c45e81f 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -666,6 +666,9 @@ typedef struct bGPdata {
/** List of bGPDpalette's - Deprecated (2.78 - 2.79 only). */
ListBase palettes DNA_DEPRECATED;
+ /** List of bDeformGroup names and flag only. */
+ ListBase vertex_group_names;
+
/* 3D Viewport/Appearance Settings */
/** Factor to define pixel size conversion. */
float pixfactor;
@@ -715,7 +718,8 @@ typedef struct bGPdata {
/** Stroke selection last index. Used to generate a unique selection index. */
int select_last_index;
- char _pad3[4];
+
+ int vertex_group_active_index;
bGPgrid grid;
diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h
index 48eb8d90702..361893db893 100644
--- a/source/blender/makesdna/DNA_lattice_types.h
+++ b/source/blender/makesdna/DNA_lattice_types.h
@@ -72,6 +72,11 @@ typedef struct Lattice {
struct MDeformVert *dvert;
/** Multiply the influence, MAX_VGROUP_NAME. */
char vgroup[64];
+ /** List of bDeformGroup names and flag only. */
+ ListBase vertex_group_names;
+ int vertex_group_active_index;
+
+ char _pad0[4];
struct EditLatt *editlatt;
void *batch_cache;
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 2f089b28048..2a569c8db50 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -166,6 +166,8 @@ typedef struct Mesh {
struct MEdge *medge;
/** Deform-group vertices. */
struct MDeformVert *dvert;
+ /** List of bDeformGroup names and flag only. */
+ ListBase vertex_group_names;
/* array of colors for the tessellated faces, must be number of tessellated
* faces * 4 in length */
@@ -189,7 +191,7 @@ typedef struct Mesh {
/* END BMESH ONLY */
int attributes_active_index;
- int _pad3;
+ int vertex_group_active_index;
/* the last selected vertex/edge/face are used for the active face however
* this means the active face must always be selected, this is to keep track
@@ -279,9 +281,9 @@ enum {
/* 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) ? \
- SCE_SELECT_FACE : \
- ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : 0)
+ (((_me)->editflag & ME_EDIT_PAINT_FACE_SEL) ? SCE_SELECT_FACE : \
+ ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \
+ 0)
/* me->flag */
enum {
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 08a38f0652c..1c765d19ce2 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2256,6 +2256,10 @@ typedef struct NodesModifierData {
ModifierData modifier;
struct bNodeTree *node_group;
struct NodesModifierSettings settings;
+
+ /* Contains logged information from the last evaluation. This can be used to help the user to
+ * debug a node tree. */
+ void *runtime_eval_log;
} NodesModifierData;
typedef struct MeshToVolumeModifierData {
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 9af77949fe2..1f75006bd07 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -37,7 +37,6 @@ struct Collection;
struct ID;
struct Image;
struct ListBase;
-struct NodeTreeUIStorage;
struct bGPdata;
struct bNodeInstanceHash;
struct bNodeLink;
@@ -516,8 +515,6 @@ typedef struct bNodeTree {
int (*test_break)(void *);
void (*update_draw)(void *);
void *tbh, *prh, *sdh, *udh;
-
- struct NodeTreeUIStorage *ui_storage;
} bNodeTree;
/* ntree->type, index */
@@ -1373,6 +1370,11 @@ typedef struct NodeGeometryCurvePrimitiveCircle {
uint8_t mode;
} NodeGeometryCurvePrimitiveCircle;
+typedef struct NodeGeometryCurvePrimitiveQuad {
+ /* GeometryNodeCurvePrimitiveQuadMode. */
+ uint8_t mode;
+} NodeGeometryCurvePrimitiveQuad;
+
typedef struct NodeGeometryCurveResample {
/* GeometryNodeCurveResampleMode. */
uint8_t mode;
@@ -1928,6 +1930,14 @@ typedef enum GeometryNodeCurvePrimitiveLineMode {
GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION = 1
} GeometryNodeCurvePrimitiveLineMode;
+typedef enum GeometryNodeCurvePrimitiveQuadMode {
+ GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE = 0,
+ GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM = 1,
+ GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID = 2,
+ GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE = 3,
+ GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS = 4,
+} GeometryNodeCurvePrimitiveQuadMode;
+
typedef enum GeometryNodeCurvePrimitiveBezierSegmentMode {
GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION = 0,
GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_OFFSET = 1,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 262d650c1ef..dd31e85647d 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -172,12 +172,6 @@ typedef struct Object_Runtime {
struct GeometrySet *geometry_set_eval;
/**
- * A GHash that contains geometry sets for intermediate stages of evaluation. The keys are just a
- * hash and are not owned by the map. The geometry sets are owned.
- */
- void *geometry_set_previews;
-
- /**
* Mesh structure created during object evaluation.
* It has deformation only modifiers applied on it.
*/
@@ -278,8 +272,7 @@ typedef struct Object {
ListBase constraintChannels DNA_DEPRECATED; /* XXX deprecated... old animation system */
ListBase effect DNA_DEPRECATED; /* XXX deprecated... keep for readfile */
- /** List of bDeformGroup (vertex groups) names and flag only. */
- ListBase defbase;
+ ListBase defbase DNA_DEPRECATED; /* Only for versioning, moved to object data. */
/** List of ModifierData structures. */
ListBase modifiers;
/** List of GpencilModifierData structures. */
@@ -381,7 +374,7 @@ typedef struct Object {
/** Custom index, for renderpasses. */
short index;
/** Current deformation group, NOTE: index starts at 1. */
- unsigned short actdef;
+ unsigned short actdef DNA_DEPRECATED;
/** Current face map, NOTE: index starts at 1. */
unsigned short actfmap;
char _pad2[2];
diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h
index 669c8500677..7de0bb29c46 100644
--- a/source/blender/makesdna/DNA_pointcache_types.h
+++ b/source/blender/makesdna/DNA_pointcache_types.h
@@ -131,32 +131,34 @@ typedef struct PointCache {
void (*free_edit)(struct PTCacheEdit *edit);
} PointCache;
-/* pointcache->flag */
-#define PTCACHE_BAKED (1 << 0)
-#define PTCACHE_OUTDATED (1 << 1)
-#define PTCACHE_SIMULATION_VALID (1 << 2)
-#define PTCACHE_BAKING (1 << 3)
-//#define PTCACHE_BAKE_EDIT (1 << 4)
-//#define PTCACHE_BAKE_EDIT_ACTIVE (1 << 5)
-#define PTCACHE_DISK_CACHE (1 << 6)
-///* removed since 2.64 - T30974, could be added back in a more useful way */
-//#define PTCACHE_QUICK_CACHE (1 << 7)
-#define PTCACHE_FRAMES_SKIPPED (1 << 8)
-#define PTCACHE_EXTERNAL (1 << 9)
-#define PTCACHE_READ_INFO (1 << 10)
-/** Don't use the filename of the blend-file the data is linked from (write a local cache). */
-#define PTCACHE_IGNORE_LIBPATH (1 << 11)
-/**
- * High resolution cache is saved for smoke for backwards compatibility,
- * so set this flag to know it's a "fake" cache.
- */
-#define PTCACHE_FAKE_SMOKE (1 << 12)
-#define PTCACHE_IGNORE_CLEAR (1 << 13)
+enum {
+ /* pointcache->flag */
+ PTCACHE_BAKED = 1 << 0,
+ PTCACHE_OUTDATED = 1 << 1,
+ PTCACHE_SIMULATION_VALID = 1 << 2,
+ PTCACHE_BAKING = 1 << 3,
+ // PTCACHE_BAKE_EDIT = 1 << 4,
+ // PTCACHE_BAKE_EDIT_ACTIVE = 1 << 5,
+ PTCACHE_DISK_CACHE = 1 << 6,
+ /* removed since 2.64 - T30974, could be added back in a more useful way */
+ // PTCACHE_QUICK_CACHE = 1 << 7,
+ PTCACHE_FRAMES_SKIPPED = 1 << 8,
+ PTCACHE_EXTERNAL = 1 << 9,
+ PTCACHE_READ_INFO = 1 << 10,
+ /** Don't use the filename of the blend-file the data is linked from (write a local cache). */
+ PTCACHE_IGNORE_LIBPATH = 1 << 11,
+ /**
+ * High resolution cache is saved for smoke for backwards compatibility,
+ * so set this flag to know it's a "fake" cache.
+ */
+ PTCACHE_FAKE_SMOKE = 1 << 12,
+ PTCACHE_IGNORE_CLEAR = 1 << 13,
-#define PTCACHE_FLAG_INFO_DIRTY (1 << 14)
+ PTCACHE_FLAG_INFO_DIRTY = 1 << 14,
-/* PTCACHE_OUTDATED + PTCACHE_FRAMES_SKIPPED */
-#define PTCACHE_REDO_NEEDED 258
+ PTCACHE_REDO_NEEDED = PTCACHE_OUTDATED | PTCACHE_FRAMES_SKIPPED,
+ PTCACHE_FLAGS_COPY = PTCACHE_DISK_CACHE | PTCACHE_EXTERNAL | PTCACHE_IGNORE_LIBPATH,
+};
#define PTCACHE_COMPRESS_NO 0
#define PTCACHE_COMPRESS_LZO 1
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 557343f79cd..73a44ec16bb 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -727,6 +727,12 @@ typedef struct FileSelectParams {
char renamefile[256];
short rename_flag;
+ char _pad[4];
+ /** An ID that was just renamed. Used to identify a renamed asset file over re-reads, similar to
+ * `renamefile` but for local IDs (takes precedence). Don't keep this stored across handlers!
+ * Would break on undo. */
+ const ID *rename_id;
+ void *_pad3;
/** List of filetypes to filter (FILE_MAXFILE). */
char filter_glob[256];
@@ -734,7 +740,6 @@ typedef struct FileSelectParams {
/** Text items name must match to be shown. */
char filter_search[64];
/** Same as filter, but for ID types (aka library groups). */
- int _pad0;
uint64_t filter_id;
/** Active file used for keyboard navigation. */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 782d0924d21..299f96a4c46 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -811,6 +811,7 @@ void RNA_struct_py_type_set(StructRNA *srna, void *py_type);
void *RNA_struct_blender_type_get(StructRNA *srna);
void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type);
+struct IDProperty **RNA_struct_idprops_p(PointerRNA *ptr);
struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 499b5538ad8..38b00afdc8f 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -493,9 +493,10 @@ StructRNA *rna_ID_refine(PointerRNA *ptr)
return ID_code_to_RNA_type(GS(id->name));
}
-IDProperty *rna_ID_idprops(PointerRNA *ptr, bool create)
+IDProperty **rna_ID_idprops(PointerRNA *ptr)
{
- return IDP_GetProperties(ptr->data, create);
+ ID *id = (ID *)ptr->data;
+ return &id->properties;
}
void rna_ID_fake_user_set(PointerRNA *ptr, bool value)
@@ -510,9 +511,9 @@ void rna_ID_fake_user_set(PointerRNA *ptr, bool value)
}
}
-IDProperty *rna_PropertyGroup_idprops(PointerRNA *ptr, bool UNUSED(create))
+IDProperty **rna_PropertyGroup_idprops(PointerRNA *ptr)
{
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type)
@@ -772,7 +773,7 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool clear_pro
static AnimData *rna_ID_animation_data_create(ID *id, Main *bmain)
{
- AnimData *adt = BKE_animdata_add_id(id);
+ AnimData *adt = BKE_animdata_ensure_id(id);
DEG_relations_tag_update(bmain);
return adt;
}
@@ -1162,12 +1163,12 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
}
-static IDProperty *rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr, bool UNUSED(create))
+static IDProperty **rna_IDPropertyWrapPtr_idprops(PointerRNA *ptr)
{
if (ptr == NULL) {
return NULL;
}
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
static void rna_Library_version_get(PointerRNA *ptr, int *value)
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index a0a84bf4fc9..eb347987f87 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -369,15 +369,32 @@ static bool rna_idproperty_ui_set_default(PointerRNA *ptr,
return true;
}
-IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create)
+IDProperty **RNA_struct_idprops_p(PointerRNA *ptr)
{
StructRNA *type = ptr->type;
+ if (type == NULL) {
+ return NULL;
+ }
+ if (type->idproperties == NULL) {
+ return NULL;
+ }
- if (type && type->idproperties) {
- return type->idproperties(ptr, create);
+ return type->idproperties(ptr);
+}
+
+IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create)
+{
+ IDProperty **property_ptr = RNA_struct_idprops_p(ptr);
+ if (property_ptr == NULL) {
+ return NULL;
}
- return NULL;
+ if (create && *property_ptr == NULL) {
+ IDPropertyTemplate val = {0};
+ *property_ptr = IDP_New(IDP_GROUP, &val, __func__);
+ }
+
+ return *property_ptr;
}
bool RNA_struct_idprops_check(StructRNA *srna)
@@ -2026,11 +2043,9 @@ bool RNA_property_enum_item_from_value(
bool RNA_property_enum_item_from_value_gettexted(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item)
{
- bool result;
+ const bool result = RNA_property_enum_item_from_value(C, ptr, prop, value, r_item);
- result = RNA_property_enum_item_from_value(C, ptr, prop, value, r_item);
-
- if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) {
+ if (result && !(prop->flag & PROP_ENUM_NO_TRANSLATE)) {
if (BLT_translate_iface()) {
r_item->name = BLT_pgettext(prop->translation_context, r_item->name);
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 816fc68195f..c4d35140423 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -422,7 +422,9 @@ static int rna_property_override_diff(Main *bmain,
bool override_changed = false;
eRNAOverrideMatch diff_flags = flags;
- if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop)) {
+ if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop) ||
+ (!ELEM(RNA_property_type(prop_a->rawprop), PROP_POINTER, PROP_COLLECTION) &&
+ !RNA_property_editable_flag(&prop_a->ptr, prop_a->rawprop))) {
diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
}
const int diff = override_diff(bmain,
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 7114e21beff..49d02524e43 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -260,28 +260,16 @@ static char *rna_Bone_path(PointerRNA *ptr)
return BLI_sprintfN("bones[\"%s\"]", name_esc);
}
-static IDProperty *rna_Bone_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_Bone_idprops(PointerRNA *ptr)
{
Bone *bone = ptr->data;
-
- if (create && !bone->prop) {
- IDPropertyTemplate val = {0};
- bone->prop = IDP_New(IDP_GROUP, &val, "RNA_Bone ID properties");
- }
-
- return bone->prop;
+ return &bone->prop;
}
-static IDProperty *rna_EditBone_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_EditBone_idprops(PointerRNA *ptr)
{
EditBone *ebone = ptr->data;
-
- if (create && !ebone->prop) {
- IDPropertyTemplate val = {0};
- ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
- }
-
- return ebone->prop;
+ return &ebone->prop;
}
static void rna_bone_layer_set(int *layer, const bool *values)
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 1af53e95cc9..55f680c736d 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -75,16 +75,10 @@ static void rna_AssetMetaData_tag_remove(AssetMetaData *asset_data,
RNA_POINTER_INVALIDATE(tag_ptr);
}
-static IDProperty *rna_AssetMetaData_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_AssetMetaData_idprops(PointerRNA *ptr)
{
AssetMetaData *asset_data = ptr->data;
-
- if (create && !asset_data->properties) {
- IDPropertyTemplate val = {0};
- asset_data->properties = IDP_New(IDP_GROUP, &val, "RNA_AssetMetaData group");
- }
-
- return asset_data->properties;
+ return &asset_data->properties;
}
static void rna_AssetMetaData_description_get(PointerRNA *ptr, char *value)
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 0dfd7d74c25..a9d5ef089bb 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -342,8 +342,8 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- /* Effect type
- * Only used by ui to view per effect settings */
+ /* Effect type
+ * Only used by UI to view per effect settings. */
static const EnumPropertyItem prop_dynamicpaint_effecttype[] = {
{1, "SPREAD", 0, "Spread", ""},
{2, "DRIP", 0, "Drip", ""},
@@ -351,7 +351,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- /* Displacemap file format */
+ /* Displace-map file format. */
static const EnumPropertyItem prop_dynamicpaint_image_fileformat[] = {
{MOD_DPAINT_IMGFORMAT_PNG, "PNG", 0, "PNG", ""},
# ifdef WITH_OPENEXR
@@ -360,7 +360,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- /* Displacemap type */
+ /* Displace-map type. */
static const EnumPropertyItem prop_dynamicpaint_displace_type[] = {
{MOD_DPAINT_DISP_DISPLACE, "DISPLACE", 0, "Displacement", ""},
{MOD_DPAINT_DISP_DEPTH, "DEPTH", 0, "Depth", ""},
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index bfe9d4bb77c..f15368bcc77 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -276,10 +276,10 @@ void rna_ID_name_get(struct PointerRNA *ptr, char *value);
int rna_ID_name_length(struct PointerRNA *ptr);
void rna_ID_name_set(struct PointerRNA *ptr, const char *value);
struct StructRNA *rna_ID_refine(struct PointerRNA *ptr);
-struct IDProperty *rna_ID_idprops(struct PointerRNA *ptr, bool create);
+struct IDProperty **rna_ID_idprops(struct PointerRNA *ptr);
void rna_ID_fake_user_set(struct PointerRNA *ptr, bool value);
void **rna_ID_instance(PointerRNA *ptr);
-struct IDProperty *rna_PropertyGroup_idprops(struct PointerRNA *ptr, bool create);
+struct IDProperty **rna_PropertyGroup_idprops(struct PointerRNA *ptr);
void rna_PropertyGroup_unregister(struct Main *bmain, struct StructRNA *type);
struct StructRNA *rna_PropertyGroup_register(struct Main *bmain,
struct ReportList *reports,
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index ee60b199d64..479306e8c06 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -54,7 +54,7 @@ typedef void (*ContextPropUpdateFunc)(struct bContext *C,
typedef void (*ContextUpdateFunc)(struct bContext *C, struct PointerRNA *ptr);
typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info);
typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index);
-typedef struct IDProperty *(*IDPropertiesFunc)(struct PointerRNA *ptr, bool create);
+typedef struct IDProperty **(*IDPropertiesFunc)(struct PointerRNA *ptr);
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
typedef char *(*StructPathFunc)(struct PointerRNA *ptr);
@@ -559,7 +559,7 @@ struct StructRNA {
*/
StructInstanceFunc instance;
- /* callback to get id properties */
+ /** Return the location of the struct's pointer to the root group IDProperty. */
IDPropertiesFunc idproperties;
/* functions of this struct */
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index b4253ab9236..0414afe1514 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -119,16 +119,10 @@ static char *rna_ViewLayer_path(PointerRNA *ptr)
return BLI_sprintfN("view_layers[\"%s\"]", name_esc);
}
-static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_ViewLayer_idprops(PointerRNA *ptr)
{
ViewLayer *view_layer = (ViewLayer *)ptr->data;
-
- if (create && !view_layer->id_properties) {
- IDPropertyTemplate val = {0};
- view_layer->id_properties = IDP_New(IDP_GROUP, &val, "ViewLayer ID properties");
- }
-
- return view_layer->id_properties;
+ return &view_layer->id_properties;
}
static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C)
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index 3fba8cdb035..9835d664a55 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -249,7 +249,7 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces");
RNA_def_function_ui_description(func, "Split faces based on the edge angle");
RNA_def_boolean(
- func, "free_loop_normals", 1, "Free Loop Notmals", "Free loop normals custom data layer");
+ func, "free_loop_normals", 1, "Free Loop Normals", "Free loop normals custom data layer");
func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 7def9bdb636..e64eaf8c363 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -602,6 +602,7 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
# include "BKE_cachefile.h"
# include "BKE_context.h"
+# include "BKE_deform.h"
# include "BKE_mesh_runtime.h"
# include "BKE_modifier.h"
# include "BKE_object.h"
@@ -1250,12 +1251,13 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
# endif
if (ob_src) {
- bDeformGroup *dg;
+ const bDeformGroup *dg;
int i;
RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob_src);
+ for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
tmp_item.value = i;
tmp_item.identifier = tmp_item.name = dg->name;
RNA_enum_item_add(&item, &totitem, &tmp_item);
@@ -1349,12 +1351,13 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(
Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */
if (ob_dst) {
- bDeformGroup *dg;
+ const bDeformGroup *dg;
int i;
RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0, dg = ob_dst->defbase.first; dg; i++, dg = dg->next) {
+ const ListBase *defbase = BKE_object_defgroup_list(ob_dst);
+ for (i = 0, dg = defbase->first; dg; i++, dg = dg->next) {
tmp_item.value = i;
tmp_item.identifier = tmp_item.name = dg->name;
RNA_enum_item_add(&item, &totitem, &tmp_item);
@@ -1618,15 +1621,11 @@ static void rna_NodesModifier_node_group_update(Main *bmain, Scene *scene, Point
MOD_nodes_update_interface(object, nmd);
}
-static IDProperty *rna_NodesModifier_properties(PointerRNA *ptr, bool create)
+static IDProperty **rna_NodesModifier_properties(PointerRNA *ptr)
{
NodesModifierData *nmd = ptr->data;
NodesModifierSettings *settings = &nmd->settings;
- if (create && settings->properties == NULL) {
- IDPropertyTemplate val = {0};
- settings->properties = IDP_New(IDP_GROUP, &val, "Nodes Modifier Settings");
- }
- return settings->properties;
+ return &settings->properties;
}
#else
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 978ea13f92f..582bc40a142 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2366,16 +2366,10 @@ static StructRNA *rna_FunctionNode_register(Main *bmain,
return nt->rna_ext.srna;
}
-static IDProperty *rna_Node_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_Node_idprops(PointerRNA *ptr)
{
bNode *node = ptr->data;
-
- if (create && !node->prop) {
- IDPropertyTemplate val = {0};
- node->prop = IDP_New(IDP_GROUP, &val, "RNA_Node ID properties");
- }
-
- return node->prop;
+ return &node->prop;
}
static void rna_Node_parent_set(PointerRNA *ptr,
@@ -2834,16 +2828,10 @@ static char *rna_NodeSocket_path(PointerRNA *ptr)
}
}
-static IDProperty *rna_NodeSocket_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_NodeSocket_idprops(PointerRNA *ptr)
{
bNodeSocket *sock = ptr->data;
-
- if (create && !sock->prop) {
- IDPropertyTemplate val = {0};
- sock->prop = IDP_New(IDP_GROUP, &val, "RNA_NodeSocket ID properties");
- }
-
- return sock->prop;
+ return &sock->prop;
}
static PointerRNA rna_NodeSocket_node_get(PointerRNA *ptr)
@@ -3150,16 +3138,10 @@ static char *rna_NodeSocketInterface_path(PointerRNA *ptr)
return NULL;
}
-static IDProperty *rna_NodeSocketInterface_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_NodeSocketInterface_idprops(PointerRNA *ptr)
{
bNodeSocket *sock = ptr->data;
-
- if (create && !sock->prop) {
- IDPropertyTemplate val = {0};
- sock->prop = IDP_New(IDP_GROUP, &val, "RNA_NodeSocketInterface ID properties");
- }
-
- return sock->prop;
+ return &sock->prop;
}
static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -3205,7 +3187,7 @@ static void rna_NodeSocketInterfaceStandard_draw(ID *id,
struct uiLayout *layout)
{
PointerRNA ptr;
- RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr);
+ RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr);
sock->typeinfo->interface_draw(C, layout, &ptr);
}
@@ -3215,7 +3197,7 @@ static void rna_NodeSocketInterfaceStandard_draw_color(ID *id,
float r_color[4])
{
PointerRNA ptr;
- RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr);
+ RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr);
sock->typeinfo->interface_draw_color(C, &ptr, r_color);
}
@@ -9947,6 +9929,45 @@ static void def_geo_switch(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_primitive_quadrilateral(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mode_items[] = {
+ {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE,
+ "RECTANGLE",
+ 0,
+ "Rectangle",
+ "Create a rectangle"},
+ {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM,
+ "PARALLELOGRAM",
+ 0,
+ "Parallelogram",
+ "Create a parallelogram"},
+ {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID,
+ "TRAPEZOID",
+ 0,
+ "Trapezoid",
+ "Create a trapezoid"},
+ {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE, "KITE", 0, "Kite", "Create a Kite / Dart"},
+ {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS,
+ "POINTS",
+ 0,
+ "Points",
+ "Create a quadrilateral from four points"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveQuad", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_resample(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 7c012922c2c..e110459eeea 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -790,9 +790,27 @@ static void rna_Object_dup_collection_set(PointerRNA *ptr,
}
}
+static void rna_Object_vertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->data;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ iter->valid = 0;
+ return;
+ }
+
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+ iter->valid = defbase != NULL;
+
+ rna_iterator_listbase_begin(iter, defbase, NULL);
+}
+
static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = (Object *)ptr->owner_id;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return;
+ }
+
bDeformGroup *dg = (bDeformGroup *)ptr->data;
BLI_strncpy_utf8(dg->name, value, sizeof(dg->name));
BKE_object_defgroup_unique_name(dg, ob);
@@ -801,15 +819,25 @@ static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value)
static int rna_VertexGroup_index_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return -1;
+ }
- return BLI_findindex(&ob->defbase, ptr->data);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ return BLI_findindex(defbase, ptr->data);
}
static PointerRNA rna_Object_active_vertex_group_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return PointerRNA_NULL;
+ }
+
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
return rna_pointer_inherit_refine(
- ptr, &RNA_VertexGroup, BLI_findlink(&ob->defbase, ob->actdef - 1));
+ ptr, &RNA_VertexGroup, BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1));
}
static void rna_Object_active_vertex_group_set(PointerRNA *ptr,
@@ -817,7 +845,13 @@ static void rna_Object_active_vertex_group_set(PointerRNA *ptr,
struct ReportList *reports)
{
Object *ob = (Object *)ptr->owner_id;
- int index = BLI_findindex(&ob->defbase, value.data);
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return;
+ }
+
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+
+ int index = BLI_findindex(defbase, value.data);
if (index == -1) {
BKE_reportf(reports,
RPT_ERROR,
@@ -827,19 +861,27 @@ static void rna_Object_active_vertex_group_set(PointerRNA *ptr,
return;
}
- ob->actdef = index + 1;
+ BKE_object_defgroup_active_index_set(ob, index + 1);
}
static int rna_Object_active_vertex_group_index_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- return ob->actdef - 1;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return -1;
+ }
+
+ return BKE_object_defgroup_active_index_get(ob) - 1;
}
static void rna_Object_active_vertex_group_index_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->owner_id;
- ob->actdef = value + 1;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return;
+ }
+
+ BKE_object_defgroup_active_index_set(ob, value + 1);
}
static void rna_Object_active_vertex_group_index_range(
@@ -848,15 +890,24 @@ static void rna_Object_active_vertex_group_index_range(
Object *ob = (Object *)ptr->owner_id;
*min = 0;
- *max = max_ii(0, BLI_listbase_count(&ob->defbase) - 1);
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ *max = 0;
+ return;
+ }
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ *max = max_ii(0, BLI_listbase_count(defbase) - 1);
}
void rna_object_vgroup_name_index_get(PointerRNA *ptr, char *value, int index)
{
Object *ob = (Object *)ptr->owner_id;
- bDeformGroup *dg;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ value[0] = '\0';
+ return;
+ }
- dg = BLI_findlink(&ob->defbase, index - 1);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ const bDeformGroup *dg = BLI_findlink(defbase, index - 1);
if (dg) {
BLI_strncpy(value, dg->name, sizeof(dg->name));
@@ -869,21 +920,34 @@ void rna_object_vgroup_name_index_get(PointerRNA *ptr, char *value, int index)
int rna_object_vgroup_name_index_length(PointerRNA *ptr, int index)
{
Object *ob = (Object *)ptr->owner_id;
- bDeformGroup *dg;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ return 0;
+ }
- dg = BLI_findlink(&ob->defbase, index - 1);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *dg = BLI_findlink(defbase, index - 1);
return (dg) ? strlen(dg->name) : 0;
}
void rna_object_vgroup_name_index_set(PointerRNA *ptr, const char *value, short *index)
{
Object *ob = (Object *)ptr->owner_id;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ *index = -1;
+ return;
+ }
+
*index = BKE_object_defgroup_name_index(ob, value) + 1;
}
void rna_object_vgroup_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen)
{
Object *ob = (Object *)ptr->owner_id;
+ if (!BKE_object_supports_vertex_groups(ob)) {
+ result[0] = '\0';
+ return;
+ }
+
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, value);
if (dg) {
/* No need for BLI_strncpy_utf8, since this matches an existing group. */
@@ -1960,7 +2024,9 @@ static void rna_Object_vgroup_remove(Object *ob,
PointerRNA *defgroup_ptr)
{
bDeformGroup *defgroup = defgroup_ptr->data;
- if (BLI_findindex(&ob->defbase, defgroup) == -1) {
+ ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
+
+ if (BLI_findindex(defbase, defgroup) == -1) {
BKE_reportf(reports,
RPT_ERROR,
"DeformGroup '%s' not in object '%s'",
@@ -2687,7 +2753,6 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_int_sdna(prop, NULL, "actdef");
RNA_def_property_int_funcs(prop,
"rna_Object_active_vertex_group_index_get",
"rna_Object_active_vertex_group_index_set",
@@ -3274,7 +3339,15 @@ static void rna_def_object(BlenderRNA *brna)
/* vertex groups */
prop = RNA_def_property(srna, "vertex_groups", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "defbase", NULL);
+ RNA_def_property_collection_funcs(prop,
+ "rna_Object_vertex_groups_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_iterator_listbase_get",
+ NULL,
+ NULL,
+ NULL,
+ NULL);
RNA_def_property_struct_type(prop, "VertexGroup");
RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Vertex Groups", "Vertex groups of the object");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 8edb80f68c5..de4cfb2b61a 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1430,9 +1430,10 @@ static void psys_vg_name_get__internal(PointerRNA *ptr, char *value, int index)
{
Object *ob = (Object *)ptr->owner_id;
ParticleSystem *psys = (ParticleSystem *)ptr->data;
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
if (psys->vgroup[index] > 0) {
- bDeformGroup *defGroup = BLI_findlink(&ob->defbase, psys->vgroup[index] - 1);
+ bDeformGroup *defGroup = BLI_findlink(defbase, psys->vgroup[index] - 1);
if (defGroup) {
strcpy(value, defGroup->name);
@@ -1448,7 +1449,8 @@ static int psys_vg_name_len__internal(PointerRNA *ptr, int index)
ParticleSystem *psys = (ParticleSystem *)ptr->data;
if (psys->vgroup[index] > 0) {
- bDeformGroup *defGroup = BLI_findlink(&ob->defbase, psys->vgroup[index] - 1);
+ const ListBase *defbase = BKE_object_defgroup_list(ob);
+ bDeformGroup *defGroup = BLI_findlink(defbase, psys->vgroup[index] - 1);
if (defGroup) {
return strlen(defGroup->name);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index bb4939a010b..ee509fa92d4 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -224,16 +224,10 @@ static void rna_BoneGroup_name_set(PointerRNA *ptr, const char *value)
sizeof(agrp->name));
}
-static IDProperty *rna_PoseBone_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_PoseBone_idprops(PointerRNA *ptr)
{
bPoseChannel *pchan = ptr->data;
-
- if (create && !pchan->prop) {
- IDPropertyTemplate val = {0};
- pchan->prop = IDP_New(IDP_GROUP, &val, "RNA_PoseBone group");
- }
-
- return pchan->prop;
+ return &pchan->prop;
}
static void rna_Pose_ik_solver_set(struct PointerRNA *ptr, int value)
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 0c46450759d..b1f0b0d760f 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -199,7 +199,10 @@ static void rna_SequenceEditor_sequences_all_begin(CollectionPropertyIterator *i
bli_iter->data = MEM_callocN(sizeof(SeqIterator), __func__);
iter->internal.custom = bli_iter;
- SEQ_iterator_ensure(all_strips, bli_iter->data, (Sequence **)&bli_iter->current);
+ if (!SEQ_iterator_ensure(all_strips, bli_iter->data, (Sequence **)&bli_iter->current)) {
+ SEQ_collection_free(all_strips);
+ }
+
iter->valid = bli_iter->current != NULL;
}
@@ -220,7 +223,9 @@ static void rna_SequenceEditor_sequences_all_end(CollectionPropertyIterator *ite
{
BLI_Iterator *bli_iter = iter->internal.custom;
SeqIterator *seq_iter = bli_iter->data;
- SEQ_collection_free(seq_iter->collection);
+ if (seq_iter->collection != NULL) {
+ SEQ_collection_free(seq_iter->collection);
+ }
MEM_freeN(seq_iter);
MEM_freeN(bli_iter);
}
@@ -729,16 +734,10 @@ static char *rna_Sequence_path(PointerRNA *ptr)
}
}
-static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_Sequence_idprops(PointerRNA *ptr)
{
Sequence *seq = ptr->data;
-
- if (create && !seq->prop) {
- IDPropertyTemplate val = {0};
- seq->prop = IDP_New(IDP_GROUP, &val, "Sequence ID properties");
- }
-
- return seq->prop;
+ return &seq->prop;
}
static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 56deb873611..7366934695e 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1041,16 +1041,10 @@ static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr)
return RV3D_VIEW_IS_AXIS(rv3d->view);
}
-static IDProperty *rna_View3DShading_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_View3DShading_idprops(PointerRNA *ptr)
{
View3DShading *shading = ptr->data;
-
- if (create && !shading->prop) {
- IDPropertyTemplate val = {0};
- shading->prop = IDP_New(IDP_GROUP, &val, "View3DShading ID properties");
- }
-
- return shading->prop;
+ return &shading->prop;
}
static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -2106,7 +2100,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
switch (saction->mode) {
case SACTCONT_ACTION:
/* TODO: context selector could help decide this with more control? */
- adt = BKE_animdata_add_id(&obact->id);
+ adt = BKE_animdata_ensure_id(&obact->id);
id = &obact->id;
break;
case SACTCONT_SHAPEKEY: {
@@ -2114,7 +2108,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
if (key == NULL) {
return;
}
- adt = BKE_animdata_add_id(&key->id);
+ adt = BKE_animdata_ensure_id(&key->id);
id = &key->id;
break;
}
diff --git a/source/blender/makesrna/intern/rna_timeline.c b/source/blender/makesrna/intern/rna_timeline.c
index c0bd9fd92a2..223e6389942 100644
--- a/source/blender/makesrna/intern/rna_timeline.c
+++ b/source/blender/makesrna/intern/rna_timeline.c
@@ -33,16 +33,10 @@
# include "BKE_idprop.h"
# include "WM_api.h"
-static IDProperty *rna_TimelineMarker_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_TimelineMarker_idprops(PointerRNA *ptr)
{
TimeMarker *marker = ptr->data;
-
- if (create && marker->prop == NULL) {
- IDPropertyTemplate val = {0};
- marker->prop = IDP_New(IDP_GROUP, &val, "Marker ID properties");
- }
-
- return marker->prop;
+ return &marker->prop;
}
static void rna_TimelineMarker_update(Main *UNUSED(bmain),
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 98bed5a7891..d4ae5f1ecfc 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -452,15 +452,10 @@ static unsigned int rna_UIList_filter_const_FILTER_ITEM_get(PointerRNA *UNUSED(p
return UILST_FLT_ITEM;
}
-static IDProperty *rna_UIList_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_UIList_idprops(PointerRNA *ptr)
{
uiList *ui_list = (uiList *)ptr->data;
- if (create && !ui_list->properties) {
- IDPropertyTemplate val = {0};
- ui_list->properties = IDP_New(IDP_GROUP, &val, "RNA_UIList IDproperties group");
- }
-
- return ui_list->properties;
+ return &ui_list->properties;
}
static void uilist_draw_item(uiList *ui_list,
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 81f6bcc5805..fd1c0b7951a 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -809,14 +809,9 @@ static const EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C
}
# endif
-static IDProperty *rna_AddonPref_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_AddonPref_idprops(PointerRNA *ptr)
{
- if (create && !ptr->data) {
- IDPropertyTemplate val = {0};
- ptr->data = IDP_New(IDP_GROUP, &val, "RNA_AddonPreferences group");
- }
-
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
static PointerRNA rna_Addon_preferences_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index a563541b968..afbde26e59e 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -568,14 +568,9 @@ static StructRNA *rna_OperatorProperties_refine(PointerRNA *ptr)
}
}
-static IDProperty *rna_OperatorProperties_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_OperatorProperties_idprops(PointerRNA *ptr)
{
- if (create && !ptr->data) {
- IDPropertyTemplate val = {0};
- ptr->data = IDP_New(IDP_GROUP, &val, "RNA_OperatorProperties group");
- }
-
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
static void rna_Operator_name_get(PointerRNA *ptr, char *value)
@@ -1120,13 +1115,9 @@ static PointerRNA rna_wmKeyConfig_preferences_get(PointerRNA *ptr)
}
}
-static IDProperty *rna_wmKeyConfigPref_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_wmKeyConfigPref_idprops(PointerRNA *ptr)
{
- if (create && !ptr->data) {
- IDPropertyTemplate val = {0};
- ptr->data = IDP_New(IDP_GROUP, &val, "RNA_KeyConfigPreferences group");
- }
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
static void rna_wmKeyConfigPref_unregister(Main *UNUSED(bmain), StructRNA *type)
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c
index 98920bbd518..076a77d4fb5 100644
--- a/source/blender/makesrna/intern/rna_wm_gizmo.c
+++ b/source/blender/makesrna/intern/rna_wm_gizmo.c
@@ -293,14 +293,9 @@ static StructRNA *rna_GizmoProperties_refine(PointerRNA *ptr)
}
}
-static IDProperty *rna_GizmoProperties_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_GizmoProperties_idprops(PointerRNA *ptr)
{
- if (create && !ptr->data) {
- IDPropertyTemplate val = {0};
- ptr->data = IDP_New(IDP_GROUP, &val, "RNA_GizmoProperties group");
- }
-
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
static PointerRNA rna_Gizmo_properties_get(PointerRNA *ptr)
@@ -585,14 +580,9 @@ static StructRNA *rna_GizmoGroupProperties_refine(PointerRNA *ptr)
}
}
-static IDProperty *rna_GizmoGroupProperties_idprops(PointerRNA *ptr, bool create)
+static IDProperty **rna_GizmoGroupProperties_idprops(PointerRNA *ptr)
{
- if (create && !ptr->data) {
- IDPropertyTemplate val = {0};
- ptr->data = IDP_New(IDP_GROUP, &val, "RNA_GizmoGroupProperties group");
- }
-
- return ptr->data;
+ return (IDProperty **)&ptr->data;
}
static wmGizmo *rna_GizmoGroup_gizmo_new(wmGizmoGroup *gzgroup,
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 649d36e3d57..828b8b79664 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -37,6 +37,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
@@ -122,7 +123,8 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
/* If neither vertex groups nor envelopes are used, the modifier has no bone dependencies. */
if ((amd->deformflag & ARM_DEF_VGROUP) != 0) {
/* Enumerate groups that match existing bones. */
- LISTBASE_FOREACH (bDeformGroup *, dg, &ctx->object->defbase) {
+ const ListBase *defbase = BKE_object_defgroup_list(ctx->object);
+ LISTBASE_FOREACH (bDeformGroup *, dg, defbase) {
if (BKE_pose_channel_find_name(amd->object->pose, dg->name) != NULL) {
/* Can't check BONE_NO_DEFORM because it can be animated. */
DEG_add_bone_relation(
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 4b9b24e4e47..bdb791dc8e7 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -109,7 +109,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
- walk(userData, ob, (ID **)&bmd->collection, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&bmd->collection, IDWALK_CB_USER);
walk(userData, ob, (ID **)&bmd->object, IDWALK_CB_NOP);
}
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index c38e5126f6b..52f21e3d3d0 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -101,7 +101,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct
range_vn_i(faceMap, numPoly_src, 0);
struct Scene *scene = DEG_get_input_scene(ctx->depsgraph);
- frac = (BKE_scene_frame_get(scene) - bmd->start) / bmd->length;
+ frac = (BKE_scene_ctime_get(scene) - bmd->start) / bmd->length;
CLAMP(frac, 0.0f, 1.0f);
if (bmd->flag & MOD_BUILD_FLAG_REVERSE) {
frac = 1.0f - frac;
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 40d027f3044..4487adcfdda 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -206,6 +206,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tclmd->point_cache->step = clmd->point_cache->step;
tclmd->point_cache->startframe = clmd->point_cache->startframe;
tclmd->point_cache->endframe = clmd->point_cache->endframe;
+ tclmd->point_cache->flag |= (clmd->point_cache->flag & PTCACHE_FLAGS_COPY);
}
}
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 20dbb299767..aae6d257766 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -167,7 +167,7 @@ static void deformVertsEM(ModifierData *md,
int defgrp_index = -1;
if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') {
- defgrp_index = BKE_object_defgroup_name_index(ctx->object, cmd->name);
+ defgrp_index = BKE_id_defgroup_name_index(&mesh->id, cmd->name);
if (defgrp_index != -1) {
use_dverts = true;
}
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 545e23221ec..bf197dca7e5 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -919,7 +919,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
EdgeHashIterator *ehi;
float *vertco = NULL, imat[4][4];
float rot[4];
- float cfra;
+ float ctime;
/* float timestep; */
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
@@ -940,7 +940,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* timestep = psys_get_timestep(&sim); */
- cfra = BKE_scene_frame_get(scene);
+ ctime = BKE_scene_ctime_get(scene);
/* hash table for vertice <-> particle relations */
vertpahash = BLI_edgehash_new(__func__);
@@ -962,7 +962,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* do mindex + totvert to ensure the vertex index to be the first
* with BLI_edgehashIterator_getKey */
- if (pa == NULL || cfra < pa->time) {
+ if (pa == NULL || ctime < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1022,7 +1022,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
psys_get_birth_coords(&sim, pa, &birth, 0, 0);
- state.time = cfra;
+ state.time = ctime;
psys_get_particle_state(&sim, ed_v2, &state, 1);
vertco = explode->mvert[v].co;
@@ -1076,7 +1076,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
orig_v4 = source.v4;
/* Same as above in the first loop over mesh's faces. */
- if (pa == NULL || cfra < pa->time) {
+ if (pa == NULL || ctime < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1096,7 +1096,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* override uv channel for particle age */
if (mtface) {
- float age = (pa != NULL) ? (cfra - pa->time) / pa->lifetime : 0.0f;
+ float age = (pa != NULL) ? (ctime - pa->time) / pa->lifetime : 0.0f;
/* Clamp to this range to avoid flipping to the other side of the coordinates. */
CLAMP(age, 0.001f, 0.999f);
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index a77f6cfe8ba..9aa8e3dd7c8 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -119,7 +119,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
/* A vertex will be in the mask if a selected bone influences it more than a certain threshold. */
static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
- Object *ob,
+ Mesh *mesh,
Object *armature_ob,
float threshold,
MutableSpan<bool> r_vertex_mask)
@@ -127,7 +127,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
/* Element i is true if there is a selected bone that uses vertex group i. */
Vector<bool> selected_bone_uses_group;
- for (bDeformGroup *def : ListBaseWrapper<bDeformGroup>(ob->defbase)) {
+ LISTBASE_FOREACH (bDeformGroup *, def, &mesh->vertex_group_names) {
bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name);
bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED);
selected_bone_uses_group.append(bone_for_group_exists);
@@ -325,10 +325,9 @@ void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
* 2. Find edges and polygons only using those vertices.
* 3. Create a new mesh that only uses the found vertices, edges and polygons.
*/
-static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
- Object *ob = ctx->object;
const bool invert_mask = mmd->flag & MOD_MASK_INV;
/* Return empty or input mesh when there are no vertex groups. */
@@ -339,7 +338,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Quick test to see if we can return early. */
if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (mesh->totvert == 0) ||
- BLI_listbase_is_empty(&ob->defbase)) {
+ BLI_listbase_is_empty(&mesh->vertex_group_names)) {
return mesh;
}
@@ -348,15 +347,15 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
Object *armature_ob = mmd->ob_arm;
/* Return input mesh if there is no armature with bones. */
- if (ELEM(NULL, armature_ob, armature_ob->pose, ob->defbase.first)) {
+ if (ELEM(NULL, armature_ob, armature_ob->pose)) {
return mesh;
}
vertex_mask = Array<bool>(mesh->totvert);
- compute_vertex_mask__armature_mode(dvert, ob, armature_ob, mmd->threshold, vertex_mask);
+ compute_vertex_mask__armature_mode(dvert, mesh, armature_ob, mmd->threshold, vertex_mask);
}
else {
- int defgrp_index = BKE_object_defgroup_name_index(ob, mmd->vgroup);
+ int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, mmd->vgroup);
/* Return input mesh if the vertex group does not exist. */
if (defgrp_index == -1) {
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index 6ec3277ee7a..e0507320628 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -104,20 +104,20 @@ static void meshcache_do(MeshCacheModifierData *mcmd,
/* -------------------------------------------------------------------- */
/* Interpret Time (the reading functions also do some of this ) */
if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) {
- const float cfra = BKE_scene_frame_get(scene);
+ const float ctime = BKE_scene_ctime_get(scene);
switch (mcmd->time_mode) {
case MOD_MESHCACHE_TIME_FRAME: {
- time = cfra;
+ time = ctime;
break;
}
case MOD_MESHCACHE_TIME_SECONDS: {
- time = cfra / fps;
+ time = ctime / fps;
break;
}
case MOD_MESHCACHE_TIME_FACTOR:
default: {
- time = cfra / fps;
+ time = ctime / fps;
break;
}
}
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 76eec76acb4..87fce26c45e 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -48,6 +48,7 @@
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "BKE_attribute_math.hh"
#include "BKE_customdata.h"
#include "BKE_geometry_set_instances.hh"
#include "BKE_global.h"
@@ -56,7 +57,6 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
-#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
@@ -83,8 +83,10 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry.h"
+#include "NOD_geometry_nodes_eval_log.hh"
#include "NOD_node_tree_multi_function.hh"
+using blender::destruct_ptr;
using blender::float3;
using blender::FunctionRef;
using blender::IndexRange;
@@ -97,6 +99,7 @@ using blender::Vector;
using blender::fn::GMutablePointer;
using blender::fn::GPointer;
using blender::nodes::GeoNodeExecParams;
+using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
@@ -734,19 +737,6 @@ static void initialize_group_input(NodesModifierData &nmd,
property_type->init_cpp_value(*property, r_value);
}
-static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> trees,
- const Object &object,
- const ModifierData &modifier)
-{
- const NodeTreeEvaluationContext context = {object, modifier};
-
- for (const blender::nodes::NodeTreeRef *tree : trees) {
- bNodeTree *btree_cow = tree->btree();
- bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
- BKE_nodetree_ui_storage_free_for_context(*btree_original, context);
- }
-}
-
static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
{
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
@@ -766,8 +756,6 @@ static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
return spreadsheets;
}
-using PreviewSocketMap = blender::MultiValueMap<DSocket, uint64_t>;
-
static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
NodesModifierData *nmd,
const ModifierEvalContext *ctx,
@@ -821,19 +809,10 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre
}
const NodeTreeRef &tree_ref = context->tree();
- for (const NodeRef *node_ref : tree_ref.nodes()) {
+ for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) {
if (node_ref->name() == last_context->node_name) {
const DNode viewer_node{context, node_ref};
- DSocket socket_to_view;
- viewer_node.input(0).foreach_origin_socket(
- [&](const DSocket socket) { socket_to_view = socket; });
- if (!socket_to_view) {
- return {};
- }
- bNodeSocket *bsocket = socket_to_view->bsocket();
- if (bsocket->type == SOCK_GEOMETRY && bsocket->flag != SOCK_MULTI_INPUT) {
- return socket_to_view;
- }
+ return viewer_node.input(0);
}
}
return {};
@@ -842,7 +821,7 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre
static void find_sockets_to_preview(NodesModifierData *nmd,
const ModifierEvalContext *ctx,
const DerivedNodeTree &tree,
- PreviewSocketMap &r_sockets_to_preview)
+ Set<DSocket> &r_sockets_to_preview)
{
Main *bmain = DEG_get_bmain(ctx->depsgraph);
@@ -852,51 +831,16 @@ static void find_sockets_to_preview(NodesModifierData *nmd,
for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree);
if (socket) {
- const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
- r_sockets_to_preview.add_non_duplicates(socket, key);
+ r_sockets_to_preview.add(socket);
}
}
}
-static void log_preview_socket_value(const Span<GPointer> values,
- Object *object,
- Span<uint64_t> keys)
+static void clear_runtime_data(NodesModifierData *nmd)
{
- GeometrySet geometry_set = *(const GeometrySet *)values[0].get();
- geometry_set.ensure_owns_direct_data();
- for (uint64_t key : keys) {
- BKE_object_preview_geometry_set_add(object, key, new GeometrySet(geometry_set));
- }
-}
-
-static void log_ui_hints(const DSocket socket,
- const Span<GPointer> values,
- Object *self_object,
- NodesModifierData *nmd)
-{
- const DNode node = socket.node();
- if (node->is_reroute_node() || socket->typeinfo()->type != SOCK_GEOMETRY) {
- return;
- }
- bNodeTree *btree_cow = node->btree();
- bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
- const NodeTreeEvaluationContext context{*self_object, nmd->modifier};
- for (const GPointer &data : values) {
- if (data.type() == &CPPType::get<GeometrySet>()) {
- const GeometrySet &geometry_set = *(const GeometrySet *)data.get();
- blender::bke::geometry_set_instances_attribute_foreach(
- geometry_set,
- [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
- BKE_nodetree_attribute_hint_add(*btree_original,
- context,
- *node->bnode(),
- attribute_name,
- meta_data.domain,
- meta_data.data_type);
- return true;
- },
- 8);
- }
+ if (nmd->runtime_eval_log != nullptr) {
+ delete (geo_log::ModifierLog *)nmd->runtime_eval_log;
+ nmd->runtime_eval_log = nullptr;
}
}
@@ -952,32 +896,32 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
Vector<DInputSocket> group_outputs;
group_outputs.append({root_context, &socket_to_compute});
- PreviewSocketMap preview_sockets;
- find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
-
- auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) {
- if (!logging_enabled(ctx)) {
- return;
- }
- Span<uint64_t> keys = preview_sockets.lookup(socket);
- if (!keys.is_empty()) {
- log_preview_socket_value(values, ctx->object, keys);
- }
- log_ui_hints(socket, values, ctx->object, nmd);
- };
+ std::optional<geo_log::GeoLogger> geo_logger;
blender::modifiers::geometry_nodes::GeometryNodesEvaluationParams eval_params;
+
+ if (logging_enabled(ctx)) {
+ Set<DSocket> preview_sockets;
+ find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
+ eval_params.force_compute_sockets.extend(preview_sockets.begin(), preview_sockets.end());
+ geo_logger.emplace(std::move(preview_sockets));
+ }
+
eval_params.input_values = group_inputs;
eval_params.output_sockets = group_outputs;
- eval_params.force_compute_sockets.extend(preview_sockets.keys().begin(),
- preview_sockets.keys().end());
eval_params.mf_by_node = &mf_by_node;
eval_params.modifier_ = nmd;
eval_params.depsgraph = ctx->depsgraph;
eval_params.self_object = ctx->object;
- eval_params.log_socket_value_fn = log_socket_value;
+ eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr;
blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params);
+ if (geo_logger.has_value()) {
+ NodesModifierData *nmd_orig = (NodesModifierData *)BKE_modifier_get_original(&nmd->modifier);
+ clear_runtime_data(nmd_orig);
+ nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
+ }
+
BLI_assert(eval_params.r_output_values.size() == 1);
GMutablePointer result = eval_params.r_output_values[0];
return result.relocate_out<GeometrySet>();
@@ -1067,10 +1011,6 @@ static void modifyGeometry(ModifierData *md,
return;
}
- if (logging_enabled(ctx)) {
- reset_tree_ui_storage(tree.used_node_tree_refs(), *ctx->object, *md);
- }
-
geometry_set = compute_geometry(
tree, input_nodes, *group_outputs[0], std::move(geometry_set), nmd, ctx);
}
@@ -1078,13 +1018,14 @@ static void modifyGeometry(ModifierData *md,
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
GeometrySet geometry_set = GeometrySet::create_with_mesh(mesh, GeometryOwnershipType::Editable);
- geometry_set.get_component_for_write<MeshComponent>().copy_vertex_group_names_from_object(
- *ctx->object);
+
modifyGeometry(md, ctx, geometry_set);
- /* This function is only called when applying modifiers. In this case it makes sense to realize
- * instances, otherwise in some cases there might be no results when applying the modifier. */
- geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(geometry_set);
+ if (ctx->flag & MOD_APPLY_TO_BASE_MESH) {
+ /* In this case it makes sense to realize instances, otherwise in some cases there might be no
+ * results when applying the modifier. */
+ geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(geometry_set);
+ }
Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release();
if (new_mesh == nullptr) {
@@ -1215,6 +1156,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
BLO_read_data_address(reader, &nmd->settings.properties);
IDP_BlendDataRead(reader, &nmd->settings.properties);
+ nmd->runtime_eval_log = nullptr;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
@@ -1224,6 +1166,8 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
BKE_modifier_copydata_generic(md, target, flag);
+ tnmd->runtime_eval_log = nullptr;
+
if (nmd->settings.properties != nullptr) {
tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag);
}
@@ -1236,6 +1180,8 @@ static void freeData(ModifierData *md)
IDP_FreeProperty_ex(nmd->settings.properties, false);
nmd->settings.properties = nullptr;
}
+
+ clear_runtime_data(nmd);
}
static void requiredDataMask(Object *UNUSED(ob),
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 205bfa34465..18cc1ce6c86 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -558,11 +558,11 @@ class GeometryNodesEvaluator {
for (auto &&item : params_.input_values.items()) {
const DOutputSocket socket = item.key;
GMutablePointer value = item.value;
- this->log_socket_value(socket, value);
const DNode node = socket.node();
if (!node_states_.contains_as(node)) {
/* The socket is not connected to any output. */
+ this->log_socket_value({socket}, value);
value.destruct();
continue;
}
@@ -780,7 +780,6 @@ class GeometryNodesEvaluator {
/* Checks if all the linked sockets have been provided already. */
if (multi_value.items.size() == multi_value.expected_size) {
input_state.was_ready_for_execution = true;
- this->log_socket_value(socket, input_state, multi_value.items);
}
else if (is_required) {
/* The input is required but is not fully provided yet. Therefore the node cannot be
@@ -792,7 +791,6 @@ class GeometryNodesEvaluator {
SingleInputValue &single_value = *input_state.value.single;
if (single_value.value != nullptr) {
input_state.was_ready_for_execution = true;
- this->log_socket_value(socket, GPointer{input_state.type, single_value.value});
}
else if (is_required) {
/* The input is required but has not been provided yet. Therefore the node cannot be
@@ -1170,6 +1168,9 @@ class GeometryNodesEvaluator {
{
BLI_assert(value_to_forward.get() != nullptr);
+ Vector<DSocket> sockets_to_log_to;
+ sockets_to_log_to.append(from_socket);
+
Vector<DInputSocket> to_sockets;
auto handle_target_socket_fn = [&, this](const DInputSocket to_socket) {
if (this->should_forward_to_socket(to_socket)) {
@@ -1177,9 +1178,7 @@ class GeometryNodesEvaluator {
}
};
auto handle_skipped_socket_fn = [&, this](const DSocket socket) {
- /* Log socket value on intermediate sockets to support e.g. attribute search or spreadsheet
- * breadcrumbs on group nodes. */
- this->log_socket_value(socket, value_to_forward);
+ sockets_to_log_to.append(socket);
};
from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn);
@@ -1192,11 +1191,18 @@ class GeometryNodesEvaluator {
if (from_type == to_type) {
/* All target sockets that do not need a conversion will be handled afterwards. */
to_sockets_same_type.append(to_socket);
+ /* Multi input socket values are logged once all values are available. */
+ if (!to_socket->is_multi_input_socket()) {
+ sockets_to_log_to.append(to_socket);
+ }
continue;
}
this->forward_to_socket_with_different_type(
allocator, value_to_forward, from_socket, to_socket, to_type);
}
+
+ this->log_socket_value(sockets_to_log_to, value_to_forward);
+
this->forward_to_sockets_with_same_type(
allocator, to_sockets_same_type, value_to_forward, from_socket);
}
@@ -1227,6 +1233,7 @@ class GeometryNodesEvaluator {
/* Allocate a buffer for the converted value. */
void *buffer = allocator.allocate(to_type.size(), to_type.alignment());
+ GMutablePointer value{to_type, buffer};
if (conversions_.is_convertible(from_type, to_type)) {
/* Do the conversion if possible. */
@@ -1236,7 +1243,11 @@ class GeometryNodesEvaluator {
/* Cannot convert, use default value instead. */
to_type.copy_construct(to_type.default_value(), buffer);
}
- this->add_value_to_input_socket(to_socket, from_socket, {to_type, buffer});
+ /* Multi input socket values are logged once all values are available. */
+ if (!to_socket->is_multi_input_socket()) {
+ this->log_socket_value({to_socket}, value);
+ }
+ this->add_value_to_input_socket(to_socket, from_socket, value);
}
void forward_to_sockets_with_same_type(LinearAllocator<> &allocator,
@@ -1284,6 +1295,10 @@ class GeometryNodesEvaluator {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
multi_value.items.append({origin, value.get()});
+
+ if (multi_value.expected_size == multi_value.items.size()) {
+ this->log_socket_value({socket}, input_state, multi_value.items);
+ }
}
else {
/* Assign the value to the input. */
@@ -1314,10 +1329,14 @@ class GeometryNodesEvaluator {
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
multi_value.items.append({origin_socket, value.get()});
+ if (multi_value.expected_size == multi_value.items.size()) {
+ this->log_socket_value({input_socket}, input_state, multi_value.items);
+ }
}
else {
SingleInputValue &single_value = *input_state.value.single;
single_value.value = value.get();
+ this->log_socket_value({input_socket}, value);
}
}
@@ -1370,29 +1389,27 @@ class GeometryNodesEvaluator {
return *node_states_.lookup_key_as(node).state;
}
- void log_socket_value(const DSocket socket, Span<GPointer> values)
+ void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values)
{
- if (params_.log_socket_value_fn) {
- params_.log_socket_value_fn(socket, values);
+ if (params_.geo_logger == nullptr) {
+ return;
}
- }
- void log_socket_value(const DSocket socket,
- InputState &input_state,
- Span<MultiInputValueItem> values)
- {
Vector<GPointer, 16> value_pointers;
value_pointers.reserve(values.size());
const CPPType &type = *input_state.type;
for (const MultiInputValueItem &item : values) {
value_pointers.append({type, item.value});
}
- this->log_socket_value(socket, value_pointers);
+ params_.geo_logger->local().log_multi_value_socket(socket, value_pointers);
}
- void log_socket_value(const DSocket socket, GPointer value)
+ void log_socket_value(Span<DSocket> sockets, GPointer value)
{
- this->log_socket_value(socket, Span<GPointer>(&value, 1));
+ if (params_.geo_logger == nullptr) {
+ return;
+ }
+ params_.geo_logger->local().log_value_for_sockets(sockets, value);
}
/* In most cases when `NodeState` is accessed, the node has to be locked first to avoid race
@@ -1431,6 +1448,7 @@ NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator,
this->self_object = evaluator.params_.self_object;
this->modifier = &evaluator.params_.modifier_->modifier;
this->depsgraph = evaluator.params_.depsgraph;
+ this->logger = evaluator.params_.geo_logger;
}
bool NodeParamsProvider::can_get_input(StringRef identifier) const
@@ -1530,8 +1548,6 @@ void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value)
const DOutputSocket socket = this->dnode.output_by_identifier(identifier);
BLI_assert(socket);
- evaluator_.log_socket_value(socket, value);
-
OutputState &output_state = node_state_.outputs[socket->index()];
BLI_assert(!output_state.has_been_computed);
evaluator_.forward_output(socket, value);
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
index 58eb6a4cd0b..f4ee6242dcb 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
@@ -19,20 +19,21 @@
#include "BLI_map.hh"
#include "NOD_derived_node_tree.hh"
+#include "NOD_geometry_nodes_eval_log.hh"
#include "NOD_node_tree_multi_function.hh"
#include "FN_generic_pointer.hh"
#include "DNA_modifier_types.h"
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+
namespace blender::modifiers::geometry_nodes {
using namespace nodes::derived_node_tree_types;
using fn::GMutablePointer;
using fn::GPointer;
-using LogSocketValueFn = std::function<void(DSocket, Span<GPointer>)>;
-
struct GeometryNodesEvaluationParams {
blender::LinearAllocator<> allocator;
@@ -48,7 +49,7 @@ struct GeometryNodesEvaluationParams {
const NodesModifierData *modifier_;
Depsgraph *depsgraph;
Object *self_object;
- LogSocketValueFn log_socket_value_fn;
+ geo_log::GeoLogger *geo_logger;
Vector<GMutablePointer> r_output_values;
};
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 38cce5e6a50..ef70f3fe6f4 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -120,7 +120,6 @@ static void deformVerts(ModifierData *md,
Mesh *mesh_src = mesh;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
ParticleSystem *psys = NULL;
- /* float cfra = BKE_scene_frame_get(md->scene); */ /* UNUSED */
if (ctx->object->particlesystem.first) {
psys = psmd->psys;
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index a5bd41c23e4..e97190b1878 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -242,9 +242,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
MDeformVert *dvert;
const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
int defgrp_index;
- const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object,
- smd->shell_defgrp_name);
- const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name);
+ const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name);
+ const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name);
/* array size is doubled in case of using a shell */
const uint stride = do_shell ? 2 : 1;
@@ -1028,14 +1027,13 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (do_rim) {
uint i;
- /* bugger, need to re-calculate the normals for the new edge faces.
+ /* NOTE(campbell): Unfortunately re-calculate the normals for the new edge faces is necessary.
* This could be done in many ways, but probably the quickest way
* is to calculate the average normals for side faces only.
* Then blend them with the normals of the edge verts.
*
- * at the moment its easiest to allocate an entire array for every vertex,
- * even though we only need edge verts - campbell
- */
+ * At the moment its easiest to allocate an entire array for every vertex,
+ * even though we only need edge verts. */
#define SOLIDIFY_SIDE_NORMALS
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index 1a7daa10e0f..b872f04b60f 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -181,9 +181,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
MDeformVert *dvert;
const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
int defgrp_index;
- const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object,
- smd->shell_defgrp_name);
- const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name);
+ const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name);
+ const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name);
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 9aed4fbfc5f..5b97d0eb259 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -254,15 +254,22 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
void MOD_get_vgroup(
Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
{
- *defgrp_index = BKE_object_defgroup_name_index(ob, name);
- *dvert = NULL;
-
- if (*defgrp_index != -1) {
- if (ob->type == OB_LATTICE) {
+ if (mesh) {
+ *defgrp_index = BKE_id_defgroup_name_index(&mesh->id, name);
+ if (*defgrp_index != -1) {
+ *dvert = mesh->dvert;
+ }
+ else {
+ *dvert = NULL;
+ }
+ }
+ else {
+ *defgrp_index = BKE_object_defgroup_name_index(ob, name);
+ if (*defgrp_index != -1 && ob->type == OB_LATTICE) {
*dvert = BKE_lattice_deform_verts_get(ob);
}
- else if (mesh) {
- *dvert = mesh->dvert;
+ else {
+ *dvert = NULL;
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index c5e2ecb9660..696c4c855c7 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -230,7 +230,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
MEM_freeN(tex_co);
}
- else if ((ref_didx = BKE_object_defgroup_name_index(ob, defgrp_name)) != -1) {
+ else if ((ref_didx = BKE_id_defgroup_name_index(&mesh->id, defgrp_name)) != -1) {
MDeformVert *dvert = NULL;
/* Check whether we want to set vgroup weights from a constant weight factor or a vertex
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index b5f72c88800..093fa118ee0 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -194,12 +194,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
- if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
+ if ((numVerts == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) {
return mesh;
}
/* Get vgroup idx from its name. */
- const int defgrp_index = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name);
+ const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index == -1) {
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index a71a2f3b480..7aae089fa18 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -245,19 +245,19 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
- if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
+ if ((numVerts == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) {
return mesh;
}
/* Get vgroup idx from its name. */
- const int defgrp_index = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name_a);
+ const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_a);
if (defgrp_index == -1) {
return mesh;
}
/* Get second vgroup idx from its name, if given. */
int defgrp_index_other = -1;
if (wmd->defgrp_name_b[0] != '\0') {
- defgrp_index_other = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name_b);
+ defgrp_index_other = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_b);
if (defgrp_index_other == -1) {
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index b0d2f52f78c..6e78774269a 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -468,7 +468,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
- if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
+ if ((numVerts == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) {
return mesh;
}
@@ -479,11 +479,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
/* Get vgroup idx from its name. */
- defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name);
+ defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index == -1) {
return mesh;
}
-
const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
/* As this modifier never add vertices to vgroup, just return. */
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index 1590f342666..fe2d699aea8 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -1573,11 +1573,12 @@ struct WeldVertexCluster {
uint merged_verts;
};
-static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
Mesh *result = mesh;
- Object *ob = ctx->object;
BLI_bitmap *v_mask = NULL;
int v_mask_act = 0;
@@ -1590,7 +1591,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
totvert = mesh->totvert;
/* Vertex Group. */
- const int defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name);
+ const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index != -1) {
MDeformVert *dvert, *dv;
dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 16bf1f7d763..e188a61e975 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -76,7 +76,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
Mesh *result;
BMesh *bm;
- const int defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name);
+ const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
bm = BKE_mesh_to_bmesh_ex(mesh,
&(struct BMeshCreateParams){0},
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a7640d6cacd..09085ac8799 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -165,11 +165,12 @@ set(SRC
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_convex_hull.cc
geometry/nodes/node_geo_curve_endpoints.cc
- geometry/nodes/node_geo_curve_length.cc
+ geometry/nodes/node_geo_curve_length.cc
geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
geometry/nodes/node_geo_curve_primitive_circle.cc
geometry/nodes/node_geo_curve_primitive_line.cc
geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+ geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
geometry/nodes/node_geo_curve_primitive_spiral.cc
geometry/nodes/node_geo_curve_primitive_star.cc
geometry/nodes/node_geo_curve_sample.cc
@@ -338,6 +339,7 @@ set(SRC
texture/node_texture_util.c
intern/derived_node_tree.cc
+ intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
intern/node_common.c
intern/node_exec.cc
@@ -361,6 +363,7 @@ set(SRC
NOD_function.h
NOD_geometry.h
NOD_geometry_exec.hh
+ NOD_geometry_nodes_eval_log.hh
NOD_math_functions.hh
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
@@ -421,6 +424,11 @@ if(WITH_TBB)
${TBB_INCLUDE_DIRS}
)
add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
endif()
if(WITH_IMAGE_OPENEXR)
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 9346a3ae5a8..8a2b77118e5 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -57,6 +57,7 @@ void register_node_type_geo_curve_primitive_bezier_segment(void);
void register_node_type_geo_curve_primitive_circle(void);
void register_node_type_geo_curve_primitive_line(void);
void register_node_type_geo_curve_primitive_quadratic_bezier(void);
+void register_node_type_geo_curve_primitive_quadrilateral(void);
void register_node_type_geo_curve_primitive_spiral(void);
void register_node_type_geo_curve_primitive_star(void);
void register_node_type_geo_curve_sample(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 23474201daa..d6a23051c0b 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -21,11 +21,11 @@
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
-#include "BKE_node_ui_storage.hh"
#include "DNA_node_types.h"
#include "NOD_derived_node_tree.hh"
+#include "NOD_geometry_nodes_eval_log.hh"
struct Depsgraph;
struct ModifierData;
@@ -52,10 +52,11 @@ using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
using fn::GVMutableArray_Typed;
using fn::GVMutableArrayPtr;
+using geometry_nodes_eval_log::NodeWarningType;
/**
- * This class exists to separate the memory management details of the geometry nodes evaluator from
- * the node execution functions and related utilities.
+ * This class exists to separate the memory management details of the geometry nodes evaluator
+ * from the node execution functions and related utilities.
*/
class GeoNodeExecParamsProvider {
public:
@@ -63,6 +64,7 @@ class GeoNodeExecParamsProvider {
const Object *self_object = nullptr;
const ModifierData *modifier = nullptr;
Depsgraph *depsgraph = nullptr;
+ geometry_nodes_eval_log::GeoLogger *logger = nullptr;
/**
* Returns true when the node is allowed to get/extract the input value. The identifier is
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
new file mode 100644
index 00000000000..b85862a0176
--- /dev/null
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -0,0 +1,309 @@
+/*
+ * 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
+
+/**
+ * Many geometry nodes related UI features need access to data produced during evaluation. Not only
+ * is the final output required but also the intermediate results. Those features include
+ * attribute search, node warnings, socket inspection and the viewer node.
+ *
+ * This file provides the framework for logging data during evaluation and accessing the data after
+ * evaluation.
+ *
+ * During logging every thread gets its own local logger to avoid too much locking (logging
+ * generally happens for every socket). After geometry nodes evaluation is done, the thread-local
+ * logging information is combined and post-processed to make it easier for the UI to lookup.
+ * necessary information.
+ */
+
+#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_linear_allocator.hh"
+#include "BLI_map.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "FN_generic_pointer.hh"
+
+#include "NOD_derived_node_tree.hh"
+
+struct SpaceNode;
+struct SpaceSpreadsheet;
+
+namespace blender::nodes::geometry_nodes_eval_log {
+
+using fn::GMutablePointer;
+using fn::GPointer;
+
+/** Contains information about a value that has been computed during geometry nodes evaluation. */
+class ValueLog {
+ public:
+ virtual ~ValueLog() = default;
+};
+
+/** Contains an owned copy of a value of a generic type. */
+class GenericValueLog : public ValueLog {
+ private:
+ GMutablePointer data_;
+
+ public:
+ GenericValueLog(GMutablePointer data) : data_(data)
+ {
+ }
+
+ ~GenericValueLog()
+ {
+ data_.destruct();
+ }
+
+ GPointer value() const
+ {
+ return data_;
+ }
+};
+
+struct GeometryAttributeInfo {
+ std::string name;
+ AttributeDomain domain;
+ CustomDataType data_type;
+};
+
+/** Contains information about a geometry set. In most cases this does not store the entire
+ * geometry set as this would require too much memory. */
+class GeometryValueLog : public ValueLog {
+ private:
+ Vector<GeometryAttributeInfo> attributes_;
+ Vector<GeometryComponentType> component_types_;
+ std::unique_ptr<GeometrySet> full_geometry_;
+
+ public:
+ struct MeshInfo {
+ int tot_verts, tot_edges, tot_faces;
+ };
+ struct CurveInfo {
+ int tot_splines;
+ };
+ struct PointCloudInfo {
+ int tot_points;
+ };
+ struct InstancesInfo {
+ int tot_instances;
+ };
+
+ std::optional<MeshInfo> mesh_info;
+ std::optional<CurveInfo> curve_info;
+ std::optional<PointCloudInfo> pointcloud_info;
+ std::optional<InstancesInfo> instances_info;
+
+ GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry);
+
+ Span<GeometryAttributeInfo> attributes() const
+ {
+ return attributes_;
+ }
+
+ Span<GeometryComponentType> component_types() const
+ {
+ return component_types_;
+ }
+
+ const GeometrySet *full_geometry() const
+ {
+ return full_geometry_.get();
+ }
+};
+
+enum class NodeWarningType {
+ Error,
+ Warning,
+ Info,
+};
+
+struct NodeWarning {
+ NodeWarningType type;
+ std::string message;
+};
+
+struct NodeWithWarning {
+ DNode node;
+ NodeWarning warning;
+};
+
+/** The same value can be referenced by multiple sockets when they are linked. */
+struct ValueOfSockets {
+ Span<DSocket> sockets;
+ destruct_ptr<ValueLog> value;
+};
+
+class GeoLogger;
+class ModifierLog;
+
+/** Every thread has its own local logger to avoid having to communicate between threads during
+ * evaluation. After evaluation the individual logs are combined. */
+class LocalGeoLogger {
+ private:
+ /* Back pointer to the owner of this local logger. */
+ GeoLogger *main_logger_;
+ /* Allocator for the many small allocations during logging. This is in a `unique_ptr` so that
+ * ownership can be transferred later on. */
+ std::unique_ptr<LinearAllocator<>> allocator_;
+ Vector<ValueOfSockets> values_;
+ Vector<NodeWithWarning> node_warnings_;
+
+ friend ModifierLog;
+
+ public:
+ LocalGeoLogger(GeoLogger &main_logger) : main_logger_(&main_logger)
+ {
+ this->allocator_ = std::make_unique<LinearAllocator<>>();
+ }
+
+ void log_value_for_sockets(Span<DSocket> sockets, GPointer value);
+ void log_multi_value_socket(DSocket socket, Span<GPointer> values);
+ void log_node_warning(DNode node, NodeWarningType type, std::string message);
+};
+
+/** The root logger class. */
+class GeoLogger {
+ private:
+ /** The entire geometry of sockets in this set should be cached, because e.g. the spreadsheet
+ * displays the data. We don't log the entire geometry at all places, because that would require
+ * way too much memory. */
+ Set<DSocket> log_full_geometry_sockets_;
+ threading::EnumerableThreadSpecific<LocalGeoLogger> threadlocals_;
+
+ friend LocalGeoLogger;
+
+ public:
+ GeoLogger(Set<DSocket> log_full_geometry_sockets)
+ : log_full_geometry_sockets_(std::move(log_full_geometry_sockets)),
+ threadlocals_([this]() { return LocalGeoLogger(*this); })
+ {
+ }
+
+ LocalGeoLogger &local()
+ {
+ return threadlocals_.local();
+ }
+
+ auto begin()
+ {
+ return threadlocals_.begin();
+ }
+
+ auto end()
+ {
+ return threadlocals_.end();
+ }
+};
+
+/** Contains information that has been logged for one specific socket. */
+class SocketLog {
+ private:
+ ValueLog *value_ = nullptr;
+
+ friend ModifierLog;
+
+ public:
+ const ValueLog *value() const
+ {
+ return value_;
+ }
+};
+
+/** Contains information that has been logged for one specific node. */
+class NodeLog {
+ private:
+ Vector<SocketLog> input_logs_;
+ Vector<SocketLog> output_logs_;
+ Vector<NodeWarning, 0> warnings_;
+
+ friend ModifierLog;
+
+ public:
+ const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const;
+ const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const;
+
+ Span<SocketLog> input_logs() const
+ {
+ return input_logs_;
+ }
+
+ Span<SocketLog> output_logs() const
+ {
+ return output_logs_;
+ }
+
+ Span<NodeWarning> warnings() const
+ {
+ return warnings_;
+ }
+
+ Vector<const GeometryAttributeInfo *> lookup_available_attributes() const;
+};
+
+/** Contains information that has been logged for one specific tree. */
+class TreeLog {
+ private:
+ Map<std::string, destruct_ptr<NodeLog>> node_logs_;
+ Map<std::string, destruct_ptr<TreeLog>> child_logs_;
+
+ friend ModifierLog;
+
+ public:
+ const NodeLog *lookup_node_log(StringRef node_name) const;
+ const NodeLog *lookup_node_log(const bNode &node) const;
+ const TreeLog *lookup_child_log(StringRef node_name) const;
+};
+
+/** Contains information about an entire geometry nodes evaluation. */
+class ModifierLog {
+ private:
+ LinearAllocator<> allocator_;
+ /* Allocators of the individual loggers. */
+ Vector<std::unique_ptr<LinearAllocator<>>> logger_allocators_;
+ destruct_ptr<TreeLog> root_tree_logs_;
+ Vector<destruct_ptr<ValueLog>> logged_values_;
+
+ public:
+ ModifierLog(GeoLogger &logger);
+
+ const TreeLog &root_tree() const
+ {
+ return *root_tree_logs_;
+ }
+
+ /* Utilities to find logged information for a specific context. */
+ static const ModifierLog *find_root_by_node_editor_context(const SpaceNode &snode);
+ static const TreeLog *find_tree_by_node_editor_context(const SpaceNode &snode);
+ static const NodeLog *find_node_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node);
+ static const SocketLog *find_socket_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node,
+ const bNodeSocket &socket);
+ static const NodeLog *find_node_by_spreadsheet_editor_context(
+ const SpaceSpreadsheet &sspreadsheet);
+
+ private:
+ using LogByTreeContext = Map<const DTreeContext *, TreeLog *>;
+
+ TreeLog &lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context,
+ const DTreeContext &tree_context);
+ NodeLog &lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node);
+ SocketLog &lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context, DSocket socket);
+};
+
+} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 854a27b01d8..c24763baa1e 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -210,7 +210,7 @@ DefNode(CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIPS
DefNode(CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" )
DefNode(CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" )
DefNode(CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" )
-DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "View Switch", "" )
+DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "Switch View", "" )
DefNode(CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" )
DefNode(CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" )
DefNode(CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" )
@@ -295,6 +295,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Cu
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_primitive_quadrilateral, "CURVE_PRIMITIVE_QUADRILATERAL", CurvePrimitiveQuadrilateral, "Quadrilateral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMITIVE_QUADRATIC_BEZIER", CurveQuadraticBezier, "Quadratic Bezier", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 1b9e9af3e2d..ae947b7aeed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -83,9 +83,10 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
}
static std::unique_ptr<CurveEval> create_point_circle_curve(
- const float3 p1, const float3 p2, const float3 p3, const int resolution, float center_out[3])
+ const float3 p1, const float3 p2, const float3 p3, const int resolution, float3 &r_center)
{
if (colinear_f3_f3_f3(p1, p2, p3)) {
+ r_center = float3(0);
return nullptr;
}
@@ -118,6 +119,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
/* If the 3 planes do not intersect at one point, just return empty geometry. */
if (!isect_plane_plane_plane_v3(plane_1, plane_2, plane_3, center)) {
+ r_center = float3(0);
return nullptr;
}
@@ -141,7 +143,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
- copy_v3_v3(center_out, center);
+ r_center = center;
return curve;
}
@@ -179,18 +181,13 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) {
- float center_point[3];
+ float3 center_point;
curve = create_point_circle_curve(params.extract_input<float3>("Point 1"),
params.extract_input<float3>("Point 2"),
params.extract_input<float3>("Point 3"),
std::max(params.extract_input<int>("Resolution"), 3),
center_point);
- if (curve) {
- params.set_output("Center", float3(center_point));
- }
- else {
- params.set_output("Center", float3(0, 0, 0));
- }
+ params.set_output("Center", center_point);
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS) {
curve = create_radius_circle_curve(std::max(params.extract_input<int>("Resolution"), 3),
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 04a7fc7e5df..419a7af1ba0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -95,7 +95,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
spline->resize(2);
MutableSpan<float3> positions = spline->positions();
positions[0] = start;
- positions[1] = direction.normalized() * length;
+ positions[1] = direction.normalized() * length + start;
spline->radii().fill(1.0f);
spline->tilts().fill(0.0f);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
new file mode 100644
index 00000000000..5f3f159c305
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -0,0 +1,241 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_spline.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_in[] = {
+ {SOCK_FLOAT, N_("Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Height"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Bottom Width"), 4.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Top Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Offset"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Bottom Height"), 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Top Height"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 1"), -1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 2"), 1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 3"), 1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 4"), -1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
+ sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
+ data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
+ node->storage = data;
+}
+
+namespace blender::nodes {
+
+static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage;
+ GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
+ node_storage.mode);
+
+ bNodeSocket *width = ((bNodeSocket *)node->inputs.first);
+ bNodeSocket *height = width->next;
+ bNodeSocket *bottom = height->next;
+ bNodeSocket *top = bottom->next;
+ bNodeSocket *offset = top->next;
+ bNodeSocket *bottom_height = offset->next;
+ bNodeSocket *top_height = bottom_height->next;
+ bNodeSocket *p1 = top_height->next;
+ bNodeSocket *p2 = p1->next;
+ bNodeSocket *p3 = p2->next;
+ bNodeSocket *p4 = p3->next;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(sock, false);
+ }
+
+ if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) {
+ nodeSetSocketAvailability(width, true);
+ nodeSetSocketAvailability(height, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) {
+ nodeSetSocketAvailability(width, true);
+ nodeSetSocketAvailability(height, true);
+ nodeSetSocketAvailability(offset, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) {
+ nodeSetSocketAvailability(bottom, true);
+ nodeSetSocketAvailability(top, true);
+ nodeSetSocketAvailability(offset, true);
+ nodeSetSocketAvailability(height, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) {
+ nodeSetSocketAvailability(width, true);
+ nodeSetSocketAvailability(bottom_height, true);
+ nodeSetSocketAvailability(top_height, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) {
+ nodeSetSocketAvailability(p1, true);
+ nodeSetSocketAvailability(p2, true);
+ nodeSetSocketAvailability(p3, true);
+ nodeSetSocketAvailability(p4, true);
+ }
+}
+
+static void create_rectangle_curve(MutableSpan<float3> positions,
+ const float height,
+ const float width)
+{
+ positions[0] = float3(width / 2.0f, -height / 2.0f, 0.0f);
+ positions[1] = float3(-width / 2.0f, -height / 2.0f, 0.0f);
+ positions[2] = float3(-width / 2.0f, height / 2.0f, 0.0f);
+ positions[3] = float3(width / 2.0f, height / 2.0f, 0.0f);
+}
+
+static void create_points_curve(MutableSpan<float3> positions,
+ const float3 &p1,
+ const float3 &p2,
+ const float3 &p3,
+ const float3 &p4)
+{
+ positions[0] = p1;
+ positions[1] = p2;
+ positions[2] = p3;
+ positions[3] = p4;
+}
+
+static void create_parallelogram_curve(MutableSpan<float3> positions,
+ const float height,
+ const float width,
+ const float offset)
+{
+ positions[0] = float3(width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f);
+ positions[1] = float3(-width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f);
+ positions[2] = float3(-width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f);
+ positions[3] = float3(width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f);
+}
+static void create_trapezoid_curve(MutableSpan<float3> positions,
+ const float bottom,
+ const float top,
+ const float offset,
+ const float height)
+{
+ positions[0] = float3(bottom / 2.0f, -height / 2.0f, 0.0f);
+ positions[1] = float3(-bottom / 2.0f, -height / 2.0f, 0.0f);
+ positions[2] = float3(-top / 2.0f + offset, height / 2.0f, 0.0f);
+ positions[3] = float3(top / 2.0f + offset, height / 2.0f, 0.0f);
+}
+
+static void create_kite_curve(MutableSpan<float3> positions,
+ const float width,
+ const float bottom_height,
+ const float top_height)
+{
+ positions[0] = float3(-width / 2.0f, 0, 0);
+ positions[1] = float3(0, top_height, 0);
+ positions[2] = float3(width / 2, 0, 0);
+ positions[3] = float3(0, -bottom_height, 0);
+}
+
+static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurvePrimitiveQuad &node_storage =
+ *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage;
+ const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
+ node_storage.mode);
+
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->resize(4);
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+ spline->set_cyclic(true);
+ MutableSpan<float3> positions = spline->positions();
+
+ switch (mode) {
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE:
+ create_rectangle_curve(positions,
+ std::max(params.extract_input<float>("Height"), 0.0f),
+ std::max(params.extract_input<float>("Width"), 0.0f));
+ break;
+
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM:
+ create_parallelogram_curve(positions,
+ std::max(params.extract_input<float>("Height"), 0.0f),
+ std::max(params.extract_input<float>("Width"), 0.0f),
+ params.extract_input<float>("Offset"));
+ break;
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID:
+ create_trapezoid_curve(positions,
+ std::max(params.extract_input<float>("Bottom Width"), 0.0f),
+ std::max(params.extract_input<float>("Top Width"), 0.0f),
+ params.extract_input<float>("Offset"),
+ std::max(params.extract_input<float>("Height"), 0.0f));
+ break;
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE:
+ create_kite_curve(positions,
+ std::max(params.extract_input<float>("Width"), 0.0f),
+ std::max(params.extract_input<float>("Bottom Height"), 0.0f),
+ params.extract_input<float>("Top Height"));
+ break;
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS:
+ create_points_curve(positions,
+ params.extract_input<float3>("Point 1"),
+ params.extract_input<float3>("Point 2"),
+ params.extract_input<float3>("Point 3"),
+ params.extract_input<float3>("Point 4"));
+ break;
+ default:
+ params.set_output("Curve", GeometrySet());
+ return;
+ }
+
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_primitive_quadrilateral()
+{
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype,
+ geo_node_curve_primitive_quadrilateral_in,
+ geo_node_curve_primitive_quadrilateral_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec;
+ ntype.draw_buttons = geo_node_curve_primitive_quadrilateral_layout;
+ node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update);
+ node_type_init(&ntype, geo_node_curve_primitive_quadrilateral_init);
+ node_type_storage(&ntype,
+ "NodeGeometryCurvePrimitiveQuad",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ 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
index 3de2604cd0a..7908c26e2dc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -116,38 +116,6 @@ static void subdivide_attribute(Span<T> src,
}
/**
- * 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.
@@ -171,6 +139,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
{
const bool is_last_cyclic_segment = index == (src.size() - 1);
const int next_index = is_last_cyclic_segment ? 0 : index + 1;
+
+ /* The first point in the segment is always copied. */
+ dst_positions[offset] = src_positions[index];
+
if (src.segment_is_vector(index)) {
if (is_last_cyclic_segment) {
dst_type_left.first() = BezierSpline::HandleType::Vector;
@@ -178,7 +150,6 @@ static void subdivide_bezier_segment(const BezierSpline &src,
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;
@@ -194,21 +165,38 @@ static void subdivide_bezier_segment(const BezierSpline &src,
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];
+
+ /* Create a Bezier segment to update iteratively for every subdivision
+ * and references to the meaningful values for ease of use. */
+ BezierSpline temp;
+ temp.resize(2);
+ float3 &segment_start = temp.positions().first();
+ float3 &segment_end = temp.positions().last();
+ float3 &handle_prev = temp.handle_positions_right().first();
+ float3 &handle_next = temp.handle_positions_left().last();
+ segment_start = src_positions[index];
+ segment_end = src_positions[next_index];
+ handle_prev = src_handles_right[index];
+ handle_next = 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);
+ const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter);
+
+ /* Copy relevant temporary data to the result. */
+ dst_handles_right[offset + cut] = insert.handle_prev;
+ dst_handles_left[offset + cut + 1] = insert.left_handle;
+ dst_positions[offset + cut + 1] = insert.position;
+
+ /* Update the segment to prepare it for the next subdivision. */
+ segment_start = insert.position;
+ handle_prev = insert.right_handle;
+ handle_next = insert.handle_next;
}
+
+ /* Copy the handles for the last segment from the temporary spline. */
+ dst_handles_right[offset + result_size - 1] = handle_prev;
+ dst_handles_left[i_segment_last] = handle_next;
}
}
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 b1da2dcd3c4..8c697275f88 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -627,7 +627,7 @@ static void delete_mesh_selection(MeshComponent &component,
mesh_out = nullptr;
break;
}
- component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+ component.replace(mesh_out);
}
static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index 7492582c8cf..245d7800621 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -91,7 +91,7 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
BKE_mesh_calc_normals(mesh_out);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+ mesh_component.replace(mesh_out);
BKE_subdiv_free(subdiv);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 20ffcdb516d..f0f032ed8f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -96,7 +96,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
BKE_mesh_calc_normals(mesh_out);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+ mesh_component.replace(mesh_out);
// BKE_subdiv_stats_print(&subdiv->stats);
BKE_subdiv_free(subdiv);
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
new file mode 100644
index 00000000000..3024cc51cad
--- /dev/null
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -0,0 +1,361 @@
+/*
+ * 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 "NOD_geometry_nodes_eval_log.hh"
+
+#include "BKE_geometry_set_instances.hh"
+
+#include "DNA_modifier_types.h"
+#include "DNA_space_types.h"
+
+namespace blender::nodes::geometry_nodes_eval_log {
+
+using fn::CPPType;
+
+ModifierLog::ModifierLog(GeoLogger &logger)
+{
+ root_tree_logs_ = allocator_.construct<TreeLog>();
+
+ LogByTreeContext log_by_tree_context;
+
+ /* Combine all the local loggers that have been used by separate threads. */
+ for (LocalGeoLogger &local_logger : logger) {
+ /* Take ownership of the allocator. */
+ logger_allocators_.append(std::move(local_logger.allocator_));
+
+ for (ValueOfSockets &value_of_sockets : local_logger.values_) {
+ ValueLog *value_log = value_of_sockets.value.get();
+
+ /* Take centralized ownership of the logged value. It might be referenced by multiple
+ * sockets. */
+ logged_values_.append(std::move(value_of_sockets.value));
+
+ for (const DSocket &socket : value_of_sockets.sockets) {
+ SocketLog &socket_log = this->lookup_or_add_socket_log(log_by_tree_context, socket);
+ socket_log.value_ = value_log;
+ }
+ }
+
+ for (NodeWithWarning &node_with_warning : local_logger.node_warnings_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_warning.node);
+ node_log.warnings_.append(node_with_warning.warning);
+ }
+ }
+}
+
+TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context,
+ const DTreeContext &tree_context)
+{
+ TreeLog *tree_log = log_by_tree_context.lookup_default(&tree_context, nullptr);
+ if (tree_log != nullptr) {
+ return *tree_log;
+ }
+
+ const DTreeContext *parent_context = tree_context.parent_context();
+ if (parent_context == nullptr) {
+ return *root_tree_logs_.get();
+ }
+ TreeLog &parent_log = this->lookup_or_add_tree_log(log_by_tree_context, *parent_context);
+ destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>();
+ tree_log = owned_tree_log.get();
+ log_by_tree_context.add_new(&tree_context, tree_log);
+ parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log));
+ return *tree_log;
+}
+
+NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node)
+{
+ TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context());
+ NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() {
+ destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>();
+ node_log->input_logs_.resize(node->inputs().size());
+ node_log->output_logs_.resize(node->outputs().size());
+ return node_log;
+ });
+ return node_log;
+}
+
+SocketLog &ModifierLog::lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context,
+ DSocket socket)
+{
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, socket.node());
+ MutableSpan<SocketLog> socket_logs = socket->is_input() ? node_log.input_logs_ :
+ node_log.output_logs_;
+ SocketLog &socket_log = socket_logs[socket->index()];
+ return socket_log;
+}
+
+const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const
+{
+ const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name);
+ if (node_log == nullptr) {
+ return nullptr;
+ }
+ return node_log->get();
+}
+
+const NodeLog *TreeLog::lookup_node_log(const bNode &node) const
+{
+ return this->lookup_node_log(node.name);
+}
+
+const TreeLog *TreeLog::lookup_child_log(StringRef node_name) const
+{
+ const destruct_ptr<TreeLog> *tree_log = child_logs_.lookup_ptr_as(node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ return tree_log->get();
+}
+
+const SocketLog *NodeLog::lookup_socket_log(eNodeSocketInOut in_out, int index) const
+{
+ BLI_assert(index >= 0);
+ Span<SocketLog> socket_logs = (in_out == SOCK_IN) ? input_logs_ : output_logs_;
+ if (index >= socket_logs.size()) {
+ return nullptr;
+ }
+ return &socket_logs[index];
+}
+
+const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket &socket) const
+{
+ ListBase sockets = socket.in_out == SOCK_IN ? node.inputs : node.outputs;
+ int index = BLI_findindex(&sockets, &socket);
+ return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index);
+}
+
+GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
+{
+ bke::geometry_set_instances_attribute_foreach(
+ geometry_set,
+ [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
+ this->attributes_.append({attribute_name, meta_data.domain, meta_data.data_type});
+ return true;
+ },
+ 8);
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ component_types_.append(component->type());
+ switch (component->type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &mesh_component = *(const MeshComponent *)component;
+ MeshInfo &info = this->mesh_info.emplace();
+ info.tot_verts = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ info.tot_edges = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ info.tot_faces = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const CurveComponent &curve_component = *(const CurveComponent *)component;
+ CurveInfo &info = this->curve_info.emplace();
+ info.tot_splines = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component;
+ PointCloudInfo &info = this->pointcloud_info.emplace();
+ info.tot_points = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const InstancesComponent &instances_component = *(const InstancesComponent *)component;
+ InstancesInfo &info = this->instances_info.emplace();
+ info.tot_instances = instances_component.instances_amount();
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ break;
+ }
+ }
+ }
+ if (log_full_geometry) {
+ full_geometry_ = std::make_unique<GeometrySet>(geometry_set);
+ full_geometry_->ensure_owns_direct_data();
+ }
+}
+
+Vector<const GeometryAttributeInfo *> NodeLog::lookup_available_attributes() const
+{
+ Vector<const GeometryAttributeInfo *> attributes;
+ Set<StringRef> names;
+ for (const SocketLog &socket_log : input_logs_) {
+ const ValueLog *value_log = socket_log.value();
+ if (const GeometryValueLog *geo_value_log = dynamic_cast<const GeometryValueLog *>(
+ value_log)) {
+ for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) {
+ if (names.add(attribute.name)) {
+ attributes.append(&attribute);
+ }
+ }
+ }
+ }
+ return attributes;
+}
+
+const ModifierLog *ModifierLog::find_root_by_node_editor_context(const SpaceNode &snode)
+{
+ if (snode.id == nullptr) {
+ return nullptr;
+ }
+ if (GS(snode.id->name) != ID_OB) {
+ return nullptr;
+ }
+ Object *object = (Object *)snode.id;
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == snode.nodetree) {
+ return (ModifierLog *)nmd->runtime_eval_log;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const TreeLog *ModifierLog::find_tree_by_node_editor_context(const SpaceNode &snode)
+{
+ const ModifierLog *eval_log = ModifierLog::find_root_by_node_editor_context(snode);
+ if (eval_log == nullptr) {
+ return nullptr;
+ }
+ Vector<bNodeTreePath *> tree_path_vec = snode.treepath;
+ if (tree_path_vec.is_empty()) {
+ return nullptr;
+ }
+ TreeLog *current = eval_log->root_tree_logs_.get();
+ for (bNodeTreePath *path : tree_path_vec.as_span().drop_front(1)) {
+ destruct_ptr<TreeLog> *tree_log = current->child_logs_.lookup_ptr_as(path->node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ current = tree_log->get();
+ }
+ return current;
+}
+
+const NodeLog *ModifierLog::find_node_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node)
+{
+ const TreeLog *tree_log = ModifierLog::find_tree_by_node_editor_context(snode);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ return tree_log->lookup_node_log(node);
+}
+
+const SocketLog *ModifierLog::find_socket_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node,
+ const bNodeSocket &socket)
+{
+ const NodeLog *node_log = ModifierLog::find_node_by_node_editor_context(snode, node);
+ if (node_log == nullptr) {
+ return nullptr;
+ }
+ return node_log->lookup_socket_log(node, socket);
+}
+
+const NodeLog *ModifierLog::find_node_by_spreadsheet_editor_context(
+ const SpaceSpreadsheet &sspreadsheet)
+{
+ Vector<SpreadsheetContext *> context_path = sspreadsheet.context_path;
+ if (context_path.size() <= 2) {
+ return nullptr;
+ }
+ if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
+ return nullptr;
+ }
+ if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
+ return nullptr;
+ }
+ for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
+ if (context->type != SPREADSHEET_CONTEXT_NODE) {
+ return nullptr;
+ }
+ }
+ Span<SpreadsheetContextNode *> node_contexts =
+ context_path.as_span().drop_front(2).cast<SpreadsheetContextNode *>();
+
+ Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
+ StringRefNull modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
+ if (object == nullptr) {
+ return nullptr;
+ }
+
+ const ModifierLog *eval_log = nullptr;
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ if (md->name == modifier_name) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ eval_log = (const ModifierLog *)nmd->runtime_eval_log;
+ break;
+ }
+ }
+ }
+ if (eval_log == nullptr) {
+ return nullptr;
+ }
+
+ const TreeLog *tree_log = &eval_log->root_tree();
+ for (SpreadsheetContextNode *context : node_contexts.drop_back(1)) {
+ tree_log = tree_log->lookup_child_log(context->node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ }
+ const NodeLog *node_log = tree_log->lookup_node_log(node_contexts.last()->node_name);
+ return node_log;
+}
+
+void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value)
+{
+ const CPPType &type = *value.type();
+ Span<DSocket> copied_sockets = allocator_->construct_array_copy(sockets);
+ if (type.is<GeometrySet>()) {
+ bool log_full_geometry = false;
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_geometry_sockets_.contains(socket)) {
+ log_full_geometry = true;
+ break;
+ }
+ }
+
+ const GeometrySet &geometry_set = *value.get<GeometrySet>();
+ destruct_ptr<GeometryValueLog> value_log = allocator_->construct<GeometryValueLog>(
+ geometry_set, log_full_geometry);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ else {
+ void *buffer = allocator_->allocate(type.size(), type.alignment());
+ type.copy_construct(value.get(), buffer);
+ destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>(
+ GMutablePointer{type, buffer});
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+}
+
+void LocalGeoLogger::log_multi_value_socket(DSocket socket, Span<GPointer> values)
+{
+ /* Doesn't have to be logged currently. */
+ UNUSED_VARS(socket, values);
+}
+
+void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::string message)
+{
+ node_warnings_.append({node, {type, std::move(message)}});
+}
+
+} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 17a13f2d1b0..bfd1ad02d36 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -16,8 +16,6 @@
#include "DNA_modifier_types.h"
-#include "BKE_node_ui_storage.hh"
-
#include "DEG_depsgraph_query.h"
#include "NOD_geometry_exec.hh"
@@ -26,21 +24,17 @@
#include "node_geometry_util.hh"
+using blender::nodes::geometry_nodes_eval_log::LocalGeoLogger;
+
namespace blender::nodes {
void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
{
- bNodeTree *btree_cow = provider_->dnode->btree();
- BLI_assert(btree_cow != nullptr);
- if (btree_cow == nullptr) {
+ if (provider_->logger == nullptr) {
return;
}
- bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
-
- const NodeTreeEvaluationContext context(*provider_->self_object, *provider_->modifier);
-
- BKE_nodetree_error_message_add(
- *btree_original, context, *provider_->dnode->bnode(), type, std::move(message));
+ LocalGeoLogger &local_logger = provider_->logger->local();
+ local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index bed4d60382d..9ce9d6fc273 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -461,7 +461,7 @@ bool NodeTreeRef::has_undefined_nodes_or_sockets() const
return true;
}
}
- return true;
+ return false;
}
std::string NodeTreeRef::to_dot() const
diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c
index edcec486398..cfef20e2e4d 100644
--- a/source/blender/python/gpu/gpu_py_uniformbuffer.c
+++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c
@@ -104,7 +104,7 @@ static PyObject *pygpu_uniformbuffer__tp_new(PyTypeObject *UNUSED(self),
}
PyDoc_STRVAR(pygpu_uniformbuffer_update_doc,
- ".. method::update(data)\n"
+ ".. method:: update(data)\n"
"\n"
" Update the data of the uniform buffer object.\n");
static PyObject *pygpu_uniformbuffer_update(BPyGPUUniformBuf *self, PyObject *obj)
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index e6479df2fa8..a8ab54ac3bb 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4253,6 +4253,56 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self)
return ret;
}
+PyDoc_STRVAR(pyrna_struct_id_properties_ensure_doc,
+ ".. method:: id_properties_ensure()\n"
+ " :return: the parent group for an RNA struct's custom IDProperties.\n"
+ " :rtype: :class:`bpy.types.IDPropertyGroup`\n");
+static PyObject *pyrna_struct_id_properties_ensure(BPy_StructRNA *self)
+{
+ PYRNA_STRUCT_CHECK_OBJ(self);
+
+ if (RNA_struct_idprops_check(self->ptr.type) == 0) {
+ PyErr_SetString(PyExc_TypeError, "This type doesn't support IDProperties");
+ return NULL;
+ }
+
+ IDProperty *idprops = RNA_struct_idprops(&self->ptr, true);
+
+ /* This is a paranoid check that theoretically might not be necessary.
+ * It allows the possibility that some structs can't ensure IDProperties. */
+ if (idprops == NULL) {
+ return Py_None;
+ }
+
+ BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
+ group->owner_id = self->ptr.owner_id;
+ group->prop = idprops;
+ group->parent = NULL;
+ return (PyObject *)group;
+}
+
+PyDoc_STRVAR(pyrna_struct_id_properties_clear_doc,
+ ".. method:: id_properties_clear()\n"
+ " :return: Remove the parent group for an RNA struct's custom IDProperties.\n");
+static PyObject *pyrna_struct_id_properties_clear(BPy_StructRNA *self)
+{
+ PYRNA_STRUCT_CHECK_OBJ(self);
+
+ if (RNA_struct_idprops_check(self->ptr.type) == 0) {
+ PyErr_SetString(PyExc_TypeError, "This type doesn't support IDProperties");
+ return NULL;
+ }
+
+ IDProperty **idprops = RNA_struct_idprops_p(&self->ptr);
+
+ if (*idprops) {
+ IDP_FreeProperty(*idprops);
+ *idprops = NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
/* ---------------getattr-------------------------------------------- */
static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
{
@@ -5743,6 +5793,14 @@ static struct PyMethodDef pyrna_struct_methods[] = {
METH_VARARGS | METH_CLASS,
pyrna_struct_bl_rna_get_subclass_doc},
{"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL},
+ {"id_properties_ensure",
+ (PyCFunction)pyrna_struct_id_properties_ensure,
+ METH_NOARGS,
+ pyrna_struct_id_properties_ensure_doc},
+ {"id_properties_clear",
+ (PyCFunction)pyrna_struct_id_properties_clear,
+ METH_NOARGS,
+ pyrna_struct_id_properties_clear_doc},
/* experimental */
/* unused for now */
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index ac061c3dd60..66044311321 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -130,7 +130,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d
}
PyDoc_STRVAR(bpy_user_map_doc,
- ".. method:: user_map([subset=(id1, id2, ...)], key_types={..}, value_types={..})\n"
+ ".. method:: user_map(subset, key_types, value_types)\n"
"\n"
" Returns a mapping of all ID data-blocks in current ``bpy.data`` to a set of all "
"datablocks using them.\n"
@@ -277,7 +277,7 @@ error:
}
PyDoc_STRVAR(bpy_batch_remove_doc,
- ".. method:: batch_remove(ids=(id1, id2, ...))\n"
+ ".. method:: batch_remove(ids)\n"
"\n"
" Remove (delete) several IDs at once.\n"
"\n"
diff --git a/source/blender/python/intern/bpy_utils_previews.c b/source/blender/python/intern/bpy_utils_previews.c
index 7a826d99a3d..6a46d2a1a96 100644
--- a/source/blender/python/intern/bpy_utils_previews.c
+++ b/source/blender/python/intern/bpy_utils_previews.c
@@ -59,7 +59,6 @@ PyDoc_STRVAR(
" :type name: string\n"
" :return: The Preview matching given name, or a new empty one.\n"
" :rtype: :class:`bpy.types.ImagePreview`\n"
- " :rtype: :class:`bpy.types.ImagePreview`\n"
/* This is only true when accessed via 'bpy.utils.previews.ImagePreviewCollection.load',
* however this is the public API, allow this minor difference to the internal version here. */
" :raises KeyError: if ``name`` already exists.");
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 4ad0264582f..c2223b023ad 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -149,7 +149,7 @@ static PyObject *C_Vector_Fill(PyObject *cls, PyObject *args)
}
PyDoc_STRVAR(C_Vector_Range_doc,
- ".. classmethod:: Range(start=0, stop, step=1)\n"
+ ".. classmethod:: Range(start, stop, step=1)\n"
"\n"
" Create a filled with a range of values.\n"
"\n"
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index fd65bb12044..d5653f87c2b 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -340,10 +340,10 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
float co_high[3], dir_high[3];
hits[i].index = -1;
- /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+ /* TODO: we should use FLT_MAX here, but sweep-sphere code isn't prepared for that. */
hits[i].dist = BVH_RAYCAST_DIST_MAX;
- /* transform the ray from the world space to the highpoly space */
+ /* Transform the ray from the world space to the `highpoly` space. */
mul_v3_m4v3(co_high, highpoly[i].imat, co);
/* rotates */
@@ -555,10 +555,10 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
TriTessFace *tris_cage = NULL;
TriTessFace **tris_high;
- /* assume all lowpoly tessfaces can be quads */
+ /* Assume all low-poly tessfaces can be quads. */
tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array");
- /* assume all highpoly tessfaces are triangles */
+ /* Assume all high-poly tessfaces are triangles. */
me_highpoly = MEM_mallocN(sizeof(Mesh *) * tot_highpoly, "Highpoly Derived Meshes");
treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees");
@@ -583,7 +583,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
BKE_mesh_runtime_looptri_ensure(me_highpoly[i]);
if (me_highpoly[i]->runtime.looptris.len != 0) {
- /* Create a BVH-tree for each highpoly object. */
+ /* Create a BVH-tree for each `highpoly` object. */
BKE_bvhtree_from_mesh_get(&treeData[i], me_highpoly[i], BVHTREE_FROM_LOOPTRI, 2);
if (treeData[i].tree == NULL) {
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index 86ed88d37ab..657cd1f606b 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -679,7 +679,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
DRW_render_context_enable(engine->re);
}
- DEG_evaluate_on_framechange(depsgraph, CFRA);
+ DEG_evaluate_on_framechange(depsgraph, BKE_scene_frame_get(scene));
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index bc03158f036..6329901b4ce 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -1828,7 +1828,7 @@ void RE_SetReports(Render *re, ReportList *reports)
static void render_update_depsgraph(Render *re)
{
Scene *scene = re->scene;
- DEG_evaluate_on_framechange(re->pipeline_depsgraph, CFRA);
+ DEG_evaluate_on_framechange(re->pipeline_depsgraph, BKE_scene_frame_get(scene));
BKE_scene_update_sound(re->pipeline_depsgraph, re->main);
}
@@ -2410,7 +2410,7 @@ void RE_RenderAnim(Render *re,
* -sergey-
*/
{
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
AnimData *adt = BKE_animdata_from_id(&scene->id);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
re->pipeline_depsgraph, ctime);
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index c0ff00d4f59..31d5bf67f28 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -169,7 +169,7 @@ static void pointdensity_cache_psys(
ParticleCacheKey *cache;
ParticleSimulationData sim = {NULL};
ParticleData *pa = NULL;
- float cfra = BKE_scene_frame_get(scene);
+ float cfra = BKE_scene_ctime_get(scene);
int i /*, Childexists*/ /* UNUSED */;
int total_particles;
int data_used;
@@ -347,9 +347,9 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
if (!mdef) {
return;
}
- mdef_index = BKE_object_defgroup_name_index(ob, pd->vertex_attribute_name);
+ mdef_index = BKE_id_defgroup_name_index(&mesh->id, pd->vertex_attribute_name);
if (mdef_index < 0) {
- mdef_index = ob->actdef - 1;
+ mdef_index = BKE_object_defgroup_active_index_get(ob) - 1;
}
if (mdef_index < 0) {
return;
@@ -782,7 +782,7 @@ static void particle_system_minmax(Depsgraph *depsgraph,
float max[3])
{
const float size[3] = {radius, radius, radius};
- const float cfra = BKE_scene_frame_get(scene);
+ const float cfra = BKE_scene_ctime_get(scene);
ParticleSettings *part = psys->part;
ParticleSimulationData sim = {NULL};
ParticleData *pa = NULL;
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index 9340cfbf03d..e324bc8b407 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -77,9 +77,9 @@ set(SRC
intern/proxy_job.c
intern/render.c
intern/render.h
+ intern/sequence_lookup.c
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_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h
index 4b2bf69a8ac..ea7f01e6ae3 100644
--- a/source/blender/sequencer/SEQ_clipboard.h
+++ b/source/blender/sequencer/SEQ_clipboard.h
@@ -29,12 +29,16 @@ extern "C" {
struct ListBase;
struct Main;
+struct Scene;
+struct Sequence;
extern struct ListBase seqbase_clipboard;
extern int seqbase_clipboard_frame;
void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void SEQ_clipboard_free(void);
+void SEQ_clipboard_active_seq_name_store(struct Scene *scene);
+bool SEQ_clipboard_pasted_seq_was_active(struct Sequence *pasted_seq);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c
index e3f82dd4bb0..9e702a4e60b 100644
--- a/source/blender/sequencer/intern/clipboard.c
+++ b/source/blender/sequencer/intern/clipboard.c
@@ -24,6 +24,8 @@
* \ingroup bke
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
@@ -31,6 +33,7 @@
#include "DNA_sound_types.h"
#include "BLI_listbase.h"
+#include "BLI_string.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
@@ -38,6 +41,7 @@
#include "BKE_sound.h"
#include "SEQ_clipboard.h"
+#include "SEQ_select.h"
#include "sequencer.h"
@@ -55,6 +59,7 @@
ListBase seqbase_clipboard;
int seqbase_clipboard_frame;
+static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR];
void seq_clipboard_pointers_free(struct ListBase *seqbase);
@@ -177,3 +182,26 @@ void SEQ_clipboard_pointers_restore(ListBase *seqbase, Main *bmain)
SEQ_clipboard_pointers_restore(&seq->seqbase, bmain);
}
}
+
+void SEQ_clipboard_active_seq_name_store(Scene *scene)
+{
+ Sequence *active_seq = SEQ_select_active_get(scene);
+ if (active_seq != NULL) {
+ STRNCPY(seq_clipboard_active_seq_name, active_seq->name);
+ }
+ else {
+ seq_clipboard_active_seq_name[0] = '\0';
+ }
+}
+
+/**
+ * Check if strip was active when it was copied. User should restrict this check to pasted strips
+ * before ensuring original name, because strip name comparison is used to check.
+ *
+ * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
+ * \return true if strip was active, false otherwise
+ */
+bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq)
+{
+ return STREQ(pasted_seq->name, seq_clipboard_active_seq_name);
+}
diff --git a/tests/performance/api/graph.py b/tests/performance/api/graph.py
index eb411915ad9..b3c8329ff27 100644
--- a/tests/performance/api/graph.py
+++ b/tests/performance/api/graph.py
@@ -39,15 +39,24 @@ class TestGraph:
else:
categories[category] = [entry]
- # Generate one graph for every device x category combination.
+ # Generate one graph for every device x category x result key combination.
for category, category_entries in categories.items():
entries = sorted(category_entries, key=lambda entry: (entry.revision, entry.test))
+
+ outputs = set()
+ for entry in entries:
+ for output in entry.output.keys():
+ outputs.add(output)
+
chart_type = 'line' if entries[0].benchmark_type == 'time_series' else 'comparison'
- data.append(self.chart(device_name, category, entries, chart_type))
+
+ for output in outputs:
+ chart_name = f"{category} ({output})"
+ data.append(self.chart(device_name, chart_name, entries, chart_type, output))
self.json = json.dumps(data, indent=2)
- def chart(self, device_name: str, category: str, entries: List, chart_type: str) -> Dict:
+ def chart(self, device_name: str, chart_name: str, entries: List, chart_type: str, output: str) -> Dict:
# Gather used tests.
tests = {}
for entry in entries:
@@ -71,7 +80,7 @@ class TestGraph:
if chart_type == 'line':
cols.append({'id': '', 'label': 'Date', 'type': 'date'})
else:
- cols.append({'id': '', 'label': 'Revision', 'type': 'string'})
+ cols.append({'id': '', 'label': ' ', 'type': 'string'})
for test, test_index in tests.items():
cols.append({'id': '', 'label': test, 'type': 'number'})
@@ -88,11 +97,11 @@ class TestGraph:
for entry in entries:
test_index = tests[entry.test]
revision_index = revisions[entry.revision]
- time = entry.output['time']
+ time = entry.output[output] if output in entry.output else -1.0
rows[revision_index]['c'][test_index + 1] = {'f': None, 'v': time}
data = {'cols': cols, 'rows': rows}
- return {'device': device_name, 'category': category, 'data': data, 'chart_type': chart_type}
+ return {'device': device_name, 'name': chart_name, 'data': data, 'chart_type': chart_type}
def write(self, filepath: pathlib.Path) -> None:
# Write HTML page with JSON graph data embedded.
diff --git a/tests/performance/api/graph.template.html b/tests/performance/api/graph.template.html
index 8929c2bdd1b..147f1628c23 100644
--- a/tests/performance/api/graph.template.html
+++ b/tests/performance/api/graph.template.html
@@ -52,7 +52,7 @@
/* Chart drawing options. */
var options = {
- chart: {title: device["category"], subtitle: device['device']},
+ chart: {title: device["name"], subtitle: device['device']},
pointsVisible: true,
pointSize: 2.5,
height: 500,
diff --git a/tests/performance/tests/cycles.py b/tests/performance/tests/cycles.py
index f79e7333458..bac6b8a7ceb 100644
--- a/tests/performance/tests/cycles.py
+++ b/tests/performance/tests/cycles.py
@@ -65,16 +65,26 @@ class CyclesTest(api.Test):
_, lines = env.run_in_blender(_run, args, ['--debug-cycles', '--verbose', '1', self.filepath])
# Parse render time from output
- prefix = "Render time (without synchronization): "
- time = 0.0
+ prefix_time = "Render time (without synchronization): "
+ prefix_memory = "Peak: "
+ time = None
+ memory = None
for line in lines:
line = line.strip()
- offset = line.find(prefix)
+ offset = line.find(prefix_time)
if offset != -1:
- time = line[offset + len(prefix):]
- return {'time': float(time)}
+ time = line[offset + len(prefix_time):]
+ time = float(time)
+ offset = line.find(prefix_memory)
+ if offset != -1:
+ memory = line[offset + len(prefix_memory):]
+ memory = memory.split()[0].replace(',', '')
+ memory = float(memory)
+
+ if not (time and memory):
+ raise Exception("Error parsing render time output")
- raise Exception("Error parsing render time output")
+ return {'time': time, 'peak_memory': memory}
def generate(env):
diff --git a/tests/python/bl_run_operators_event_simulate.py b/tests/python/bl_run_operators_event_simulate.py
index 92315d3e853..1cc621b9684 100644
--- a/tests/python/bl_run_operators_event_simulate.py
+++ b/tests/python/bl_run_operators_event_simulate.py
@@ -165,6 +165,16 @@ def gen_events_type_text(text):
yield dict(type=type, value='RELEASE', **kw_extra)
+def repr_action(name, args, kwargs):
+ return "%s(%s)" % (
+ name,
+ ", ".join(
+ [repr(value) for value in args] +
+ [("%s=%r" % (key, value)) for key, value in kwargs.items()]
+ )
+ )
+
+
# -----------------------------------------------------------------------------
# Simulate Events
@@ -505,6 +515,18 @@ def argparse_create():
required=False,
)
+ parser.add_argument(
+ "--time-actions",
+ dest="time_actions",
+ default=False,
+ action="store_true",
+ help=(
+ "Display the time each action takes\n"
+ "(useful for measuring delay between key-presses)."
+ ),
+ required=False,
+ )
+
# Collect doc-strings from static methods in `actions`.
actions_docstring = []
for action_key in ACTION_DIR:
@@ -554,7 +576,7 @@ def setup_default_preferences(prefs):
# Main Function
-def main_event_iter(*, action_list):
+def main_event_iter(*, action_list, time_actions):
"""
Yield all events from action handlers.
"""
@@ -565,9 +587,18 @@ def main_event_iter(*, action_list):
yield dict(type='MOUSEMOVE', value='NOTHING', x=x_init, y=y_init)
+ if time_actions:
+ import time
+ t_prev = time.time()
+
for (op, args, kwargs) in action_list:
yield from handle_action(op, args, kwargs)
+ if time_actions:
+ t = time.time()
+ print("%.4f: %s" % ((t - t_prev), repr_action(op, args, kwargs)))
+ t_prev = t
+
def main():
from sys import argv
@@ -588,7 +619,7 @@ def main():
bpy.app.use_event_simulate = False
run_event_simulate(
- event_iter=main_event_iter(action_list=args.actions),
+ event_iter=main_event_iter(action_list=args.actions, time_actions=args.time_actions),
exit_fn=exit_fn,
)
diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py
index c1ae0b05fcd..560f8e33585 100755
--- a/tests/python/modules/render_report.py
+++ b/tests/python/modules/render_report.py
@@ -287,7 +287,7 @@ class Report:
-moz-background-size:50px 50px;
background-size:50px 50px;
- -webkit-background-size:50px 51px; /* override value for shitty webkit */
+ -webkit-background-size:50px 51px; /* Override value for silly webkit. */
background-position:0 0, 25px 0, 25px -25px, 0px 25px;
}}