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:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c25
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c21
-rw-r--r--source/blender/editors/animation/anim_deps.c3
-rw-r--r--source/blender/editors/animation/anim_draw.c33
-rw-r--r--source/blender/editors/animation/anim_filter.c22
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c1
-rw-r--r--source/blender/editors/animation/anim_markers.c130
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c8
-rw-r--r--source/blender/editors/animation/anim_ops.c18
-rw-r--r--source/blender/editors/animation/drivers.c3
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c2
-rw-r--r--source/blender/editors/animation/keyframes_edit.c17
-rw-r--r--source/blender/editors/animation/keyframes_general.c110
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc7
-rw-r--r--source/blender/editors/animation/keyframing.c39
-rw-r--r--source/blender/editors/animation/keyingsets.c3
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c6
-rw-r--r--source/blender/editors/armature/CMakeLists.txt1
-rw-r--r--source/blender/editors/armature/armature_add.c6
-rw-r--r--source/blender/editors/armature/armature_naming.c12
-rw-r--r--source/blender/editors/armature/armature_relations.c5
-rw-r--r--source/blender/editors/armature/armature_select.c15
-rw-r--r--source/blender/editors/armature/armature_skinning.c8
-rw-r--r--source/blender/editors/armature/editarmature_undo.c2
-rw-r--r--source/blender/editors/armature/meshlaplacian.c30
-rw-r--r--source/blender/editors/armature/pose_group.c1
-rw-r--r--source/blender/editors/armature/pose_lib.c12
-rw-r--r--source/blender/editors/armature/pose_lib_2.c2
-rw-r--r--source/blender/editors/armature/pose_select.c8
-rw-r--r--source/blender/editors/armature/pose_slide.c11
-rw-r--r--source/blender/editors/armature/pose_transform.c6
-rw-r--r--source/blender/editors/armature/pose_utils.c1
-rw-r--r--source/blender/editors/asset/ED_asset_list.h2
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc16
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference_enum.cc6
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc7
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc2
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/editcurve.c414
-rw-r--r--source/blender/editors/curve/editcurve_add.c5
-rw-r--r--source/blender/editors/curve/editcurve_paint.c2
-rw-r--r--source/blender/editors/curve/editcurve_pen.c2
-rw-r--r--source/blender/editors/curve/editcurve_select.c60
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont.c66
-rw-r--r--source/blender/editors/curve/editfont_undo.c3
-rw-r--r--source/blender/editors/curves/CMakeLists.txt14
-rw-r--r--source/blender/editors/curves/intern/curves_add.cc99
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc543
-rw-r--r--source/blender/editors/geometry/CMakeLists.txt1
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc36
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c8
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c6
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt2
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c8
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c27
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c47
-rw-r--r--source/blender/editors/gpencil/gpencil_add_blank.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_lineart.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_bake_animation.cc8
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c13
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c437
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c21
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.cc4
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c103
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c30
-rw-r--r--source/blender/editors/include/ED_anim_api.h7
-rw-r--r--source/blender/editors/include/ED_clip.h40
-rw-r--r--source/blender/editors/include/ED_curves.h13
-rw-r--r--source/blender/editors/include/ED_curves_sculpt.h25
-rw-r--r--source/blender/editors/include/ED_fileselect.h8
-rw-r--r--source/blender/editors/include/ED_gpencil.h12
-rw-r--r--source/blender/editors/include/ED_image.h31
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h23
-rw-r--r--source/blender/editors/include/ED_mask.h29
-rw-r--r--source/blender/editors/include/ED_mesh.h44
-rw-r--r--source/blender/editors/include/ED_paint.h7
-rw-r--r--source/blender/editors/include/ED_screen.h3
-rw-r--r--source/blender/editors/include/ED_sculpt.h11
-rw-r--r--source/blender/editors/include/ED_select_utils.h8
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h47
-rw-r--r--source/blender/editors/include/ED_types.h27
-rw-r--r--source/blender/editors/include/ED_uvedit.h45
-rw-r--r--source/blender/editors/include/ED_view3d.h36
-rw-r--r--source/blender/editors/include/UI_abstract_view.hh280
-rw-r--r--source/blender/editors/include/UI_grid_view.hh55
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h94
-rw-r--r--source/blender/editors/include/UI_interface.hh6
-rw-r--r--source/blender/editors/include/UI_resources.h2
-rw-r--r--source/blender/editors/include/UI_tree_view.hh181
-rw-r--r--source/blender/editors/include/UI_view2d.h31
-rw-r--r--source/blender/editors/interface/CMakeLists.txt41
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_color.c (renamed from source/blender/editors/interface/interface_eyedropper_color.c)4
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_colorband.c (renamed from source/blender/editors/interface/interface_eyedropper_colorband.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_datablock.c (renamed from source/blender/editors/interface/interface_eyedropper_datablock.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_depth.c (renamed from source/blender/editors/interface/interface_eyedropper_depth.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_driver.c (renamed from source/blender/editors/interface/interface_eyedropper_driver.c)7
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.c (renamed from source/blender/editors/interface/interface_eyedropper_gpencil_color.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_intern.h (renamed from source/blender/editors/interface/interface_eyedropper_intern.h)4
-rw-r--r--source/blender/editors/interface/eyedroppers/interface_eyedropper.c (renamed from source/blender/editors/interface/interface_eyedropper.c)2
-rw-r--r--source/blender/editors/interface/interface.cc95
-rw-r--r--source/blender/editors/interface/interface_anim.cc (renamed from source/blender/editors/interface/interface_anim.c)57
-rw-r--r--source/blender/editors/interface/interface_context_menu.c18
-rw-r--r--source/blender/editors/interface/interface_drag.cc8
-rw-r--r--source/blender/editors/interface/interface_draw.c44
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc32
-rw-r--r--source/blender/editors/interface/interface_handlers.c148
-rw-r--r--source/blender/editors/interface/interface_icons.c10
-rw-r--r--source/blender/editors/interface/interface_icons_event.c100
-rw-r--r--source/blender/editors/interface/interface_intern.h40
-rw-r--r--source/blender/editors/interface/interface_layout.c7
-rw-r--r--source/blender/editors/interface/interface_ops.cc (renamed from source/blender/editors/interface/interface_ops.c)640
-rw-r--r--source/blender/editors/interface/interface_panel.cc (renamed from source/blender/editors/interface/interface_panel.c)363
-rw-r--r--source/blender/editors/interface/interface_query.cc32
-rw-r--r--source/blender/editors/interface/interface_region_hud.cc7
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.cc5
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.cc2
-rw-r--r--source/blender/editors/interface/interface_region_popover.cc4
-rw-r--r--source/blender/editors/interface/interface_region_popup.cc4
-rw-r--r--source/blender/editors/interface/interface_region_search.cc17
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.cc (renamed from source/blender/editors/interface/interface_region_tooltip.c)696
-rw-r--r--source/blender/editors/interface/interface_regions.cc2
-rw-r--r--source/blender/editors/interface/interface_regions_intern.hh (renamed from source/blender/editors/interface/interface_regions_intern.h)15
-rw-r--r--source/blender/editors/interface/interface_style.cc18
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc4
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc10
-rw-r--r--source/blender/editors/interface/interface_template_list.cc16
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc1
-rw-r--r--source/blender/editors/interface/interface_template_search_operator.cc (renamed from source/blender/editors/interface/interface_template_search_operator.c)26
-rw-r--r--source/blender/editors/interface/interface_templates.c194
-rw-r--r--source/blender/editors/interface/interface_undo.cc (renamed from source/blender/editors/interface/interface_undo.c)33
-rw-r--r--source/blender/editors/interface/interface_utils.cc2
-rw-r--r--source/blender/editors/interface/interface_view.cc229
-rw-r--r--source/blender/editors/interface/interface_widgets.c96
-rw-r--r--source/blender/editors/interface/resources.c6
-rw-r--r--source/blender/editors/interface/view2d.cc141
-rw-r--r--source/blender/editors/interface/view2d_draw.cc2
-rw-r--r--source/blender/editors/interface/view2d_ops.cc4
-rw-r--r--source/blender/editors/interface/views/abstract_view.cc109
-rw-r--r--source/blender/editors/interface/views/abstract_view_item.cc373
-rw-r--r--source/blender/editors/interface/views/grid_view.cc (renamed from source/blender/editors/interface/grid_view.cc)102
-rw-r--r--source/blender/editors/interface/views/interface_view.cc196
-rw-r--r--source/blender/editors/interface/views/tree_view.cc (renamed from source/blender/editors/interface/tree_view.cc)412
-rw-r--r--source/blender/editors/io/CMakeLists.txt6
-rw-r--r--source/blender/editors/io/io_alembic.c48
-rw-r--r--source/blender/editors/io/io_collada.c22
-rw-r--r--source/blender/editors/io/io_gpencil_export.c40
-rw-r--r--source/blender/editors/io/io_gpencil_import.c51
-rw-r--r--source/blender/editors/io/io_obj.c73
-rw-r--r--source/blender/editors/io/io_stl_ops.c2
-rw-r--r--source/blender/editors/io/io_usd.c21
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c4
-rw-r--r--source/blender/editors/mask/CMakeLists.txt1
-rw-r--r--source/blender/editors/mask/mask_add.c14
-rw-r--r--source/blender/editors/mask/mask_draw.c78
-rw-r--r--source/blender/editors/mask/mask_edit.c32
-rw-r--r--source/blender/editors/mask/mask_editaction.c2
-rw-r--r--source/blender/editors/mask/mask_intern.h3
-rw-r--r--source/blender/editors/mask/mask_ops.c34
-rw-r--r--source/blender/editors/mask/mask_query.c3
-rw-r--r--source/blender/editors/mask/mask_relationships.c3
-rw-r--r--source/blender/editors/mask/mask_select.c20
-rw-r--r--source/blender/editors/mask/mask_shapekey.c16
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editface.cc287
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_screw.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c2
-rw-r--r--source/blender/editors/mesh/editmesh_path.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c3
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c4
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c11
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c599
-rw-r--r--source/blender/editors/mesh/mesh_data.cc405
-rw-r--r--source/blender/editors/mesh/mesh_intern.h4
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c13
-rw-r--r--source/blender/editors/mesh/mesh_ops.c4
-rw-r--r--source/blender/editors/mesh/meshtools.cc122
-rw-r--r--source/blender/editors/metaball/editmball_undo.c2
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/object/CMakeLists.txt4
-rw-r--r--source/blender/editors/object/object_add.cc254
-rw-r--r--source/blender/editors/object/object_bake.c5
-rw-r--r--source/blender/editors/object/object_bake_api.c184
-rw-r--r--source/blender/editors/object/object_collection.c3
-rw-r--r--source/blender/editors/object/object_constraint.c5
-rw-r--r--source/blender/editors/object/object_data_transfer.c8
-rw-r--r--source/blender/editors/object/object_edit.c42
-rw-r--r--source/blender/editors/object/object_facemap_ops.c2
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c3
-rw-r--r--source/blender/editors/object/object_intern.h8
-rw-r--r--source/blender/editors/object/object_modes.c2
-rw-r--r--source/blender/editors/object/object_modifier.cc80
-rw-r--r--source/blender/editors/object/object_ops.c5
-rw-r--r--source/blender/editors/object/object_relations.c203
-rw-r--r--source/blender/editors/object/object_remesh.cc58
-rw-r--r--source/blender/editors/object/object_select.c14
-rw-r--r--source/blender/editors/object/object_shader_fx.c9
-rw-r--r--source/blender/editors/object/object_shapekey.c46
-rw-r--r--source/blender/editors/object/object_transform.cc12
-rw-r--r--source/blender/editors/object/object_vgroup.cc (renamed from source/blender/editors/object/object_vgroup.c)600
-rw-r--r--source/blender/editors/physics/CMakeLists.txt1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c3
-rw-r--r--source/blender/editors/physics/particle_edit.c35
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c5
-rw-r--r--source/blender/editors/physics/particle_object.c9
-rw-r--r--source/blender/editors/physics/physics_fluid.c9
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c7
-rw-r--r--source/blender/editors/render/CMakeLists.txt1
-rw-r--r--source/blender/editors/render/render_opengl.cc73
-rw-r--r--source/blender/editors/render/render_preview.cc16
-rw-r--r--source/blender/editors/render/render_shading.cc26
-rw-r--r--source/blender/editors/render/render_update.cc26
-rw-r--r--source/blender/editors/render/render_view.cc8
-rw-r--r--source/blender/editors/scene/scene_edit.c2
-rw-r--r--source/blender/editors/screen/CMakeLists.txt1
-rw-r--r--source/blender/editors/screen/area.c40
-rw-r--r--source/blender/editors/screen/glutil.c7
-rw-r--r--source/blender/editors/screen/screen_context.c63
-rw-r--r--source/blender/editors/screen/screen_draw.c6
-rw-r--r--source/blender/editors/screen/screen_edit.c8
-rw-r--r--source/blender/editors/screen/screen_geometry.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c83
-rw-r--r--source/blender/editors/screen/screen_user_menu.c10
-rw-r--r--source/blender/editors/screen/screendump.c3
-rw-r--r--source/blender/editors/screen/workspace_edit.c130
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt9
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc887
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc140
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc119
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc49
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_density.cc922
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc122
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh53
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc1011
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc325
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_puff.cc385
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection.cc54
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc40
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_slide.cc498
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc261
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc61
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c19
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc5
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c38
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h17
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c54
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c61
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c54
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c85
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc313
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c485
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc514
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c75
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c69
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c638
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc36
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c333
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c157
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c73
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c31
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c358
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c97
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c24
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c44
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_geodesic.c78
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h159
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c56
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_init.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c241
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c83
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_image.cc12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c110
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c89
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c22
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c193
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c437
-rw-r--r--source/blender/editors/sound/sound_ops.c15
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_action/action_draw.c4
-rw-r--r--source/blender/editors/space_action/action_edit.c392
-rw-r--r--source/blender/editors/space_action/action_select.c236
-rw-r--r--source/blender/editors/space_action/space_action.c23
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c10
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c10
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c4
-rw-r--r--source/blender/editors/space_clip/clip_draw.c48
-rw-r--r--source/blender/editors/space_clip/clip_editor.c26
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c2
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c8
-rw-r--r--source/blender/editors/space_clip/clip_intern.h3
-rw-r--r--source/blender/editors/space_clip/clip_ops.c10
-rw-r--r--source/blender/editors/space_clip/clip_utils.c14
-rw-r--r--source/blender/editors/space_clip/space_clip.c18
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c154
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c4
-rw-r--r--source/blender/editors/space_console/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_console/console_draw.c2
-rw-r--r--source/blender/editors/space_console/console_ops.c12
-rw-r--r--source/blender/editors/space_console/space_console.c5
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc58
-rw-r--r--source/blender/editors/space_file/file_draw.c18
-rw-r--r--source/blender/editors/space_file/file_ops.c2
-rw-r--r--source/blender/editors/space_file/filelist.c19
-rw-r--r--source/blender/editors/space_file/filesel.c21
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c6
-rw-r--r--source/blender/editors/space_graph/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c9
-rw-r--r--source/blender/editors/space_graph/graph_draw.c21
-rw-r--r--source/blender/editors/space_graph/graph_edit.c151
-rw-r--r--source/blender/editors/space_graph/graph_ops.c23
-rw-r--r--source/blender/editors/space_graph/graph_select.c42
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c4
-rw-r--r--source/blender/editors/space_graph/graph_utils.c11
-rw-r--r--source/blender/editors/space_graph/graph_view.c7
-rw-r--r--source/blender/editors/space_graph/space_graph.c9
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_image/image_buttons.c12
-rw-r--r--source/blender/editors/space_image/image_draw.c15
-rw-r--r--source/blender/editors/space_image/image_edit.c32
-rw-r--r--source/blender/editors/space_image/image_ops.c105
-rw-r--r--source/blender/editors/space_image/image_undo.cc (renamed from source/blender/editors/space_image/image_undo.c)348
-rw-r--r--source/blender/editors/space_image/space_image.c16
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_info/info_stats.cc55
-rw-r--r--source/blender/editors/space_info/space_info.c4
-rw-r--r--source/blender/editors/space_info/textview.c17
-rw-r--r--source/blender/editors/space_nla/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c6
-rw-r--r--source/blender/editors/space_nla/nla_channels.c12
-rw-r--r--source/blender/editors/space_nla/nla_draw.c151
-rw-r--r--source/blender/editors/space_nla/nla_edit.c94
-rw-r--r--source/blender/editors/space_nla/nla_ops.c24
-rw-r--r--source/blender/editors/space_nla/nla_select.c16
-rw-r--r--source/blender/editors/space_nla/space_nla.c15
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_node/drawnode.cc584
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc3
-rw-r--r--source/blender/editors/space_node/node_add.cc315
-rw-r--r--source/blender/editors/space_node/node_context_path.cc31
-rw-r--r--source/blender/editors/space_node/node_draw.cc226
-rw-r--r--source/blender/editors/space_node/node_edit.cc212
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc8
-rw-r--r--source/blender/editors/space_node/node_gizmo.cc45
-rw-r--r--source/blender/editors/space_node/node_group.cc43
-rw-r--r--source/blender/editors/space_node/node_intern.hh48
-rw-r--r--source/blender/editors/space_node/node_ops.cc2
-rw-r--r--source/blender/editors/space_node/node_relationships.cc524
-rw-r--r--source/blender/editors/space_node/node_select.cc249
-rw-r--r--source/blender/editors/space_node/node_templates.cc67
-rw-r--r--source/blender/editors/space_node/node_view.cc20
-rw-r--r--source/blender/editors/space_node/space_node.cc14
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.cc125
-rw-r--r--source/blender/editors/space_outliner/outliner_context.cc4
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc155
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc175
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc225
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh127
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.cc5
-rw-r--r--source/blender/editors/space_outliner/outliner_query.cc4
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc93
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.cc20
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc1217
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc125
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc36
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc35
-rw-r--r--source/blender/editors/space_outliner/tree/common.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/common.hh4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh16
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_data.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc297
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc43
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh24
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_label.cc36
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_label.hh36
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc397
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.cc15
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.hh4
-rw-r--r--source/blender/editors/space_script/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_script/script_edit.c2
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c55
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_drag_drop.c294
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c729
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c187
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h7
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c147
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c52
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c20
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c13
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc10
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc248
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_draw.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc34
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc91
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc27
-rw-r--r--source/blender/editors/space_statusbar/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c2
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_text/space_text.c5
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c2
-rw-r--r--source/blender/editors/space_text/text_draw.c14
-rw-r--r--source/blender/editors/space_text/text_format_lua.c13
-rw-r--r--source/blender/editors/space_text/text_format_osl.c11
-rw-r--r--source/blender/editors/space_text/text_format_pov.c11
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c11
-rw-r--r--source/blender/editors/space_text/text_format_py.c13
-rw-r--r--source/blender/editors/space_text/text_ops.c19
-rw-r--r--source/blender/editors/space_topbar/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c7
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c25
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c181
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c18
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_camera.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_empty.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_forcefield.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_light.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h10
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c33
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate.c87
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate.h24
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_dolly.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_move.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_ndof.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_roll.c13
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_rotate.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_smoothview.c278
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c112
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_zoom.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_zoom_border.c11
-rw-r--r--source/blender/editors/space_view3d/view3d_select.cc (renamed from source/blender/editors/space_view3d/view3d_select.c)747
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c62
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c25
-rw-r--r--source/blender/editors/transform/CMakeLists.txt2
-rw-r--r--source/blender/editors/transform/transform.c17
-rw-r--r--source/blender/editors/transform/transform.h51
-rw-r--r--source/blender/editors/transform/transform_constraints.c10
-rw-r--r--source/blender/editors/transform/transform_constraints.h2
-rw-r--r--source/blender/editors/transform/transform_convert.c749
-rw-r--r--source/blender/editors/transform/transform_convert.h137
-rw-r--r--source/blender/editors/transform/transform_convert_action.c129
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c32
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c33
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c13
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c16
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c50
-rw-r--r--source/blender/editors/transform/transform_convert_lattice.c13
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c27
-rw-r--r--source/blender/editors/transform/transform_convert_mball.c13
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c46
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c15
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c11
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c21
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_vert_cdata.c296
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c32
-rw-r--r--source/blender/editors/transform/transform_convert_node.c49
-rw-r--r--source/blender/editors/transform/transform_convert_object.c23
-rw-r--r--source/blender/editors/transform/transform_convert_object_texspace.c16
-rw-r--r--source/blender/editors/transform/transform_convert_paintcurve.c11
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c20
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c22
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c93
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c26
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c13
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c87
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c11
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c8
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c2
-rw-r--r--source/blender/editors/transform/transform_input.c69
-rw-r--r--source/blender/editors/transform/transform_mode.c29
-rw-r--r--source/blender/editors/transform/transform_mode.h2
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c2
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c10
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c11
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c11
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c162
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c2
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c2
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c2
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c97
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c91
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c4
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c47
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c30
-rw-r--r--source/blender/editors/transform/transform_ops.c76
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c608
-rw-r--r--source/blender/editors/transform/transform_snap.h7
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc548
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c49
-rw-r--r--source/blender/editors/undo/CMakeLists.txt1
-rw-r--r--source/blender/editors/undo/ed_undo.c16
-rw-r--r--source/blender/editors/util/CMakeLists.txt3
-rw-r--r--source/blender/editors/util/ed_draw.c24
-rw-r--r--source/blender/editors/util/ed_util.c4
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c6
-rw-r--r--source/blender/editors/util/numinput.c13
-rw-r--r--source/blender/editors/util/select_utils.c30
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt3
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h4
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.cc (renamed from source/blender/editors/uvedit/uvedit_islands.c)95
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c406
-rw-r--r--source/blender/editors/uvedit/uvedit_path.c311
-rw-r--r--source/blender/editors/uvedit/uvedit_rip.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c981
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c191
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c250
562 files changed, 24779 insertions, 15636 deletions
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index 6adfab6e921..a72b2874f95 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -12,7 +12,6 @@ set(INC
../../sequencer
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 9eeabf2d05e..b7562073ee7 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -43,6 +43,7 @@
#include "DNA_world_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "BKE_anim_data.h"
@@ -156,7 +157,7 @@ static void acf_generic_dataexpand_backdrop(bAnimContext *ac,
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(color);
/* no rounded corner - just rectangular box */
@@ -245,7 +246,7 @@ static void acf_generic_channel_backdrop(bAnimContext *ac,
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(color);
/* no rounded corners - just rectangular box */
@@ -3123,7 +3124,7 @@ static bAnimChannelType ACF_DSSIMULATION = {
/* TODO: just get this from RNA? */
static int acf_dsgpencil_icon(bAnimListElem *UNUSED(ale))
{
- return ICON_GREASEPENCIL;
+ return ICON_OUTLINER_DATA_GREASEPENCIL;
}
/* Get the appropriate flag(s) for the setting when it is valid. */
@@ -4448,7 +4449,7 @@ void ANIM_channel_draw(
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* F-Curve channels need to have a special 'color code' box drawn,
* which is colored with whatever color the curve has stored.
@@ -4512,7 +4513,7 @@ void ANIM_channel_draw(
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* FIXME: replace hardcoded color here, and check on extents! */
immUniformColor3f(1.0f, 0.0f, 0.0f);
@@ -4548,7 +4549,7 @@ void ANIM_channel_draw(
float color[3];
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* get and set backdrop color */
acf->get_backdrop_color(ac, ale, color);
@@ -4747,13 +4748,13 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
RNA_id_pointer_create(id, &id_ptr);
/* Get NLA context for value remapping */
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, &id_ptr, adt, &anim_eval_context);
/* get current frame and apply NLA-mapping to it (if applicable) */
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
/* Get flags for keyframing. */
flag = ANIM_get_keyframing_flags(scene, true);
@@ -4803,8 +4804,8 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
RNA_id_pointer_create((ID *)key, &id_ptr);
/* Get NLA context for value remapping */
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, &id_ptr, key->adt, &anim_eval_context);
@@ -4872,7 +4873,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C,
float cfra;
/* get current frame - *no* NLA mapping should be done */
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene, true);
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index b223a1493fd..06a62b7a9de 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1498,7 +1498,8 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
int filter;
/* get animdata blocks */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1639,7 +1640,8 @@ static void animchannels_group_channels(bAnimContext *ac,
int filter;
/* find selected F-Curves to re-group */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, adt_ref, ANIMCONT_CHANNEL);
if (anim_data.first) {
@@ -1693,7 +1695,7 @@ static int animchannels_group_exec(bContext *C, wmOperator *op)
/* Handle each animdata block separately, so that the regrouping doesn't flow into blocks. */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1753,7 +1755,7 @@ static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op))
/* just selected F-Curves... */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -2033,7 +2035,7 @@ static void setflag_anim_channels(bAnimContext *ac,
if ((ac->spacetype == SPACE_GRAPH) && (ac->regiontype != RGN_TYPE_CHANNELS)) {
/* graph editor (case 2) */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
}
else {
/* standard case */
@@ -2453,7 +2455,7 @@ static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
}
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* loop through filtered data and clean curves */
@@ -3258,10 +3260,14 @@ static int mouse_anim_channels(bContext *C,
bAnimListElem *ale;
int filter;
int notifierFlags = 0;
+ ScrArea *area = CTX_wm_area(C);
/* get the channel that was clicked on */
/* filter channels */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ if (ELEM(area->spacetype, SPACE_NLA, SPACE_GRAPH)) {
+ filter |= ANIMFILTER_FCURVESONLY;
+ }
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get channel from index */
@@ -3453,7 +3459,8 @@ static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool e
/* get the channel that was clicked on */
/* filter channels */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get channel from index */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index d80eac2422e..22c14983569 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -32,6 +32,7 @@
#include "DEG_depsgraph.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "SEQ_sequencer.h"
#include "SEQ_utils.h"
@@ -356,7 +357,7 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
if (ale->update & ANIM_UPDATE_HANDLES) {
ale->update &= ~ANIM_UPDATE_HANDLES;
if (fcu) {
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index ee1522c7b76..06a0077df9b 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -35,6 +35,7 @@
#include "ED_keyframes_keylist.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -59,7 +60,7 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw a light green line to indicate current frame */
immUniformThemeColor(TH_CFRAME);
@@ -86,7 +87,7 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_ANIM_PREVIEW_RANGE, -25, -30);
/* XXX: Fix this hardcoded color (anim_active) */
// immUniformColor4f(0.8f, 0.44f, 0.1f, 0.2f);
@@ -117,12 +118,12 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
- if (SFRA < EFRA) {
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ if (scene->r.sfra < scene->r.efra) {
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)scene->r.sfra, v2d->cur.ymax);
+ immRectf(pos, (float)scene->r.efra, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
@@ -135,11 +136,11 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymax);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymax);
immEnd();
immUnbindProgram();
@@ -192,7 +193,7 @@ void ANIM_draw_action_framerange(
GPU_blend(GPU_BLEND_NONE);
/* Thin lines where the actual frames are. */
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShade(TH_BACK, -60);
GPU_line_width(1.0f);
@@ -530,7 +531,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
bool donenext = false, doneprev = false;
int nextcount = 0, prevcount = 0;
- cfranext = cfraprev = (float)(CFRA);
+ cfranext = cfraprev = (float)(scene->r.cfra);
/* seed up dummy dopesheet context with flags to perform necessary filtering */
if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
@@ -559,7 +560,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
aknext = ED_keylist_find_next(keylist, cfranext);
if (aknext) {
- if (CFRA == (int)aknext->cfra) {
+ if (scene->r.cfra == (int)aknext->cfra) {
/* make this the new starting point for the search and ignore */
cfranext = aknext->cfra;
}
@@ -577,7 +578,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
akprev = ED_keylist_find_prev(keylist, cfraprev);
if (akprev) {
- if (CFRA == (int)akprev->cfra) {
+ if (scene->r.cfra == (int)akprev->cfra) {
/* make this the new starting point for the search */
}
else {
@@ -599,14 +600,14 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
*r_prevfra = cfraprev;
}
else {
- *r_prevfra = CFRA - (cfranext - CFRA);
+ *r_prevfra = scene->r.cfra - (cfranext - scene->r.cfra);
}
if (donenext) {
*r_nextfra = cfranext;
}
else {
- *r_nextfra = CFRA + (CFRA - cfraprev);
+ *r_nextfra = scene->r.cfra + (scene->r.cfra - cfraprev);
}
return true;
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a75944fa2f2..2442a5910a0 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -122,7 +122,7 @@ static Key *actedit_get_shapekeys(bAnimContext *ac)
Object *ob;
Key *key;
- ob = OBACT(view_layer);
+ ob = BKE_view_layer_active_object_get(view_layer);
if (ob == NULL) {
return NULL;
}
@@ -1807,11 +1807,13 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data,
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
- /* add gpencil animation channels */
- BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
- tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
+ if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
+ /* add gpencil animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
+ tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
}
- END_ANIMFILTER_SUBCHANNELS;
/* did we find anything? */
if (tmp_items) {
@@ -1925,6 +1927,9 @@ static size_t animdata_filter_ds_gpencil(
tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode);
/* add Grease Pencil layers */
+ if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
+ tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
+ }
/* TODO: do these need a separate expander?
* XXX: what order should these go in? */
@@ -3267,7 +3272,7 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac,
/* Filter and add contents of each base (i.e. object) without them sorting first
* NOTE: This saves performance in cases where order doesn't matter
*/
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (animdata_filter_base_is_ok(ads, base, object_mode, filter_mode)) {
@@ -3401,9 +3406,8 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data)
GSet *gs;
size_t items = 0;
- /* build new hashtable to efficiently store and retrieve which entries have been
- * encountered already while searching
- */
+ /* Build new hash-table to efficiently store and retrieve which entries have been
+ * encountered already while searching. */
gs = BLI_gset_ptr_new(__func__);
/* loop through items, removing them from the list if a similar item occurs already */
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index f01b3522547..93d83ff5f8e 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -22,6 +22,7 @@
#include "DNA_anim_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "ED_anim_api.h"
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index ad06b185132..f1562fac7ee 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -51,7 +51,6 @@
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h"
-#include "ED_types.h"
#include "ED_util.h"
#include "DEG_depsgraph.h"
@@ -104,7 +103,7 @@ int ED_markers_post_apply_transform(
ListBase *markers, Scene *scene, int mode, float value, char side)
{
TimeMarker *marker;
- float cfra = (float)CFRA;
+ float cfra = (float)scene->r.cfra;
int changed_tot = 0;
/* sanity check - no markers, or locked markers */
@@ -402,6 +401,7 @@ static void draw_marker_name(const uchar *text_color,
const uiFontStyle *fstyle,
TimeMarker *marker,
float marker_x,
+ float xmax,
float text_y)
{
const char *name = marker->name;
@@ -419,8 +419,16 @@ static void draw_marker_name(const uchar *text_color,
}
#endif
- int name_x = marker_x + UI_DPI_ICON_SIZE * 0.6;
- UI_fontstyle_draw_simple(fstyle, name_x, text_y, name, final_text_color);
+ const int icon_half_width = UI_DPI_ICON_SIZE * 0.6;
+ const struct uiFontStyleDraw_Params fs_params = {.align = UI_STYLE_TEXT_LEFT, .word_wrap = 0};
+ const struct rcti rect = {
+ .xmin = marker_x + icon_half_width,
+ .xmax = xmax - icon_half_width,
+ .ymin = text_y,
+ .ymax = text_y,
+ };
+
+ UI_fontstyle_draw(fstyle, &rect, name, strlen(name), final_text_color, &fs_params);
}
static void draw_marker_line(const uchar *color, int xpos, int ymin, int ymax)
@@ -428,7 +436,7 @@ static void draw_marker_line(const uchar *color, int xpos, int ymin, int ymax)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -450,9 +458,7 @@ static void draw_marker_line(const uchar *color, int xpos, int ymin, int ymax)
static int marker_get_icon_id(TimeMarker *marker, int flag)
{
if (flag & DRAW_MARKERS_LOCAL) {
- return (marker->flag & ACTIVE) ? ICON_PMARKER_ACT :
- (marker->flag & SELECT) ? ICON_PMARKER_SEL :
- ICON_PMARKER;
+ return (marker->flag & SELECT) ? ICON_PMARKER_SEL : ICON_PMARKER;
}
#ifdef DURIAN_CAMERA_SWITCH
if (marker->camera) {
@@ -462,8 +468,13 @@ static int marker_get_icon_id(TimeMarker *marker, int flag)
return (marker->flag & SELECT) ? ICON_MARKER_HLT : ICON_MARKER;
}
-static void draw_marker(
- const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int xpos, int flag, int region_height)
+static void draw_marker(const uiFontStyle *fstyle,
+ TimeMarker *marker,
+ int xpos,
+ int xmax,
+ int flag,
+ int region_height,
+ bool is_elevated)
{
uchar line_color[4], text_color[4];
@@ -479,18 +490,17 @@ static void draw_marker(
GPU_blend(GPU_BLEND_NONE);
float name_y = UI_DPI_FAC * 18;
- /* Give an offset to the marker name when selected,
- * or when near the current frame (5 frames range, starting from the current one). */
- if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) {
+ /* Give an offset to the marker that is elevated. */
+ if (is_elevated) {
name_y += UI_DPI_FAC * 10;
}
- draw_marker_name(text_color, fstyle, marker, xpos, name_y);
+ draw_marker_name(text_color, fstyle, marker, xpos, xmax, name_y);
}
static void draw_markers_background(rctf *rect)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
uchar shade[4];
UI_GetThemeColor4ubv(TH_TIME_SCRUB_BACKGROUND, shade);
@@ -532,6 +542,14 @@ static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2
r_range[1] = v2d->cur.xmax + font_width_max;
}
+static int markers_frame_sort(const void *a, const void *b)
+{
+ const TimeMarker *marker_a = a;
+ const TimeMarker *marker_b = b;
+
+ return marker_a->frame > marker_b->frame;
+}
+
void ED_markers_draw(const bContext *C, int flag)
{
ListBase *markers = ED_context_get_markers(C);
@@ -561,22 +579,69 @@ void ED_markers_draw(const bContext *C, int flag)
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- /* Separate loops in order to draw selected markers on top */
- LISTBASE_FOREACH (TimeMarker *, marker, markers) {
- if ((marker->flag & SELECT) == 0) {
- if (marker_is_in_frame_range(marker, clip_frame_range)) {
- draw_marker(fstyle, marker, cfra, marker->frame * xscale, flag, region->winy);
- }
+ /* Markers are not stored by frame order, so we need to sort it here. */
+ ListBase sorted_markers;
+
+ BLI_duplicatelist(&sorted_markers, markers);
+ BLI_listbase_sort(&sorted_markers, markers_frame_sort);
+
+ /**
+ * Set a temporary bit in the marker's flag to indicate that it should be elevated.
+ * This bit will be flipped back at the end of this function.
+ */
+ const int ELEVATED = 0x10;
+ LISTBASE_FOREACH (TimeMarker *, marker, &sorted_markers) {
+ const bool is_elevated = (marker->flag & SELECT) ||
+ (cfra >= marker->frame &&
+ (marker->next == NULL || cfra < marker->next->frame));
+ SET_FLAG_FROM_TEST(marker->flag, is_elevated, ELEVATED);
+ }
+
+ /* Separate loops in order to draw selected markers on top. */
+
+ /**
+ * Draw non-elevated markers first.
+ * Note that unlike the elevated markers, these marker names will always be clipped by the
+ * proceeding marker. This is done because otherwise, the text overlaps with the icon of the
+ * marker itself.
+ */
+ LISTBASE_FOREACH (TimeMarker *, marker, &sorted_markers) {
+ if ((marker->flag & ELEVATED) == 0 && marker_is_in_frame_range(marker, clip_frame_range)) {
+ const int xmax = marker->next ? marker->next->frame : clip_frame_range[1] + 1;
+ draw_marker(
+ fstyle, marker, marker->frame * xscale, xmax * xscale, flag, region->winy, false);
}
}
- LISTBASE_FOREACH (TimeMarker *, marker, markers) {
- if (marker->flag & SELECT) {
- if (marker_is_in_frame_range(marker, clip_frame_range)) {
- draw_marker(fstyle, marker, cfra, marker->frame * xscale, flag, region->winy);
- }
+
+ /* Now draw the elevated markers */
+ for (TimeMarker *marker = sorted_markers.first; marker != NULL;) {
+
+ /* Skip this marker if it is elevated or out of the frame range. */
+ if ((marker->flag & ELEVATED) == 0 || !marker_is_in_frame_range(marker, clip_frame_range)) {
+ marker = marker->next;
+ continue;
}
+
+ /* Find the next elevated marker. */
+ /* We use the next marker to determine how wide our text should be */
+ TimeMarker *next_marker = marker->next;
+ while (next_marker != NULL && (next_marker->flag & ELEVATED) == 0) {
+ next_marker = next_marker->next;
+ }
+
+ const int xmax = next_marker ? next_marker->frame : clip_frame_range[1] + 1;
+ draw_marker(fstyle, marker, marker->frame * xscale, xmax * xscale, flag, region->winy, true);
+
+ marker = next_marker;
}
+ /* Reset the elevated flag. */
+ LISTBASE_FOREACH (TimeMarker *, marker, &sorted_markers) {
+ marker->flag &= ~ELEVATED;
+ }
+
+ BLI_freelistN(&sorted_markers);
+
GPU_matrix_pop();
}
@@ -1497,8 +1562,8 @@ static void ED_markers_select_leftright(bAnimContext *ac,
}
LISTBASE_FOREACH (TimeMarker *, marker, markers) {
- if ((mode == MARKERS_LRSEL_LEFT && marker->frame <= CFRA) ||
- (mode == MARKERS_LRSEL_RIGHT && marker->frame >= CFRA)) {
+ if ((mode == MARKERS_LRSEL_LEFT && marker->frame <= scene->r.cfra) ||
+ (mode == MARKERS_LRSEL_RIGHT && marker->frame >= scene->r.cfra)) {
marker->flag |= SELECT;
}
}
@@ -1588,12 +1653,13 @@ static void MARKER_OT_delete(wmOperatorType *ot)
ot->idname = "MARKER_OT_delete";
/* api callbacks */
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm_or_exec;
ot->exec = ed_marker_delete_exec;
ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ WM_operator_properties_confirm_or_exec(ot);
}
/** \} */
@@ -1754,11 +1820,11 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- marker = ED_markers_find_nearest_marker(markers, CFRA);
- if ((marker == NULL) || (marker->frame != CFRA)) {
+ marker = ED_markers_find_nearest_marker(markers, scene->r.cfra);
+ if ((marker == NULL) || (marker->frame != scene->r.cfra)) {
marker = MEM_callocN(sizeof(TimeMarker), "Camera TimeMarker");
marker->flag = SELECT;
- marker->frame = CFRA;
+ marker->frame = scene->r.cfra;
BLI_addtail(markers, marker);
/* deselect all others, so that the user can then move it without problems */
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index b15bd3db678..23c1d68b4d6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -391,7 +391,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
return;
}
- const int cfra = CFRA;
+ const int cfra = scene->r.cfra;
int sfra = INT_MAX, efra = INT_MIN;
switch (range) {
case ANIMVIZ_CALC_RANGE_CURRENT_FRAME:
@@ -485,7 +485,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
sfra,
efra,
efra - sfra + 1);
- for (CFRA = sfra; CFRA <= efra; CFRA++) {
+ for (scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) {
/* For current frame, only update tagged. */
BKE_scene_graph_update_tagged(depsgraph, bmain);
@@ -496,14 +496,14 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
}
/* perform baking for targets */
- motionpaths_calc_bake_targets(targets, CFRA);
+ motionpaths_calc_bake_targets(targets, scene->r.cfra);
}
/* reset original environment */
/* NOTE: We don't always need to reevaluate the main scene, as the depsgraph
* may be a temporary one that works on a subset of the data.
* We always have to restore the current frame though. */
- CFRA = cfra;
+ scene->r.cfra = cfra;
if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
motionpaths_calc_update_scene(depsgraph);
}
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 84f99ec0ac0..c7e755fb6df 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -111,9 +111,9 @@ static int seq_frame_apply_snap(bContext *C, Scene *scene, const int timeline_fr
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
seq_frame_snap_update_best(
- SEQ_time_left_handle_frame_get(seq), timeline_frame, &best_frame, &best_distance);
+ SEQ_time_left_handle_frame_get(scene, seq), timeline_frame, &best_frame, &best_distance);
seq_frame_snap_update_best(
- SEQ_time_right_handle_frame_get(seq), timeline_frame, &best_frame, &best_distance);
+ SEQ_time_right_handle_frame_get(scene, seq), timeline_frame, &best_frame, &best_distance);
}
SEQ_collection_free(strips);
@@ -142,14 +142,14 @@ static void change_frame_apply(bContext *C, wmOperator *op)
/* set the new frame number */
if (scene->r.flag & SCER_SHOW_SUBFRAME) {
- CFRA = (int)frame;
- SUBFRA = frame - (int)frame;
+ scene->r.cfra = (int)frame;
+ scene->r.subframe = frame - (int)frame;
}
else {
- CFRA = round_fl_to_int(frame);
- SUBFRA = 0.0f;
+ scene->r.cfra = round_fl_to_int(frame);
+ scene->r.subframe = 0.0f;
}
- FRAMENUMBER_MIN_CLAMP(CFRA);
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
/* do updates */
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
@@ -382,7 +382,7 @@ static int anim_set_sfra_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- frame = CFRA;
+ frame = scene->r.cfra;
/* if Preview Range is defined, set the 'start' frame for that */
if (PRVRANGEON) {
@@ -437,7 +437,7 @@ static int anim_set_efra_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- frame = CFRA;
+ frame = scene->r.cfra;
/* if Preview Range is defined, set the 'end' frame for that */
if (PRVRANGEON) {
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index c6f68228807..63794caf5a7 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -39,6 +39,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "anim_intern.h"
@@ -124,7 +125,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[],
insert_vert_fcurve(
fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 6f31472907b..d2f0ee622c4 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -1020,7 +1020,7 @@ bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *c
/* adding or removing the Cycles modifier requires an update to handles */
if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic) {
- calchandles_fcurve(curve);
+ BKE_fcurve_handles_recalc(curve);
}
/* did we succeed? */
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index f8277cf6a85..2a94c5db439 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -218,7 +218,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked,
ac.datatype = ANIMCONT_CHANNEL;
/* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Loop through each F-Curve, applying the operation as required,
@@ -267,7 +267,7 @@ static short scene_keyframes_loop(KeyframeEditData *ked,
ac.datatype = ANIMCONT_CHANNEL;
/* get F-Curves to take keyframes from */
- filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Loop through each F-Curve, applying the operation as required,
@@ -444,7 +444,7 @@ void ANIM_animdata_keyframe_callback(bAnimContext *ac,
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, callback_fn, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, callback_fn, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -831,7 +831,7 @@ static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
{
const Scene *scene = ked->scene;
if (bezt->f2 & SELECT) {
- bezt->vec[1][0] = (float)CFRA;
+ bezt->vec[1][0] = (float)scene->r.cfra;
}
return 0;
}
@@ -929,7 +929,7 @@ static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
const Scene *scene = ked->scene;
if (bezt->f2 & SELECT) {
- mirror_bezier_xaxis_ex(bezt, CFRA);
+ mirror_bezier_xaxis_ex(bezt, scene->r.cfra);
}
return 0;
@@ -1303,7 +1303,8 @@ void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu,
/* Perform handle equalization if mode is 'Both' or 'Left'. */
if (mode & EQUALIZE_HANDLES_LEFT) {
- /*If left handle type is 'Auto', 'Auto Clamped', or 'Vector', convert handles to 'Aligned'.*/
+ /* If left handle type is 'Auto', 'Auto Clamped', or 'Vector', convert handles to 'Aligned'.
+ */
if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
bezt->h1 = HD_ALIGN;
bezt->h2 = HD_ALIGN;
@@ -1319,8 +1320,8 @@ void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu,
/* Perform handle equalization if mode is 'Both' or 'Right'. */
if (mode & EQUALIZE_HANDLES_RIGHT) {
- /*If right handle type is 'Auto', 'Auto Clamped', or 'Vector', convert handles to
- * 'Aligned'.*/
+ /* If right handle type is 'Auto', 'Auto Clamped', or 'Vector', convert handles to
+ * 'Aligned'. */
if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
bezt->h1 = HD_ALIGN;
bezt->h2 = HD_ALIGN;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 00e2f221117..40f0ac59b01 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -29,6 +29,7 @@
#include "RNA_access.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
@@ -47,77 +48,6 @@
/* **************************************************** */
-void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
-{
- /* sanity check */
- if (fcu == NULL) {
- return;
- }
-
- /* verify the index:
- * 1) cannot be greater than the number of available keyframes
- * 2) negative indices are for specifying a value from the end of the array
- */
- if (abs(index) >= fcu->totvert) {
- return;
- }
- if (index < 0) {
- index += fcu->totvert;
- }
-
- /* Delete this keyframe */
- memmove(
- &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
- fcu->totvert--;
-
- if (fcu->totvert == 0) {
- MEM_SAFE_FREE(fcu->bezt);
- }
-
- /* recalc handles - only if it won't cause problems */
- if (do_recalc) {
- calchandles_fcurve(fcu);
- }
-}
-
-bool delete_fcurve_keys(FCurve *fcu)
-{
- bool changed = false;
-
- if (fcu->bezt == NULL) { /* ignore baked curves */
- return false;
- }
-
- /* Delete selected BezTriples */
- for (int i = 0; i < fcu->totvert; i++) {
- if (fcu->bezt[i].f2 & SELECT) {
- if (i == fcu->active_keyframe_index) {
- BKE_fcurve_active_keyframe_set(fcu, NULL);
- }
- memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
- fcu->totvert--;
- i--;
- changed = true;
- }
- }
-
- /* Free the array of BezTriples if there are not keyframes */
- if (fcu->totvert == 0) {
- clear_fcurve_keys(fcu);
- }
-
- return changed;
-}
-
-void clear_fcurve_keys(FCurve *fcu)
-{
- MEM_SAFE_FREE(fcu->bezt);
-
- fcu->totvert = 0;
-}
-
-/* ---------------- */
-
bool duplicate_fcurve_keys(FCurve *fcu)
{
bool changed = false;
@@ -282,7 +212,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
if (fcu->bezt->vec[1][1] == default_value) {
- clear_fcurve_keys(fcu);
+ BKE_fcurve_delete_keys_all(fcu);
/* check if curve is really unused and if it is, return signal for deletion */
if (BKE_fcurve_is_empty(fcu)) {
@@ -679,7 +609,7 @@ void smooth_fcurve(FCurve *fcu)
}
/* recalculate handles */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* ---------------- */
@@ -762,7 +692,7 @@ void sample_fcurve(FCurve *fcu)
}
/* recalculate channel's handles? */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* **************************************************** */
@@ -921,7 +851,7 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
}
/* in case 'relative' paste method is used */
- animcopy_cfra = CFRA;
+ animcopy_cfra = scene->r.cfra;
/* everything went fine */
return 0;
@@ -1121,7 +1051,7 @@ static void paste_animedit_keys_fcurve(
case KEYFRAME_PASTE_MERGE_OVER:
/* remove all keys */
- clear_fcurve_keys(fcu);
+ BKE_fcurve_delete_keys_all(fcu);
break;
case KEYFRAME_PASTE_MERGE_OVER_RANGE:
@@ -1148,7 +1078,7 @@ static void paste_animedit_keys_fcurve(
}
/* remove frames in the range */
- delete_fcurve_keys(fcu);
+ BKE_fcurve_delete_keys_selected(fcu);
}
break;
}
@@ -1182,7 +1112,7 @@ static void paste_animedit_keys_fcurve(
}
/* recalculate F-Curve's handles? */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
@@ -1217,11 +1147,11 @@ const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
{0, NULL, 0, NULL, NULL},
};
-short paste_animedit_keys(bAnimContext *ac,
- ListBase *anim_data,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
- bool flip)
+eKeyPasteError paste_animedit_keys(bAnimContext *ac,
+ ListBase *anim_data,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
bAnimListElem *ale;
@@ -1235,25 +1165,23 @@ short paste_animedit_keys(bAnimContext *ac,
/* check if buffer is empty */
if (BLI_listbase_is_empty(&animcopybuf)) {
- BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
- return -1;
+ return KEYFRAME_PASTE_NOTHING_TO_PASTE;
}
if (BLI_listbase_is_empty(anim_data)) {
- BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
- return -1;
+ return KEYFRAME_PASTE_NOWHERE_TO_PASTE;
}
/* methods of offset */
switch (offset_mode) {
case KEYFRAME_PASTE_OFFSET_CFRA_START:
- offset = (float)(CFRA - animcopy_firstframe);
+ offset = (float)(scene->r.cfra - animcopy_firstframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_END:
- offset = (float)(CFRA - animcopy_lastframe);
+ offset = (float)(scene->r.cfra - animcopy_lastframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
- offset = (float)(CFRA - animcopy_cfra);
+ offset = (float)(scene->r.cfra - animcopy_cfra);
break;
case KEYFRAME_PASTE_OFFSET_NONE:
offset = 0.0f;
@@ -1335,7 +1263,7 @@ short paste_animedit_keys(bAnimContext *ac,
ANIM_animdata_update(ac, anim_data);
- return 0;
+ return KEYFRAME_PASTE_OK;
}
/* **************************************************** */
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 8dc598e6e2d..da266dd4253 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -943,7 +943,8 @@ void scene_to_keylist(bDopeSheet *ads, Scene *sce, AnimKeylist *keylist, const i
ac.datatype = ANIMCONT_CHANNEL;
/* get F-Curves to take keyframes from */
- const eAnimFilter_Flags filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ const eAnimFilter_Flags filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY;
+
ANIM_animdata_filter(
&ac, &anim_data, filter, ac.data, static_cast<eAnimCont_Types>(ac.datatype));
@@ -980,7 +981,7 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, AnimKeylist *keylist, const int
ac.datatype = ANIMCONT_CHANNEL;
/* get F-Curves to take keyframes from */
- const eAnimFilter_Flags filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ const eAnimFilter_Flags filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY;
ANIM_animdata_filter(
&ac, &anim_data, filter, ac.data, static_cast<eAnimCont_Types>(ac.datatype));
@@ -1015,7 +1016,7 @@ void cachefile_to_keylist(bDopeSheet *ads,
/* get F-Curves to take keyframes from */
ListBase anim_data = {nullptr, nullptr};
- const eAnimFilter_Flags filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
+ const eAnimFilter_Flags filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY;
ANIM_animdata_filter(
&ac, &anim_data, filter, ac.data, static_cast<eAnimCont_Types>(ac.datatype));
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index aa99a4e50c3..acf53541843 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "anim_intern.h"
@@ -639,7 +640,7 @@ int insert_vert_fcurve(
* - we may calculate twice (due to auto-handle needing to be calculated twice)
*/
if ((flag & INSERTKEY_FAST) == 0) {
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* return the index at which the keyframe was added */
@@ -1080,10 +1081,7 @@ static float *visualkey_get_values(
}
if (strstr(identifier, "rotation_quaternion")) {
- float mat3[3][3];
-
- copy_m3_m4(mat3, tmat);
- mat3_to_quat_is_ok(buffer, mat3);
+ mat4_to_quat(buffer, tmat);
*r_count = 4;
return buffer;
@@ -1282,10 +1280,12 @@ static bool insert_keyframe_value(ReportList *reports,
/* delete keyframe immediately before/after newly added */
switch (insert_mode) {
case KEYNEEDED_DELPREV:
- delete_fcurve_key(fcu, fcu->totvert - 2, 1);
+ BKE_fcurve_delete_key(fcu, fcu->totvert - 2);
+ BKE_fcurve_handles_recalc(fcu);
break;
case KEYNEEDED_DELNEXT:
- delete_fcurve_key(fcu, 1, 1);
+ BKE_fcurve_delete_key(fcu, 1);
+ BKE_fcurve_handles_recalc(fcu);
break;
}
@@ -1683,7 +1683,8 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
if (found) {
/* delete the key at the index (will sanity check + do recalc afterwards) */
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
/* Only delete curve too if it won't be doing anything anymore */
if (BKE_fcurve_is_empty(fcu)) {
@@ -1947,7 +1948,8 @@ static int insert_key_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
bool ob_edit_mode = false;
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ float cfra = (float)
+ scene->r.cfra; /* XXX for now, don't bother about all the yucky offset crap */
int num_channels;
const bool confirm = op->flag & OP_IS_INVOKE;
@@ -2168,7 +2170,8 @@ static int delete_key_exec(bContext *C, wmOperator *op)
static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks)
{
Scene *scene = CTX_data_scene(C);
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ float cfra = (float)
+ scene->r.cfra; /* XXX for now, don't bother about all the yucky offset crap */
int num_channels;
const bool confirm = op->flag & OP_IS_INVOKE;
@@ -2344,7 +2347,7 @@ void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot)
static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- float cfra = (float)CFRA;
+ float cfra = (float)scene->r.cfra;
int selected_objects_len = 0;
int selected_objects_success_len = 0;
@@ -2494,7 +2497,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
char *path;
uiBut *but;
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
- CTX_data_depsgraph_pointer(C), (float)CFRA);
+ CTX_data_depsgraph_pointer(C), (float)scene->r.cfra);
bool changed = false;
int index;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -2663,7 +2666,8 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
PropertyRNA *prop = NULL;
Main *bmain = CTX_data_main(C);
char *path;
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ float cfra = (float)
+ scene->r.cfra; /* XXX for now, don't bother about all the yucky offset crap */
bool changed = false;
int index;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -2706,7 +2710,8 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
if (found) {
/* delete the key at the index (will sanity check + do recalc afterwards) */
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
changed = true;
}
}
@@ -2835,7 +2840,7 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot)
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
{
- float cfra = (float)CFRA; /* XXX for now, this will do */
+ float cfra = (float)scene->r.cfra; /* XXX for now, this will do */
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_ON(scene) == 0) {
@@ -3065,7 +3070,7 @@ bool ED_autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks
* 3) Free the extra info.
*/
ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
return true;
@@ -3085,7 +3090,7 @@ bool ED_autokeyframe_pchan(
* 3) Free the extra info.
*/
ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
return true;
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 97b81277008..e6bcb404bcb 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -39,6 +39,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "anim_intern.h"
@@ -713,7 +714,7 @@ static void anim_keyingset_visit_for_search_impl(const bContext *C,
void *visit_user_data,
const bool use_poll)
{
- /* Poll requires context. */
+ /* Poll requires context. */
if (use_poll && (C == NULL)) {
return;
}
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 623d4e605ba..ebeac6552cd 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -48,7 +48,7 @@ static int get_centered_text_y(const rcti *rect)
static void draw_background(const rcti *rect)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_TIME_SCRUB_BACKGROUND);
@@ -97,7 +97,7 @@ static void draw_current_frame(const Scene *scene,
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_blend(GPU_BLEND_ALPHA);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Outline. */
immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
@@ -208,7 +208,7 @@ void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDope
rect.ymax = region->winy;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_BACK);
immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
immUnbindProgram();
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 3ce5b70918d..243b2950e2e 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -14,7 +14,6 @@ set(INC
../../windowmanager
../../../../intern/clog
../../../../intern/eigen
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index dd43e3e6613..2071f056f9e 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -422,7 +422,7 @@ static void updateDuplicateActionConstraintSettings(
float mat[4][4];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
- BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+ BKE_constraint_custom_object_space_init(&cob, curcon);
unit_m4(mat);
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
@@ -576,7 +576,7 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
unit_m4(local_mat);
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
- BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+ BKE_constraint_custom_object_space_init(&cob, curcon);
BKE_constraint_mat_convertspace(
ob, pchan, &cob, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
@@ -631,7 +631,7 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
float target_mat[4][4], own_mat[4][4], imat[4][4];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
- BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+ BKE_constraint_custom_object_space_init(&cob, curcon);
unit_m4(own_mat);
BKE_constraint_mat_convertspace(
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 1f02e24666d..4f329dbe449 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -13,6 +13,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
@@ -281,6 +282,17 @@ void ED_armature_bone_rename(Main *bmain,
}
}
+ /* fix camera focus */
+ if (ob->type == OB_CAMERA) {
+ Camera *cam = (Camera *)ob->data;
+ if ((cam->dof.focus_object != NULL) && (cam->dof.focus_object->data == arm)) {
+ if (STREQ(cam->dof.focus_subtarget, oldname)) {
+ BLI_strncpy(cam->dof.focus_subtarget, newname, MAXBONENAME);
+ DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ }
+
/* fix grease pencil modifiers and vertex groups */
if (ob->type == OB_GPENCIL) {
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 950178e865d..0825d6968c6 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -159,6 +159,11 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data
ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
+ /* Ensure that invalid drivers gets re-evaluated in case they become valid once the join
+ * operation is finished. */
+ fcu->flag &= ~FCURVE_DISABLED;
+ driver->flag &= ~DRIVER_FLAG_INVALID;
+
/* Fix driver references to invalid ID's */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
/* only change the used targets, since the others will need fixing manually anyway */
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 08d5d6558e0..479a2245b30 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -59,7 +59,7 @@ Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases,
const uint hit_object = select_id & 0xFFFF;
Base *base = NULL;
EditBone *ebone = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
+ /* TODO(@campbellbarton): optimize, eg: sort & binary search. */
for (uint base_index = 0; base_index < bases_len; base_index++) {
if (bases[base_index]->object->runtime.select_id == hit_object) {
base = bases[base_index];
@@ -83,7 +83,7 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects,
const uint hit_object = select_id & 0xFFFF;
Object *ob = NULL;
EditBone *ebone = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
+ /* TODO(@campbellbarton): optimize, eg: sort & binary search. */
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
if (objects[ob_index]->runtime.select_id == hit_object) {
ob = objects[ob_index];
@@ -107,7 +107,7 @@ Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
const uint hit_object = select_id & 0xFFFF;
Base *base = NULL;
bPoseChannel *pchan = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
+ /* TODO(@campbellbarton): optimize, eg: sort & binary search. */
for (uint base_index = 0; base_index < bases_len; base_index++) {
if (bases[base_index]->object->runtime.select_id == hit_object) {
base = bases[base_index];
@@ -339,12 +339,7 @@ static void *ed_armature_pick_bone_impl(
Base **bases;
if (vc.obedit != NULL) {
- bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
- vc.v3d,
- &bases_len,
- {
- .object_mode = OB_MODE_EDIT,
- });
+ bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
}
else {
bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
@@ -1452,7 +1447,7 @@ static void armature_select_more_less(Object *ob, bool more)
bArmature *arm = (bArmature *)ob->data;
EditBone *ebone;
- /* XXX(campbell): eventually we shouldn't need this. */
+ /* XXX(@campbellbarton): eventually we shouldn't need this. */
ED_armature_edit_sync_selection(arm->edbo);
/* count bones & store selection state */
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 3a1e7419d3c..e39cc157c19 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -21,6 +21,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_deform.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
@@ -203,9 +204,9 @@ static void envelope_bone_weighting(Object *ob,
}
/* for each vertex in the mesh */
+ const MVert *mesh_verts = BKE_mesh_verts(mesh);
for (int i = 0; i < mesh->totvert; i++) {
-
- if (use_mask && !(mesh->mvert[i].flag & SELECT)) {
+ if (use_mask && !(mesh_verts[i].flag & SELECT)) {
continue;
}
@@ -405,9 +406,10 @@ static void add_verts_to_dgroups(ReportList *reports,
}
/* transform verts to global space */
+ const MVert *mesh_verts = BKE_mesh_verts(mesh);
for (int i = 0; i < mesh->totvert; i++) {
if (!vertsfilled) {
- copy_v3_v3(verts[i], mesh->mvert[i].co);
+ copy_v3_v3(verts[i], mesh_verts[i].co);
}
mul_m4_v3(ob->obmat, verts[i]);
}
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index bcf8b7cff99..3f084c08044 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -98,7 +98,7 @@ static void undoarm_free_data(UndoArmature *uarm)
static Object *editarm_object_from_context(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit && obedit->type == OB_ARMATURE) {
bArmature *arm = obedit->data;
if (arm->edbo != NULL) {
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 7016511111e..904e6213466 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -645,14 +645,16 @@ void heat_bone_weighting(Object *ob,
{
LaplacianSystem *sys;
MLoopTri *mlooptri;
- MPoly *mp;
- MLoop *ml;
+ const MPoly *mp;
+ const MLoop *ml;
float solution, weight;
int *vertsflipped = NULL, *mask = NULL;
int a, tris_num, j, bbone, firstsegment, lastsegment;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
- MVert *mvert = me->mvert;
+ const MVert *mesh_verts = BKE_mesh_verts(me);
+ const MPoly *polys = BKE_mesh_polys(me);
+ const MLoop *loops = BKE_mesh_loops(me);
bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
@@ -667,16 +669,16 @@ void heat_bone_weighting(Object *ob,
/* (added selectedVerts content for vertex mask, they used to just equal 1) */
if (use_vert_sel) {
- for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
- for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
- mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0;
+ for (a = 0, mp = polys; a < me->totpoly; mp++, a++) {
+ for (j = 0, ml = loops + mp->loopstart; j < mp->totloop; j++, ml++) {
+ mask[ml->v] = (mesh_verts[ml->v].flag & SELECT) != 0;
}
}
}
else if (use_face_sel) {
- for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
+ for (a = 0, mp = polys; a < me->totpoly; mp++, a++) {
if (mp->flag & ME_FACE_SEL) {
- for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
+ for (j = 0, ml = loops + mp->loopstart; j < mp->totloop; j++, ml++) {
mask[ml->v] = 1;
}
}
@@ -690,10 +692,10 @@ void heat_bone_weighting(Object *ob,
sys->heat.tris_num = poly_to_tri_count(me->totpoly, me->totloop);
mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tris_num, __func__);
- BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri);
+ BKE_mesh_recalc_looptri(loops, polys, mesh_verts, me->totloop, me->totpoly, mlooptri);
sys->heat.mlooptri = mlooptri;
- sys->heat.mloop = me->mloop;
+ sys->heat.mloop = loops;
sys->heat.verts_num = me->totvert;
sys->heat.verts = verts;
sys->heat.root = root;
@@ -1606,8 +1608,8 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
/* initialize data from 'cagedm' for reuse */
{
Mesh *me = mdb->cagemesh;
- mdb->cagemesh_cache.mpoly = me->mpoly;
- mdb->cagemesh_cache.mloop = me->mloop;
+ mdb->cagemesh_cache.mpoly = BKE_mesh_polys(me);
+ mdb->cagemesh_cache.mloop = BKE_mesh_loops(me);
mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me);
}
@@ -1743,7 +1745,7 @@ void ED_mesh_deform_bind_callback(Object *object,
MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)BKE_modifier_get_original(
object, &mmd->modifier);
MeshDeformBind mdb;
- MVert *mvert;
+ const MVert *mvert;
int a;
waitcursor(1);
@@ -1763,7 +1765,7 @@ void ED_mesh_deform_bind_callback(Object *object,
mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.cage_verts_num, "MeshDeformBindCos");
copy_m4_m4(mdb.cagemat, cagemat);
- mvert = mdb.cagemesh->mvert;
+ mvert = BKE_mesh_verts(mdb.cagemesh);
for (a = 0; a < mdb.cage_verts_num; a++) {
copy_v3_v3(mdb.cagecos[a], mvert[a].co);
}
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index d0f0bd55eea..1b78d3cc77e 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -42,6 +42,7 @@
static bool pose_group_poll(bContext *C)
{
if (!ED_operator_posemode_context(C)) {
+ CTX_wm_operator_poll_msg_set(C, "Bone groups can only be edited in pose mode");
return false;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index ea54c3014ca..ff187a52154 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -24,6 +24,7 @@
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -448,7 +449,7 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
ICON_NONE,
"POSELIB_OT_pose_add",
"frame",
- CFRA);
+ scene->r.cfra);
/* Replace existing - sub-menu. */
uiItemMenuF(
@@ -615,7 +616,8 @@ static int poselib_remove_exec(bContext *C, wmOperator *op)
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* check if remove */
if (IS_EQF(bezt->vec[1][0], (float)marker->frame)) {
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
break;
}
}
@@ -1113,7 +1115,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
/* perform actual auto-keying now */
if (autokey) {
/* insert keyframes for all relevant bones in one go */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
}
@@ -1578,7 +1580,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
case EVT_PADMINUS:
if (pld->searchstr[0]) {
/* searching... */
- poselib_preview_handle_search(pld, event->type, event->ascii);
+ poselib_preview_handle_search(pld, event->type, WM_event_utf8_to_ascii(event));
}
else {
/* view manipulation (see above) */
@@ -1589,7 +1591,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
/* otherwise, assume that searching might be able to handle it */
default:
- poselib_preview_handle_search(pld, event->type, event->ascii);
+ poselib_preview_handle_search(pld, event->type, WM_event_utf8_to_ascii(event));
break;
}
diff --git a/source/blender/editors/armature/pose_lib_2.c b/source/blender/editors/armature/pose_lib_2.c
index 9ee289145c4..d866062cec0 100644
--- a/source/blender/editors/armature/pose_lib_2.c
+++ b/source/blender/editors/armature/pose_lib_2.c
@@ -134,7 +134,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd)
}
/* Perform actual auto-keying. */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
/* send notifiers for this */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index b6b5d3ee495..55dc664b756 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -158,15 +158,15 @@ bool ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
}
if (found) {
- Object *ob_act = OBACT(view_layer);
- BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
+ Object *ob_act = BKE_view_layer_active_object_get(view_layer);
+ BLI_assert(BKE_view_layer_edit_object_get(view_layer) == NULL);
/* If the bone cannot be affected, don't do anything. */
bArmature *arm = ob->data;
/* Since we do unified select, we don't shift+select a bone if the
* armature object was not active yet.
- * NOTE(campbell): special exception for armature mode so we can do multi-select
+ * NOTE(@campbellbarton): special exception for armature mode so we can do multi-select
* we could check for multi-select explicitly but think its fine to
* always give predictable behavior in weight paint mode. */
if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) {
@@ -269,7 +269,7 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
{
BLI_assert(base_select && (base_select->object->type == OB_ARMATURE));
- Object *ob_active = OBACT(view_layer);
+ Object *ob_active = BKE_view_layer_active_object_get(view_layer);
BLI_assert(ob_active && (ob_active->mode & OB_MODE_ALL_WEIGHT_PAINT));
if (ob_active->type == OB_GPENCIL) {
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 0efa32ec63a..5e0ef9217c7 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -53,6 +53,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
@@ -285,8 +286,10 @@ static void pose_slide_exit(bContext *C, wmOperator *op)
ED_slider_destroy(C, pso->slider);
/* Hide Bone Overlay. */
- View3D *v3d = pso->area->spacedata.first;
- v3d->overlay.flag = pso->overlay_flag;
+ if (pso->area) {
+ View3D *v3d = pso->area->spacedata.first;
+ v3d->overlay.flag = pso->overlay_flag;
+ }
/* Free the temp pchan links and their data. */
poseAnim_mapping_free(&pso->pfLinks);
@@ -2061,12 +2064,12 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
if (mode == POSE_PROPAGATE_SMART_HOLDS) {
/* We store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
* from the keyframe that occurs after the current frame. */
- modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
+ modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)scene->r.cfra);
}
/* Go through propagating pose to keyframes, curve by curve. */
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
+ pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)scene->r.cfra, modeData);
}
}
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index f0b0218d7e0..cfc6b0b6b6e 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -1201,7 +1201,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
/* insert keyframes */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
/* now recalculate paths */
if (ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
@@ -1343,8 +1343,8 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 032e0ec077c..ea038362532 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -26,6 +26,7 @@
#include "DEG_depsgraph.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
index 2dc67fc4d37..b54f81004f2 100644
--- a/source/blender/editors/asset/ED_asset_list.h
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -24,7 +24,7 @@ struct wmNotifier;
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
- struct bContext *C);
+ const struct bContext *C);
void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
/**
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
index 3cc3638c299..cc06fa80429 100644
--- a/source/blender/editors/asset/intern/asset_indexer.cc
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -351,7 +351,7 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
{
indexer_entry.idcode = entry.get_idcode();
- const std::string &name = entry.get_name();
+ const std::string name = entry.get_name();
BLI_strncpy(
indexer_entry.datablock_info.name, name.c_str(), sizeof(indexer_entry.datablock_info.name));
@@ -359,19 +359,19 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
indexer_entry.datablock_info.asset_data = asset_data;
if (entry.has_description()) {
- const std::string &description = entry.get_description();
- char *description_c_str = static_cast<char *>(MEM_mallocN(description.length() + 1, __func__));
- BLI_strncpy(description_c_str, description.c_str(), description.length() + 1);
+ const StringRefNull description = entry.get_description();
+ char *description_c_str = static_cast<char *>(MEM_mallocN(description.size() + 1, __func__));
+ BLI_strncpy(description_c_str, description.c_str(), description.size() + 1);
asset_data->description = description_c_str;
}
if (entry.has_author()) {
- const std::string &author = entry.get_author();
- char *author_c_str = static_cast<char *>(MEM_mallocN(author.length() + 1, __func__));
- BLI_strncpy(author_c_str, author.c_str(), author.length() + 1);
+ const StringRefNull author = entry.get_author();
+ char *author_c_str = static_cast<char *>(MEM_mallocN(author.size() + 1, __func__));
+ BLI_strncpy(author_c_str, author.c_str(), author.size() + 1);
asset_data->author = author_c_str;
}
- const std::string &catalog_name = entry.get_catalog_name();
+ const StringRefNull catalog_name = entry.get_catalog_name();
BLI_strncpy(asset_data->catalog_simple_name,
catalog_name.c_str(),
sizeof(asset_data->catalog_simple_name));
diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
index 67e253a4fcd..773838a54cd 100644
--- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc
+++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
@@ -97,10 +97,8 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
RNA_enum_item_add_separator(&item, &totitem);
}
- int i = 0;
- for (bUserAssetLibrary *user_library = (bUserAssetLibrary *)U.asset_libraries.first;
- user_library;
- user_library = user_library->next, i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bUserAssetLibrary *, user_library, &U.asset_libraries, i) {
/* Note that the path itself isn't checked for validity here. If an invalid library path is
* used, the Asset Browser can give a nice hint on what's wrong. */
const bool is_valid = (user_library->name[0] && user_library->path[0]);
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index 55167c1ed2d..b0ff5c86520 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -110,7 +110,7 @@ class AssetList : NonCopyable {
void setup();
void fetch(const bContext &C);
- void ensurePreviewsJob(bContext *C);
+ void ensurePreviewsJob(const bContext *C);
void clear(bContext *C);
bool needsRefetch() const;
@@ -212,7 +212,7 @@ void AssetList::iterate(AssetListIterFn fn) const
}
}
-void AssetList::ensurePreviewsJob(bContext *C)
+void AssetList::ensurePreviewsJob(const bContext *C)
{
FileList *files = filelist_;
int numfiles = filelist_files_ensure(files);
@@ -422,7 +422,8 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference,
AssetListStorage::fetch_library(*library_reference, *C);
}
-void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, bContext *C)
+void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference,
+ const bContext *C)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index 619a873909a..05d0b7d0af4 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -295,7 +295,7 @@ void AssetClearHelper::reportResults(const bContext *C, ReportList &reports) con
else if (stats.tot_cleared == 1) {
/* If only one data-block: Give more useful message by printing asset name. */
BKE_reportf(
- &reports, RPT_INFO, "Data-block '%s' is no asset anymore", stats.last_id->name + 2);
+ &reports, RPT_INFO, "Data-block '%s' is not an asset anymore", stats.last_id->name + 2);
}
else {
BKE_reportf(&reports, RPT_INFO, "%i data-blocks are no assets anymore", stats.tot_cleared);
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 791e28de694..0cedc05981b 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -11,7 +11,6 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../extern/curve_fit_nd
# RNA_prototypes.h
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 4c0df48f65b..2829e8bc115 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -47,7 +47,6 @@
#include "ED_select_utils.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
-#include "ED_types.h"
#include "ED_view3d.h"
#include "curve_intern.h"
@@ -1279,7 +1278,7 @@ void ED_curve_editnurb_make(Object *obedit)
if (actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
- /* TODO(campbell): undo_system: investigate why this was needed. */
+ /* TODO(@campbellbarton): undo_system: investigate why this was needed. */
#if 0
undo_editmode_clear();
#endif
@@ -1541,67 +1540,6 @@ void CURVE_OT_split(wmOperatorType *ot)
/** \name Flag Utility Functions
* \{ */
-static bool isNurbselUV(const Nurb *nu, uint8_t flag, int *r_u, int *r_v)
-{
- /* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
- * return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
- */
- BPoint *bp;
- int a, b, sel;
-
- *r_u = *r_v = -1;
-
- bp = nu->bp;
- for (b = 0; b < nu->pntsv; b++) {
- sel = 0;
- for (a = 0; a < nu->pntsu; a++, bp++) {
- if (bp->f1 & flag) {
- sel++;
- }
- }
- if (sel == nu->pntsu) {
- if (*r_u == -1) {
- *r_u = b;
- }
- else {
- return 0;
- }
- }
- else if (sel > 1) {
- return 0; /* because sel == 1 is still ok */
- }
- }
-
- for (a = 0; a < nu->pntsu; a++) {
- sel = 0;
- bp = &nu->bp[a];
- for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
- if (bp->f1 & flag) {
- sel++;
- }
- }
- if (sel == nu->pntsv) {
- if (*r_v == -1) {
- *r_v = a;
- }
- else {
- return 0;
- }
- }
- else if (sel > 1) {
- return 0;
- }
- }
-
- if (*r_u == -1 && *r_v > -1) {
- return 1;
- }
- if (*r_v == -1 && *r_u > -1) {
- return 1;
- }
- return 0;
-}
-
/* return true if U direction is selected and number of selected columns v */
static bool isNurbselU(Nurb *nu, int *v, int flag)
{
@@ -1976,119 +1914,201 @@ static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
}
}
-bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
+static void select_bpoints(BPoint *bp,
+ const int stride,
+ const int count,
+ const bool selstatus,
+ const uint8_t flag,
+ const bool hidden)
{
- BPoint *bp, *bpn, *newbp;
- int a, u, v, len;
- bool ok = false;
+ for (int i = 0; i < count; i++) {
+ select_bpoint(bp, selstatus, flag, hidden);
+ bp += stride;
+ }
+}
- LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
- if (nu->pntsv == 1) {
- bp = nu->bp;
- a = nu->pntsu;
- while (a) {
- if (bp->f1 & flag) {
- /* pass */
- }
- else {
- break;
- }
- bp++;
- a--;
- }
- if (a == 0) {
- ok = true;
- newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
- ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
- bp = newbp + nu->pntsu;
- ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- a = nu->pntsu;
- while (a--) {
- select_bpoint(bp, SELECT, flag, HIDDEN);
- select_bpoint(newbp, DESELECT, flag, HIDDEN);
- bp++;
- newbp++;
- }
+/**
+ * Calculate and return fully selected legs along i dimension.
+ * Calculates intervals to create extrusion by duplicating existing points while copied to
+ * destination NURBS. For ex. for curve of 3 points indexed by 0..2 to extrude first and last
+ * point copy intervals would be [0, 0][0, 2][2, 2]. Representation in copy_intervals array would
+ * be [0, 0, 2, 2]. Returns -1 if selection is not valid.
+ */
+static int sel_to_copy_ints(const BPoint *bp,
+ const int next_j,
+ const int max_j,
+ const int next_i,
+ const int max_i,
+ const uint8_t flag,
+ int copy_intervals[],
+ int *interval_count,
+ bool *out_is_first_sel)
+{
+ const BPoint *bp_j = bp;
- nu->pntsv = 2;
- nu->orderv = 2;
- BKE_nurb_knot_calc_v(nu);
- }
- }
- else {
- /* which row or column is selected */
+ int selected_leg_count = 0;
+ int ins = 0;
+ int selected_in_prev_leg = -1;
+ int not_full = -1;
- if (isNurbselUV(nu, flag, &u, &v)) {
+ bool is_first_sel = false;
+ bool is_last_sel = false;
- /* deselect all */
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- select_bpoint(bp, DESELECT, flag, HIDDEN);
- bp++;
- }
+ for (int j = 0; j < max_j; j++, bp_j += next_j) {
+ const BPoint *bp_j_i = bp_j;
+ int selected_in_curr_leg = 0;
+ for (int i = 0; i < max_i; i++, bp_j_i += next_i) {
+ if (bp_j_i->f1 & flag) {
+ selected_in_curr_leg++;
+ }
+ }
+ if (selected_in_curr_leg == max_i) {
+ selected_leg_count++;
+ if (j == 0) {
+ is_first_sel = true;
+ }
+ else if (j + 1 == max_j) {
+ is_last_sel = true;
+ }
+ }
+ else if (not_full == -1) {
+ not_full = selected_in_curr_leg;
+ }
+ /* We have partially selected leg in opposite dimension if condition is met. */
+ else if (not_full != selected_in_curr_leg) {
+ return -1;
+ }
+ /* Extrusion area starts/ends if met. */
+ if (selected_in_prev_leg != selected_in_curr_leg) {
+ copy_intervals[ins] = selected_in_curr_leg == max_i || j == 0 ? j : j - 1;
+ ins++;
+ selected_in_prev_leg = selected_in_curr_leg;
+ }
+ copy_intervals[ins] = j;
+ }
+ if (selected_leg_count &&
+ /* Prevents leading and trailing unselected legs if all selected.
+ * Unless it is extrusion from point or curve. */
+ (selected_leg_count < max_j || max_j == 1)) {
+ /* Prepend unselected leg if more than one leg selected at the starting edge.
+ * max_j == 1 handles extrusion from point to curve and from curve to surface cases. */
+ if (is_first_sel && (copy_intervals[0] < copy_intervals[1] || max_j == 1)) {
+ memmove(copy_intervals + 1, copy_intervals, (ins + 1) * sizeof(copy_intervals[0]));
+ copy_intervals[0] = 0;
+ ins++;
+ is_first_sel = false;
+ }
+ /* Append unselected leg if more than one leg selected at the end. */
+ if (is_last_sel && copy_intervals[ins - 1] < copy_intervals[ins]) {
+ copy_intervals[ins + 1] = copy_intervals[ins];
+ ins++;
+ }
+ }
+ *interval_count = ins;
+ *out_is_first_sel = ins > 1 ? is_first_sel : false;
+ return selected_leg_count;
+}
- if (ELEM(u, 0, nu->pntsv - 1)) { /* row in u-direction selected */
- ok = true;
- newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) * sizeof(BPoint),
- "extrudeNurb1");
- if (u == 0) {
- len = nu->pntsv * nu->pntsu;
- ED_curve_bpcpy(editnurb, newbp + nu->pntsu, nu->bp, len);
- ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
- bp = newbp;
- }
- else {
- len = nu->pntsv * nu->pntsu;
- ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
- ED_curve_bpcpy(editnurb, newbp + len, &nu->bp[len - nu->pntsu], nu->pntsu);
- bp = newbp + len;
- }
+typedef struct NurbDim {
+ int pntsu;
+ int pntsv;
+} NurbDim;
- a = nu->pntsu;
- while (a--) {
- select_bpoint(bp, SELECT, flag, HIDDEN);
- bp++;
- }
+static NurbDim editnurb_find_max_points_num(const EditNurb *editnurb)
+{
+ NurbDim ret = {0, 0};
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
+ if (nu->pntsu > ret.pntsu) {
+ ret.pntsu = nu->pntsu;
+ }
+ if (nu->pntsv > ret.pntsv) {
+ ret.pntsv = nu->pntsv;
+ }
+ }
+ return ret;
+}
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- nu->pntsv++;
- BKE_nurb_knot_calc_v(nu);
- }
- else if (ELEM(v, 0, nu->pntsu - 1)) { /* column in v-direction selected */
- ok = true;
- bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint),
- "extrudeNurb1");
- bp = nu->bp;
+bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
+{
+ const NurbDim max = editnurb_find_max_points_num(editnurb);
+ /* One point induces at most one interval. Except single point case, it can give + 1.
+ * Another +1 is for first element of the first interval. */
+ int *const intvls_u = MEM_malloc_arrayN(max.pntsu + 2, sizeof(int), "extrudeNurb0");
+ int *const intvls_v = MEM_malloc_arrayN(max.pntsv + 2, sizeof(int), "extrudeNurb1");
+ bool ok = false;
- for (a = 0; a < nu->pntsv; a++) {
- if (v == 0) {
- *bpn = *bp;
- bpn->f1 |= flag;
- bpn++;
- }
- ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
- bp += nu->pntsu;
- bpn += nu->pntsu;
- if (v == nu->pntsu - 1) {
- *bpn = *(bp - 1);
- bpn->f1 |= flag;
- bpn++;
- }
- }
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
+ int intvl_cnt_u;
+ bool is_first_sel_u;
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- nu->pntsu++;
- BKE_nurb_knot_calc_u(nu);
- }
- }
+ /* Calculate selected U legs and intervals for their extrusion. */
+ const int selected_us = sel_to_copy_ints(
+ nu->bp, 1, nu->pntsu, nu->pntsu, nu->pntsv, flag, intvls_u, &intvl_cnt_u, &is_first_sel_u);
+ if (selected_us == -1) {
+ continue;
}
- }
+ int intvl_cnt_v;
+ bool is_first_sel_v;
+ const bool is_point = nu->pntsu == 1;
+ const bool is_curve = nu->pntsv == 1;
+ const bool extrude_every_u_point = selected_us == nu->pntsu;
+ if (is_point || (is_curve && !extrude_every_u_point)) {
+ intvls_v[0] = intvls_v[1] = 0;
+ intvl_cnt_v = 1;
+ is_first_sel_v = false;
+ }
+ else {
+ sel_to_copy_ints(nu->bp,
+ nu->pntsu,
+ nu->pntsv,
+ 1,
+ nu->pntsu,
+ flag,
+ intvls_v,
+ &intvl_cnt_v,
+ &is_first_sel_v);
+ }
+
+ const int new_pntsu = nu->pntsu + intvl_cnt_u - 1;
+ const int new_pntsv = nu->pntsv + intvl_cnt_v - 1;
+ BPoint *const new_bp = (BPoint *)MEM_malloc_arrayN(
+ new_pntsu * new_pntsv, sizeof(BPoint), "extrudeNurb2");
+ BPoint *new_bp_v = new_bp;
+
+ bool selected_v = is_first_sel_v;
+ for (int j = 1; j <= intvl_cnt_v; j++, selected_v = !selected_v) {
+ BPoint *old_bp_v = nu->bp + intvls_v[j - 1] * nu->pntsu;
+ for (int v_j = intvls_v[j - 1]; v_j <= intvls_v[j];
+ v_j++, new_bp_v += new_pntsu, old_bp_v += nu->pntsu) {
+ BPoint *new_bp_u_v = new_bp_v;
+ bool selected_u = is_first_sel_u;
+ for (int i = 1; i <= intvl_cnt_u; i++, selected_u = !selected_u) {
+ const int copy_from = intvls_u[i - 1];
+ const int copy_to = intvls_u[i];
+ const int copy_count = copy_to - copy_from + 1;
+ const bool sel_status = selected_u || selected_v ? true : false;
+ ED_curve_bpcpy(editnurb, new_bp_u_v, old_bp_v + copy_from, copy_count);
+ select_bpoints(new_bp_u_v, 1, copy_count, sel_status, flag, HIDDEN);
+ new_bp_u_v += copy_count;
+ }
+ }
+ }
+
+ MEM_freeN(nu->bp);
+ nu->bp = new_bp;
+ nu->pntsu = new_pntsu;
+ if (nu->pntsv == 1 && new_pntsv > 1) {
+ nu->orderv = 2;
+ }
+ nu->pntsv = new_pntsv;
+ BKE_nurb_knot_calc_u(nu);
+ BKE_nurb_knot_calc_v(nu);
+
+ ok = true;
+ }
+ MEM_freeN(intvls_u);
+ MEM_freeN(intvls_v);
return ok;
}
@@ -2133,7 +2153,7 @@ static void adduplicateflagNurb(
starta = a;
while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) {
if (!split) {
- select_beztriple(bezt, DESELECT, flag, HIDDEN);
+ select_beztriple(bezt, false, flag, HIDDEN);
}
enda = a;
if (a >= nu->pntsu - 1) {
@@ -2173,7 +2193,7 @@ static void adduplicateflagNurb(
}
for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
- select_beztriple(bezt1, SELECT, flag, HIDDEN);
+ select_beztriple(bezt1, true, flag, HIDDEN);
}
BLI_addtail(newnurb, newnu);
@@ -2191,7 +2211,7 @@ static void adduplicateflagNurb(
newnu->flagu &= ~CU_NURB_CYCLIC;
for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
- select_beztriple(bezt1, SELECT, flag, HIDDEN);
+ select_beztriple(bezt1, true, flag, HIDDEN);
}
BLI_addtail(newnurb, newnu);
@@ -2203,7 +2223,7 @@ static void adduplicateflagNurb(
starta = a;
while (bp->f1 & flag) {
if (!split) {
- select_bpoint(bp, DESELECT, flag, HIDDEN);
+ select_bpoint(bp, false, flag, HIDDEN);
}
enda = a;
if (a >= nu->pntsu - 1) {
@@ -2243,7 +2263,7 @@ static void adduplicateflagNurb(
}
for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
- select_bpoint(bp1, SELECT, flag, HIDDEN);
+ select_bpoint(bp1, true, flag, HIDDEN);
}
BLI_addtail(newnurb, newnu);
@@ -2261,7 +2281,7 @@ static void adduplicateflagNurb(
newnu->flagu &= ~CU_NURB_CYCLIC;
for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
- select_bpoint(bp1, SELECT, flag, HIDDEN);
+ select_bpoint(bp1, true, flag, HIDDEN);
}
BLI_addtail(newnurb, newnu);
@@ -2481,7 +2501,7 @@ static void adduplicateflagNurb(
for (b = 0, bp1 = nu->bp; b < nu->pntsu * nu->pntsv; b++, bp1++) {
bp1->f1 &= ~SURF_SEEN;
if (!split) {
- select_bpoint(bp1, DESELECT, flag, HIDDEN);
+ select_bpoint(bp1, false, flag, HIDDEN);
}
}
}
@@ -3216,11 +3236,11 @@ static int hide_exec(bContext *C, wmOperator *op)
sel = 0;
while (a--) {
if (invert == 0 && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, false, SELECT, HIDDEN);
bezt->hide = 1;
}
else if (invert && !BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, false, SELECT, HIDDEN);
bezt->hide = 1;
}
if (bezt->hide) {
@@ -3238,11 +3258,11 @@ static int hide_exec(bContext *C, wmOperator *op)
sel = 0;
while (a--) {
if (invert == 0 && (bp->f1 & SELECT)) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ select_bpoint(bp, false, SELECT, HIDDEN);
bp->hide = 1;
}
else if (invert && (bp->f1 & SELECT) == 0) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ select_bpoint(bp, false, SELECT, HIDDEN);
bp->hide = 1;
}
if (bp->hide) {
@@ -4332,7 +4352,7 @@ static bool merge_2_nurb(Curve *cu, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
keyIndex_updateBP(cu->editnurb, bp1, bp, 1);
*bp = *bp1;
bp1++;
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ select_bpoint(bp, true, SELECT, HIDDEN);
}
else {
keyIndex_updateBP(cu->editnurb, bp2, bp, 1);
@@ -4787,7 +4807,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
bezt->f2 |= SELECT;
}
else {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, true, SELECT, HIDDEN);
}
}
else {
@@ -4801,7 +4821,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ select_bpoint(bp, true, SELECT, HIDDEN);
BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
break;
@@ -4813,7 +4833,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
bezt->f2 &= ~SELECT;
}
else {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, false, SELECT, HIDDEN);
}
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
@@ -4827,7 +4847,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
}
}
else {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ select_bpoint(bp, false, SELECT, HIDDEN);
if (bp == vert) {
cu->actvert = CU_ACT_NONE;
}
@@ -4842,7 +4862,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
bezt->f2 &= ~SELECT;
}
else {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, false, SELECT, HIDDEN);
}
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
@@ -4853,7 +4873,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
bezt->f2 |= SELECT;
}
else {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, true, SELECT, HIDDEN);
}
BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
@@ -4867,13 +4887,13 @@ bool ED_curve_editnurb_select_pick(bContext *C,
}
else {
if (bp->f1 & SELECT) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ select_bpoint(bp, false, SELECT, HIDDEN);
if (bp == vert) {
cu->actvert = CU_ACT_NONE;
}
}
else {
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ select_bpoint(bp, true, SELECT, HIDDEN);
BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
}
@@ -4889,7 +4909,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
bezt->f2 |= SELECT;
}
else {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, true, SELECT, HIDDEN);
}
}
else {
@@ -4903,7 +4923,7 @@ bool ED_curve_editnurb_select_pick(bContext *C,
BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ select_bpoint(bp, true, SELECT, HIDDEN);
BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
break;
@@ -5562,7 +5582,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Curve *cu;
float location[3];
const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
- (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
+ (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST));
Nurb *nu;
BezTriple *bezt;
@@ -5595,12 +5615,13 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
vc.depsgraph,
vc.region,
vc.v3d,
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
.snap_target_select = (vc.obedit != NULL) ? SCE_SNAP_TARGET_NOT_ACTIVE :
SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
},
+ NULL,
mval,
NULL,
NULL,
@@ -5694,23 +5715,12 @@ static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
bool changed = false;
- bool as_curve = false;
if (!ED_curve_select_check(v3d, cu->editnurb)) {
continue;
}
- /* First test: curve? */
- if (obedit->type != OB_CURVES_LEGACY) {
- LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
- if ((nu->pntsv == 1) && (ED_curve_nurb_select_count(v3d, nu) < nu->pntsu)) {
- as_curve = true;
- break;
- }
- }
- }
-
- if (obedit->type == OB_CURVES_LEGACY || as_curve) {
+ if (obedit->type == OB_CURVES_LEGACY) {
changed = ed_editcurve_extrude(cu, editnurb, v3d);
}
else {
@@ -6396,7 +6406,7 @@ static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split)
if (split) {
/* deselect for split operator */
for (b = 0, bezt1 = nu->bezt; b < nu->pntsu; b++, bezt1++) {
- select_beztriple(bezt1, DESELECT, SELECT, true);
+ select_beztriple(bezt1, false, SELECT, true);
}
}
@@ -6406,7 +6416,7 @@ static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split)
if (split) {
/* deselect for split operator */
for (b = 0, bp1 = nu->bp; b < nu->pntsu * nu->pntsv; b++, bp1++) {
- select_bpoint(bp1, DESELECT, SELECT, HIDDEN);
+ select_bpoint(bp1, false, SELECT, HIDDEN);
}
}
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index ba5a7409ba7..a21c8fc85f8 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -18,6 +18,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -87,6 +88,8 @@ static const char *get_surf_defname(int type)
return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfCircle");
case CU_PRIM_PATCH:
return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfPatch");
+ case CU_PRIM_TUBE:
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfCylinder");
case CU_PRIM_SPHERE:
return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfSphere");
case CU_PRIM_DONUT:
@@ -493,7 +496,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
struct Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
ListBase *editnurb;
Nurb *nu;
bool newob = false;
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 6946c09e6f1..7632f1b1e64 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -1162,7 +1162,7 @@ static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
curve_draw_event_add_first(op, event);
}
}
- else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ else if (ISMOUSE_MOTION(event->type)) {
if (cdd->state == CURVE_DRAW_PAINTING) {
const float mval_fl[2] = {UNPACK2(event->mval)};
if (len_squared_v2v2(mval_fl, cdd->prev.mval) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c
index 729ad46877a..27f4e4fca61 100644
--- a/source/blender/editors/curve/editcurve_pen.c
+++ b/source/blender/editors/curve/editcurve_pen.c
@@ -1622,7 +1622,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (ISMOUSE_MOTION(event->type)) {
/* Check if dragging */
if (!cpd->dragging && WM_event_drag_test(event, event->prev_press_xy)) {
cpd->dragging = true;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 5a1777b7097..b7e6827c6df 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -30,7 +30,6 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
-#include "ED_types.h"
#include "ED_view3d.h"
#include "curve_intern.h"
@@ -47,7 +46,7 @@
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
{
if ((bezt->hide == 0) || (hidden == HIDDEN)) {
- if (selstatus == SELECT) { /* selects */
+ if (selstatus) { /* selects */
bezt->f1 |= flag;
bezt->f2 |= flag;
bezt->f3 |= flag;
@@ -66,7 +65,7 @@ bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Ty
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
{
if ((bp->hide == 0) || (hidden == 1)) {
- if (selstatus == SELECT) {
+ if (selstatus) {
bp->f1 |= flag;
return true;
}
@@ -80,17 +79,17 @@ bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
static bool swap_selection_beztriple(BezTriple *bezt)
{
if (bezt->f2 & SELECT) {
- return select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
+ return select_beztriple(bezt, false, SELECT, VISIBLE);
}
- return select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ return select_beztriple(bezt, true, SELECT, VISIBLE);
}
static bool swap_selection_bpoint(BPoint *bp)
{
if (bp->f1 & SELECT) {
- return select_bpoint(bp, DESELECT, SELECT, VISIBLE);
+ return select_bpoint(bp, false, SELECT, VISIBLE);
}
- return select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ return select_bpoint(bp, true, SELECT, VISIBLE);
}
bool ED_curve_nurb_select_check(const View3D *v3d, const Nurb *nu)
@@ -336,9 +335,9 @@ static void select_adjacent_cp(ListBase *editnurb,
break;
}
if ((lastsel == false) && (bezt->hide == 0) &&
- ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
+ ((bezt->f2 & SELECT) || (selstatus == false))) {
bezt += next;
- if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
+ if (!(bezt->f2 & SELECT) || (selstatus == false)) {
bool sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
if (sel && !cont) {
lastsel = true;
@@ -363,10 +362,9 @@ static void select_adjacent_cp(ListBase *editnurb,
if (a - abs(next) < 0) {
break;
}
- if ((lastsel == false) && (bp->hide == 0) &&
- ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
+ if ((lastsel == false) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == false))) {
bp += next;
- if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
+ if (!(bp->f1 & SELECT) || (selstatus == false)) {
bool sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
if (sel && !cont) {
lastsel = true;
@@ -477,7 +475,7 @@ static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- selectend_nurb(obedit, FIRST, true, DESELECT);
+ selectend_nurb(obedit, FIRST, true, false);
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
BKE_curve_nurb_vert_active_validate(obedit->data);
@@ -510,7 +508,7 @@ static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- selectend_nurb(obedit, LAST, true, DESELECT);
+ selectend_nurb(obedit, LAST, true, false);
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
BKE_curve_nurb_vert_active_validate(obedit->data);
@@ -780,12 +778,12 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
for (b = 0; b < nu->pntsu; b++, bp++) {
if (direction) {
if (a == v) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ select_bpoint(bp, true, SELECT, VISIBLE);
}
}
else {
if (b == u) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ select_bpoint(bp, true, SELECT, VISIBLE);
}
}
}
@@ -923,7 +921,7 @@ static void curve_select_more(Object *obedit)
if (a % nu->pntsu != 0) {
tempbp = bp - 1;
if (!(tempbp->f1 & SELECT)) {
- select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ select_bpoint(tempbp, true, SELECT, VISIBLE);
}
}
@@ -932,7 +930,7 @@ static void curve_select_more(Object *obedit)
sel = 0;
tempbp = bp + nu->pntsu;
if (!(tempbp->f1 & SELECT)) {
- sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ sel = select_bpoint(tempbp, true, SELECT, VISIBLE);
}
/* make sure selected bpoint is discarded */
if (sel == 1) {
@@ -944,7 +942,7 @@ static void curve_select_more(Object *obedit)
if (a + nu->pntsu < nu->pntsu * nu->pntsv) {
tempbp = bp - nu->pntsu;
if (!(tempbp->f1 & SELECT)) {
- select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ select_bpoint(tempbp, true, SELECT, VISIBLE);
}
}
@@ -953,7 +951,7 @@ static void curve_select_more(Object *obedit)
sel = 0;
tempbp = bp + 1;
if (!(tempbp->f1 & SELECT)) {
- sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ sel = select_bpoint(tempbp, true, SELECT, VISIBLE);
}
if (sel) {
bp++;
@@ -1080,7 +1078,7 @@ static void curve_select_less(Object *obedit)
}
if (sel != 4) {
- select_bpoint(bp, DESELECT, SELECT, VISIBLE);
+ select_bpoint(bp, false, SELECT, VISIBLE);
BLI_BITMAP_ENABLE(selbpoints, a);
}
}
@@ -1130,7 +1128,7 @@ static void curve_select_less(Object *obedit)
}
if (sel != 2) {
- select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
+ select_beztriple(bezt, false, SELECT, VISIBLE);
lastsel = true;
}
else {
@@ -1175,7 +1173,7 @@ static void curve_select_less(Object *obedit)
}
if (sel != 2) {
- select_bpoint(bp, DESELECT, SELECT, VISIBLE);
+ select_bpoint(bp, false, SELECT, VISIBLE);
lastsel = true;
}
else {
@@ -1359,7 +1357,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerInter
while (a--) {
const int depth = abs(start - a);
if (!WM_operator_properties_checker_interval_test(params, depth)) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ select_beztriple(bezt, false, SELECT, HIDDEN);
}
bezt--;
@@ -1382,7 +1380,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalPara
while (a--) {
const int depth = abs(pnt - startpnt) + abs(row - startrow);
if (!WM_operator_properties_checker_interval_test(params, depth)) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ select_bpoint(bp, false, SELECT, HIDDEN);
}
pnt--;
@@ -1645,7 +1643,7 @@ static bool curve_nurb_select_similar_type(Object *ob,
}
if (select) {
- select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ select_beztriple(bezt, true, SELECT, VISIBLE);
changed = true;
}
}
@@ -1690,7 +1688,7 @@ static bool curve_nurb_select_similar_type(Object *ob,
}
if (select) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ select_bpoint(bp, true, SELECT, VISIBLE);
changed = true;
}
}
@@ -1898,10 +1896,10 @@ static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_ds
i = vert_src;
while (true) {
if (nu->type & CU_BEZIER) {
- select_beztriple(&nu->bezt[i], SELECT, SELECT, HIDDEN);
+ select_beztriple(&nu->bezt[i], true, SELECT, HIDDEN);
}
else {
- select_bpoint(&nu->bp[i], SELECT, SELECT, HIDDEN);
+ select_bpoint(&nu->bp[i], true, SELECT, HIDDEN);
}
if (i == vert_dst) {
@@ -1979,10 +1977,10 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
int i = 0;
while (vert_curr != vert_src && i++ < vert_num) {
if (nu->type == CU_BEZIER) {
- select_beztriple(&nu->bezt[vert_curr], SELECT, SELECT, HIDDEN);
+ select_beztriple(&nu->bezt[vert_curr], true, SELECT, HIDDEN);
}
else {
- select_bpoint(&nu->bp[vert_curr], SELECT, SELECT, HIDDEN);
+ select_bpoint(&nu->bp[vert_curr], true, SELECT, HIDDEN);
}
vert_curr = data[vert_curr].vert_prev;
}
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 888bb2169e0..cd350e8bd3c 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -161,7 +161,7 @@ static void undocurve_free_data(UndoCurve *uc)
static Object *editcurve_object_from_context(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit && ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
Curve *cu = obedit->data;
if (BKE_curve_editNurbs_get(cu) != NULL) {
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 611dbb2e80c..ceed12dcff1 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -59,7 +59,7 @@ static int kill_selection(Object *obedit, int ins);
/** \name Internal Utilities
* \{ */
-static char32_t findaccent(char32_t char1, uint code)
+static char32_t findaccent(char32_t char1, const char code)
{
char32_t new = 0;
@@ -1638,12 +1638,11 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
- static int accentcode = 0;
- uintptr_t ascii = event->ascii;
+ static bool accentcode = false;
const bool alt = event->modifier & KM_ALT;
const bool shift = event->modifier & KM_SHIFT;
const bool ctrl = event->modifier & KM_CTRL;
- int event_type = event->type, event_val = event->val;
+ char32_t insert_char_override = 0;
char32_t inserted_text[2] = {0};
if (RNA_struct_property_is_set(op->ptr, "text")) {
@@ -1652,48 +1651,47 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (RNA_struct_property_is_set(op->ptr, "accent")) {
if (ef->len != 0 && ef->pos > 0) {
- accentcode = 1;
+ accentcode = true;
}
return OPERATOR_FINISHED;
}
- /* tab should exit editmode, but we allow it to be typed using modifier keys */
- if (event_type == EVT_TABKEY) {
- if ((alt || ctrl || shift) == 0) {
- return OPERATOR_PASS_THROUGH;
- }
-
- ascii = 9;
- }
-
- if (event_type == EVT_BACKSPACEKEY) {
+ if (event->type == EVT_BACKSPACEKEY) {
if (alt && ef->len != 0 && ef->pos > 0) {
- accentcode = 1;
+ accentcode = true;
}
return OPERATOR_PASS_THROUGH;
}
- if (event_val && (ascii || event->utf8_buf[0])) {
- /* handle case like TAB (== 9) */
- if ((ascii > 31 && ascii < 254 && ascii != 127) || (ELEM(ascii, 13, 10)) || (ascii == 8) ||
- (event->utf8_buf[0])) {
+ /* Tab typically exit edit-mode, but we allow it to be typed using modifier keys. */
+ if (event->type == EVT_TABKEY) {
+ if ((alt || ctrl || shift) == 0) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ insert_char_override = '\t';
+ }
+ if (insert_char_override || event->utf8_buf[0]) {
+ if (insert_char_override) {
+ /* Handle case like TAB ('\t'). */
+ inserted_text[0] = insert_char_override;
+ insert_into_textbuf(obedit, insert_char_override);
+ text_update_edited(C, obedit, FO_EDIT);
+ }
+ else {
+ BLI_assert(event->utf8_buf[0]);
if (accentcode) {
if (ef->pos > 0) {
- inserted_text[0] = findaccent(ef->textbuf[ef->pos - 1], ascii);
+ inserted_text[0] = findaccent(ef->textbuf[ef->pos - 1],
+ BLI_str_utf8_as_unicode(event->utf8_buf));
ef->textbuf[ef->pos - 1] = inserted_text[0];
}
- accentcode = 0;
+ accentcode = false;
}
else if (event->utf8_buf[0]) {
inserted_text[0] = BLI_str_utf8_as_unicode(event->utf8_buf);
- ascii = inserted_text[0];
- insert_into_textbuf(obedit, ascii);
- accentcode = 0;
- }
- else if (ascii) {
- insert_into_textbuf(obedit, ascii);
- accentcode = 0;
+ insert_into_textbuf(obedit, inserted_text[0]);
+ accentcode = false;
}
else {
BLI_assert(0);
@@ -1702,11 +1700,6 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
kill_selection(obedit, 1);
text_update_edited(C, obedit, FO_EDIT);
}
- else {
- inserted_text[0] = ascii;
- insert_into_textbuf(obedit, ascii);
- text_update_edited(C, obedit, FO_EDIT);
- }
}
else {
return OPERATOR_PASS_THROUGH;
@@ -1720,11 +1713,6 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_string_set(op->ptr, "text", inserted_utf8);
}
- /* reset property? */
- if (event_val == 0) {
- accentcode = 0;
- }
-
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 09e5428b0f9..06d2357dc89 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -19,6 +19,7 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_undo_system.h"
#include "BKE_vfont.h"
@@ -308,7 +309,7 @@ static void undofont_free_data(UndoFont *uf)
static Object *editfont_object_from_context(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit && obedit->type == OB_FONT) {
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt
index 3c31e8014ff..945bba0a77c 100644
--- a/source/blender/editors/curves/CMakeLists.txt
+++ b/source/blender/editors/curves/CMakeLists.txt
@@ -8,10 +8,12 @@ set(INC
../../depsgraph
../../functions
../../geometry
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../bmesh
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -27,5 +29,17 @@ set(LIB
bf_blenlib
)
+if(WITH_TBB)
+ list(APPEND INC_SYS
+ ${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()
+
blender_add_lib(bf_editor_curves "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_dependencies(bf_editor_curves bf_rna)
diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc
index 552ef1d96c8..f234a58f439 100644
--- a/source/blender/editors/curves/intern/curves_add.cc
+++ b/source/blender/editors/curves/intern/curves_add.cc
@@ -6,22 +6,105 @@
#include "BLI_rand.hh"
+#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "ED_curves.h"
+#include "ED_node.h"
+#include "ED_object.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
namespace blender::ed::curves {
+static bool has_surface_deformation_node(const bNodeTree &ntree)
+{
+ LISTBASE_FOREACH (const bNode *, node, &ntree.nodes) {
+ if (node->type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) {
+ return true;
+ }
+ if (node->type == NODE_GROUP) {
+ if (node->id != nullptr) {
+ if (has_surface_deformation_node(*reinterpret_cast<const bNodeTree *>(node->id))) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool has_surface_deformation_node(const Object &curves_ob)
+{
+ LISTBASE_FOREACH (const ModifierData *, md, &curves_ob.modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
+ if (nmd->node_group == nullptr) {
+ continue;
+ }
+ if (has_surface_deformation_node(*nmd->node_group)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
+{
+ if (has_surface_deformation_node(curves_ob)) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(&C);
+ Scene *scene = CTX_data_scene(&C);
+
+ ModifierData *md = ED_object_modifier_add(
+ nullptr, bmain, scene, &curves_ob, "Surface Deform", eModifierType_Nodes);
+ NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
+ nmd.node_group = ntreeAddTree(bmain, "Surface Deform", "GeometryNodeTree");
+
+ bNodeTree *ntree = nmd.node_group;
+ ntreeAddSocketInterface(ntree, SOCK_IN, "NodeSocketGeometry", "Geometry");
+ ntreeAddSocketInterface(ntree, SOCK_OUT, "NodeSocketGeometry", "Geometry");
+ bNode *group_input = nodeAddStaticNode(&C, ntree, NODE_GROUP_INPUT);
+ bNode *group_output = nodeAddStaticNode(&C, ntree, NODE_GROUP_OUTPUT);
+ bNode *deform_node = nodeAddStaticNode(&C, ntree, GEO_NODE_DEFORM_CURVES_ON_SURFACE);
+
+ ED_node_tree_propagate_change(&C, bmain, nmd.node_group);
+
+ nodeAddLink(ntree,
+ group_input,
+ static_cast<bNodeSocket *>(group_input->outputs.first),
+ deform_node,
+ nodeFindSocket(deform_node, SOCK_IN, "Curves"));
+ nodeAddLink(ntree,
+ deform_node,
+ nodeFindSocket(deform_node, SOCK_OUT, "Curves"),
+ group_output,
+ static_cast<bNodeSocket *>(group_output->inputs.first));
+
+ group_input->locx = -200;
+ group_output->locx = 200;
+ deform_node->locx = 0;
+
+ ED_node_tree_propagate_change(&C, bmain, nmd.node_group);
+}
+
bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int points_per_curve)
{
bke::CurvesGeometry curves(points_per_curve * curves_size, curves_size);
MutableSpan<int> offsets = curves.offsets_for_write();
MutableSpan<float3> positions = curves.positions_for_write();
-
- float *radius_data = (float *)CustomData_add_layer_named(
- &curves.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, curves.point_num, "radius");
- MutableSpan<float> radii{radius_data, curves.points_num()};
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+ bke::SpanAttributeWriter<float> radius = attributes.lookup_or_add_for_write_only_span<float>(
+ "radius", ATTR_DOMAIN_POINT);
for (const int i : offsets.index_range()) {
offsets[i] = points_per_curve * i;
@@ -30,9 +113,9 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi
RandomNumberGenerator rng;
for (const int i : curves.curves_range()) {
- const IndexRange curve_range = curves.points_for_curve(i);
- MutableSpan<float3> curve_positions = positions.slice(curve_range);
- MutableSpan<float> curve_radii = radii.slice(curve_range);
+ const IndexRange points = curves.points_for_curve(i);
+ MutableSpan<float3> curve_positions = positions.slice(points);
+ MutableSpan<float> curve_radii = radius.span.slice(points);
const float theta = 2.0f * M_PI * rng.get_float();
const float phi = saacosf(2.0f * rng.get_float() - 1.0f);
@@ -51,6 +134,8 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi
}
}
+ radius.finish();
+
return curves;
}
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index 25bcba6cfb3..2386fd1030d 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -25,6 +25,7 @@
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -72,7 +73,7 @@ static bool object_has_editable_curves(const Main &bmain, const Object &object)
return true;
}
-static VectorSet<Curves *> get_unique_editable_curves(const bContext &C)
+VectorSet<Curves *> get_unique_editable_curves(const bContext &C)
{
VectorSet<Curves *> unique_curves;
@@ -93,11 +94,53 @@ static VectorSet<Curves *> get_unique_editable_curves(const bContext &C)
return unique_curves;
}
+static bool curves_poll_impl(bContext *C, const bool check_editable, const bool check_surface)
+{
+ Object *object = CTX_data_active_object(C);
+ if (object == nullptr || object->type != OB_CURVES) {
+ return false;
+ }
+ if (check_editable) {
+ if (!ED_operator_object_active_editable_ex(C, object)) {
+ return false;
+ }
+ }
+ if (check_surface) {
+ Curves &curves = *static_cast<Curves *>(object->data);
+ if (curves.surface == nullptr || curves.surface->type != OB_MESH) {
+ CTX_wm_operator_poll_msg_set(C, "Curves must have a mesh surface object set");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool editable_curves_with_surface_poll(bContext *C)
+{
+ return curves_poll_impl(C, true, true);
+}
+
+bool curves_with_surface_poll(bContext *C)
+{
+ return curves_poll_impl(C, false, true);
+}
+
+bool editable_curves_poll(bContext *C)
+{
+ return curves_poll_impl(C, false, false);
+}
+
+bool curves_poll(bContext *C)
+{
+ return curves_poll_impl(C, false, false);
+}
+
using bke::CurvesGeometry;
namespace convert_to_particle_system {
-static int find_mface_for_root_position(const Mesh &mesh,
+static int find_mface_for_root_position(const Span<MVert> verts,
+ const MFace *mface,
const Span<int> possible_mface_indices,
const float3 &root_pos)
{
@@ -109,14 +152,14 @@ static int find_mface_for_root_position(const Mesh &mesh,
int mface_i;
float best_distance_sq = FLT_MAX;
for (const int possible_mface_i : possible_mface_indices) {
- const MFace &possible_mface = mesh.mface[possible_mface_i];
+ const MFace &possible_mface = mface[possible_mface_i];
{
float3 point_in_triangle;
closest_on_tri_to_point_v3(point_in_triangle,
root_pos,
- mesh.mvert[possible_mface.v1].co,
- mesh.mvert[possible_mface.v2].co,
- mesh.mvert[possible_mface.v3].co);
+ verts[possible_mface.v1].co,
+ verts[possible_mface.v2].co,
+ verts[possible_mface.v3].co);
const float distance_sq = len_squared_v3v3(root_pos, point_in_triangle);
if (distance_sq < best_distance_sq) {
best_distance_sq = distance_sq;
@@ -128,9 +171,9 @@ static int find_mface_for_root_position(const Mesh &mesh,
float3 point_in_triangle;
closest_on_tri_to_point_v3(point_in_triangle,
root_pos,
- mesh.mvert[possible_mface.v1].co,
- mesh.mvert[possible_mface.v3].co,
- mesh.mvert[possible_mface.v4].co);
+ verts[possible_mface.v1].co,
+ verts[possible_mface.v3].co,
+ verts[possible_mface.v4].co);
const float distance_sq = len_squared_v3v3(root_pos, point_in_triangle);
if (distance_sq < best_distance_sq) {
best_distance_sq = distance_sq;
@@ -144,25 +187,22 @@ static int find_mface_for_root_position(const Mesh &mesh,
/**
* \return Barycentric coordinates in the #MFace.
*/
-static float4 compute_mface_weights_for_position(const Mesh &mesh,
+static float4 compute_mface_weights_for_position(const Span<MVert> verts,
const MFace &mface,
const float3 &position)
{
float4 mface_weights;
if (mface.v4) {
float mface_verts_su[4][3];
- copy_v3_v3(mface_verts_su[0], mesh.mvert[mface.v1].co);
- copy_v3_v3(mface_verts_su[1], mesh.mvert[mface.v2].co);
- copy_v3_v3(mface_verts_su[2], mesh.mvert[mface.v3].co);
- copy_v3_v3(mface_verts_su[3], mesh.mvert[mface.v4].co);
+ copy_v3_v3(mface_verts_su[0], verts[mface.v1].co);
+ copy_v3_v3(mface_verts_su[1], verts[mface.v2].co);
+ copy_v3_v3(mface_verts_su[2], verts[mface.v3].co);
+ copy_v3_v3(mface_verts_su[3], verts[mface.v4].co);
interp_weights_poly_v3(mface_weights, mface_verts_su, 4, position);
}
else {
- interp_weights_tri_v3(mface_weights,
- mesh.mvert[mface.v1].co,
- mesh.mvert[mface.v2].co,
- mesh.mvert[mface.v3].co,
- position);
+ interp_weights_tri_v3(
+ mface_weights, verts[mface.v1].co, verts[mface.v2].co, verts[mface.v3].co, position);
mface_weights[3] = 0.0f;
}
return mface_weights;
@@ -243,17 +283,17 @@ static void try_convert_single_object(Object &curves_ob,
}
/* Prepare transformation matrices. */
- const float4x4 curves_to_world_mat = curves_ob.obmat;
- const float4x4 surface_to_world_mat = surface_ob.obmat;
- const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
- const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
+ const bke::CurvesSurfaceTransforms transforms{curves_ob, &surface_ob};
+
+ const MFace *mfaces = (const MFace *)CustomData_get_layer(&surface_me.fdata, CD_MFACE);
+ const Span<MVert> verts = surface_me.verts();
for (const int new_hair_i : IndexRange(hair_num)) {
const int curve_i = new_hair_i;
const IndexRange points = curves.points_for_curve(curve_i);
const float3 &root_pos_cu = positions_cu[points.first()];
- const float3 root_pos_su = curves_to_surface_mat * root_pos_cu;
+ const float3 root_pos_su = transforms.curves_to_surface * root_pos_cu;
BVHTreeNearest nearest;
nearest.dist_sq = FLT_MAX;
@@ -266,11 +306,10 @@ static void try_convert_single_object(Object &curves_ob,
const int poly_i = looptri.poly;
const int mface_i = find_mface_for_root_position(
- surface_me, poly_to_mface_map[poly_i], root_pos_su);
- const MFace &mface = surface_me.mface[mface_i];
+ verts, mfaces, poly_to_mface_map[poly_i], root_pos_su);
+ const MFace &mface = mfaces[mface_i];
- const float4 mface_weights = compute_mface_weights_for_position(
- surface_me, mface, root_pos_su);
+ const float4 mface_weights = compute_mface_weights_for_position(verts, mface, root_pos_su);
ParticleData &particle = particles[new_hair_i];
const int num_keys = points.size();
@@ -293,7 +332,7 @@ static void try_convert_single_object(Object &curves_ob,
for (const int key_i : hair_keys.index_range()) {
const float3 &key_pos_cu = positions_cu[points[key_i]];
- const float3 key_pos_su = curves_to_surface_mat * key_pos_cu;
+ const float3 key_pos_su = transforms.curves_to_surface * key_pos_cu;
const float3 key_pos_ha = surface_to_hair_mat * key_pos_su;
HairKey &key = hair_keys[key_i];
@@ -339,16 +378,6 @@ static int curves_convert_to_particle_system_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static bool curves_convert_to_particle_system_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- if (ob == nullptr || ob->type != OB_CURVES) {
- return false;
- }
- Curves &curves = *static_cast<Curves *>(ob->data);
- return curves.surface != nullptr;
-}
-
} // namespace convert_to_particle_system
static void CURVES_OT_convert_to_particle_system(wmOperatorType *ot)
@@ -357,7 +386,7 @@ static void CURVES_OT_convert_to_particle_system(wmOperatorType *ot)
ot->idname = "CURVES_OT_convert_to_particle_system";
ot->description = "Add a new or update an existing hair particle system on the surface object";
- ot->poll = convert_to_particle_system::curves_convert_to_particle_system_poll;
+ ot->poll = curves_with_surface_poll;
ot->exec = convert_to_particle_system::curves_convert_to_particle_system_exec;
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
@@ -467,7 +496,6 @@ static int curves_convert_from_particle_system_exec(bContext *C, wmOperator *UNU
}
Object *ob_new = BKE_object_add(&bmain, &view_layer, OB_CURVES, psys_eval->name);
- ob_new->dtx |= OB_DRAWBOUNDOX; /* TODO: Remove once there is actual drawing. */
Curves *curves_id = static_cast<Curves *>(ob_new->data);
BKE_object_apply_mat4(ob_new, ob_from_orig->obmat, true, false);
bke::CurvesGeometry::wrap(curves_id->geometry) = particles_to_curves(*ob_from_eval, *psys_eval);
@@ -504,174 +532,169 @@ enum class AttachMode {
Deform,
};
-static bool snap_curves_to_surface_poll(bContext *C)
+static void snap_curves_to_surface_exec_object(Object &curves_ob,
+ const Object &surface_ob,
+ const AttachMode attach_mode,
+ bool *r_invalid_uvs,
+ bool *r_missing_uvs)
{
- Object *ob = CTX_data_active_object(C);
- if (ob == nullptr || ob->type != OB_CURVES) {
- return false;
- }
- if (!ED_operator_object_active_editable_ex(C, ob)) {
- return false;
+ Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+
+ const Mesh &surface_mesh = *static_cast<const Mesh *>(surface_ob.data);
+ const Span<MVert> verts = surface_mesh.verts();
+ const Span<MLoop> loops = surface_mesh.loops();
+ const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
+ BKE_mesh_runtime_looptri_len(&surface_mesh)};
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id.surface_uv_map != nullptr) {
+ const bke::AttributeAccessor surface_attributes = surface_mesh.attributes();
+ surface_uv_map = surface_attributes
+ .lookup(curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
+ .typed<float2>();
}
- Curves &curves = *static_cast<Curves *>(ob->data);
- if (curves.surface == nullptr) {
- return false;
+
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
+
+ const bke::CurvesSurfaceTransforms transforms{curves_ob, &surface_ob};
+
+ switch (attach_mode) {
+ case AttachMode::Nearest: {
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_point_pos_cu = positions_cu[first_point_i];
+ const float3 old_first_point_pos_su = transforms.curves_to_surface *
+ old_first_point_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh.tree,
+ old_first_point_pos_su,
+ &nearest,
+ surface_bvh.nearest_callback,
+ &surface_bvh);
+ const int looptri_index = nearest.index;
+ if (looptri_index == -1) {
+ continue;
+ }
+
+ const float3 new_first_point_pos_su = nearest.co;
+ const float3 new_first_point_pos_cu = transforms.surface_to_curves *
+ new_first_point_pos_su;
+ const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
+
+ for (float3 &pos_cu : positions_cu.slice(points)) {
+ pos_cu += pos_diff_cu;
+ }
+
+ if (!surface_uv_map.is_empty()) {
+ const MLoopTri &looptri = surface_looptris[looptri_index];
+ const int corner0 = looptri.tri[0];
+ const int corner1 = looptri.tri[1];
+ const int corner2 = looptri.tri[2];
+ const float2 &uv0 = surface_uv_map[corner0];
+ const float2 &uv1 = surface_uv_map[corner1];
+ const float2 &uv2 = surface_uv_map[corner2];
+ const float3 &p0_su = verts[loops[corner0].v].co;
+ const float3 &p1_su = verts[loops[corner1].v].co;
+ const float3 &p2_su = verts[loops[corner2].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
+ const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
+ surface_uv_coords[curve_i] = uv;
+ }
+ }
+ });
+ break;
+ }
+ case AttachMode::Deform: {
+ if (surface_uv_map.is_empty()) {
+ *r_missing_uvs = true;
+ break;
+ }
+ using geometry::ReverseUVSampler;
+ ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_point_pos_cu = positions_cu[first_point_i];
+
+ const float2 uv = surface_uv_coords[curve_i];
+ ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
+ if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
+ *r_invalid_uvs = true;
+ continue;
+ }
+
+ const MLoopTri &looptri = *lookup_result.looptri;
+ const float3 &bary_coords = lookup_result.bary_weights;
+
+ const float3 &p0_su = verts[loops[looptri.tri[0]].v].co;
+ const float3 &p1_su = verts[loops[looptri.tri[1]].v].co;
+ const float3 &p2_su = verts[loops[looptri.tri[2]].v].co;
+
+ float3 new_first_point_pos_su;
+ interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
+ const float3 new_first_point_pos_cu = transforms.surface_to_curves *
+ new_first_point_pos_su;
+
+ const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
+ for (float3 &pos_cu : positions_cu.slice(points)) {
+ pos_cu += pos_diff_cu;
+ }
+ }
+ });
+ break;
+ }
}
- return true;
+
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
}
static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
{
const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode"));
- std::atomic<bool> found_invalid_uv = false;
+ bool found_invalid_uvs = false;
+ bool found_missing_uvs = false;
CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) {
if (curves_ob->type != OB_CURVES) {
continue;
}
Curves &curves_id = *static_cast<Curves *>(curves_ob->data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
if (curves_id.surface == nullptr) {
continue;
}
- Object &surface_ob = *curves_id.surface;
- if (surface_ob.type != OB_MESH) {
+ if (curves_id.surface->type != OB_MESH) {
continue;
}
- Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
-
- MeshComponent surface_mesh_component;
- surface_mesh_component.replace(&surface_mesh, GeometryOwnershipType::ReadOnly);
-
- VArray_Span<float2> surface_uv_map;
- if (curves_id.surface_uv_map != nullptr) {
- surface_uv_map = surface_mesh_component
- .attribute_try_get_for_read(
- curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
- .typed<float2>();
- }
-
- MutableSpan<float3> positions_cu = curves.positions_for_write();
- MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
-
- const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
- BKE_mesh_runtime_looptri_len(&surface_mesh)};
-
- const float4x4 curves_to_world_mat = curves_ob->obmat;
- const float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
- const float4x4 surface_to_world_mat = surface_ob.obmat;
- const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
- const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
- const float4x4 surface_to_curves_mat = world_to_curves_mat * surface_to_world_mat;
-
- switch (attach_mode) {
- case AttachMode::Nearest: {
- BVHTreeFromMesh surface_bvh;
- BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRI, 2);
- BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange points = curves.points_for_curve(curve_i);
- const int first_point_i = points.first();
- const float3 old_first_point_pos_cu = positions_cu[first_point_i];
- const float3 old_first_point_pos_su = curves_to_surface_mat * old_first_point_pos_cu;
-
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(surface_bvh.tree,
- old_first_point_pos_su,
- &nearest,
- surface_bvh.nearest_callback,
- &surface_bvh);
- const int looptri_index = nearest.index;
- if (looptri_index == -1) {
- continue;
- }
-
- const float3 new_first_point_pos_su = nearest.co;
- const float3 new_first_point_pos_cu = surface_to_curves_mat * new_first_point_pos_su;
- const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
-
- for (float3 &pos_cu : positions_cu.slice(points)) {
- pos_cu += pos_diff_cu;
- }
-
- if (!surface_uv_map.is_empty()) {
- const MLoopTri &looptri = surface_looptris[looptri_index];
- const int corner0 = looptri.tri[0];
- const int corner1 = looptri.tri[1];
- const int corner2 = looptri.tri[2];
- const float2 &uv0 = surface_uv_map[corner0];
- const float2 &uv1 = surface_uv_map[corner1];
- const float2 &uv2 = surface_uv_map[corner2];
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
- const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
- surface_uv_coords[curve_i] = uv;
- }
- }
- });
- break;
- }
- case AttachMode::Deform: {
- if (surface_uv_map.is_empty()) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Curves do not have attachment information that can be used for deformation");
- break;
- }
- using geometry::ReverseUVSampler;
- ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange points = curves.points_for_curve(curve_i);
- const int first_point_i = points.first();
- const float3 old_first_point_pos_cu = positions_cu[first_point_i];
-
- const float2 uv = surface_uv_coords[curve_i];
- ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
- if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
- found_invalid_uv = true;
- continue;
- }
-
- const MLoopTri &looptri = *lookup_result.looptri;
- const float3 &bary_coords = lookup_result.bary_weights;
-
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
-
- float3 new_first_point_pos_su;
- interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
- const float3 new_first_point_pos_cu = surface_to_curves_mat * new_first_point_pos_su;
-
- const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
- for (float3 &pos_cu : positions_cu.slice(points)) {
- pos_cu += pos_diff_cu;
- }
- }
- });
- break;
- }
- }
-
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ snap_curves_to_surface_exec_object(
+ *curves_ob, *curves_id.surface, attach_mode, &found_invalid_uvs, &found_missing_uvs);
}
CTX_DATA_END;
- if (found_invalid_uv) {
+ if (found_missing_uvs) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Curves do not have attachment information that can be used for deformation");
+ }
+ if (found_invalid_uvs) {
BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface");
}
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
+ /* Refresh the entire window to also clear eventual modifier and nodes editor warnings. */
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -686,7 +709,7 @@ static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot)
ot->idname = "CURVES_OT_snap_curves_to_surface";
ot->description = "Move curves so that the first point is exactly on the surface mesh";
- ot->poll = snap_curves_to_surface_poll;
+ ot->poll = editable_curves_with_surface_poll;
ot->exec = snap_curves_to_surface_exec;
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
@@ -715,21 +738,6 @@ static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot)
"How to find the point on the surface to attach to");
}
-static bool selection_poll(bContext *C)
-{
- const Object *object = CTX_data_active_object(C);
- if (object == nullptr) {
- return false;
- }
- if (object->type != OB_CURVES) {
- return false;
- }
- if (!BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(object->data))) {
- return false;
- }
- return true;
-}
-
namespace set_selection_domain {
static int curves_set_selection_domain_exec(bContext *C, wmOperator *op)
@@ -745,21 +753,23 @@ static int curves_set_selection_domain_exec(bContext *C, wmOperator *op)
curves_id->selection_domain = domain;
curves_id->flag |= CV_SCULPT_SELECTION_ENABLED;
- CurveComponent component;
- component.replace(curves_id, GeometryOwnershipType::Editable);
CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+ if (curves.points_num() == 0) {
+ continue;
+ }
if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) {
VArray<float> curve_selection = curves.adapt_domain(
curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
curve_selection.materialize(curves.selection_curve_float_for_write());
- component.attribute_try_delete(".selection_point_float");
+ attributes.remove(".selection_point_float");
}
else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) {
VArray<float> point_selection = curves.adapt_domain(
curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
point_selection.materialize(curves.selection_point_float_for_write());
- component.attribute_try_delete(".selection_curve_float");
+ attributes.remove(".selection_curve_float");
}
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
@@ -784,7 +794,7 @@ static void CURVES_OT_set_selection_domain(wmOperatorType *ot)
ot->description = "Change the mode used for selection masking in curves sculpt mode";
ot->exec = set_selection_domain::curves_set_selection_domain_exec;
- ot->poll = selection_poll;
+ ot->poll = editable_curves_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -820,13 +830,11 @@ static void CURVES_OT_disable_selection(wmOperatorType *ot)
ot->description = "Disable the drawing of influence of selection in sculpt mode";
ot->exec = disable_selection::curves_disable_selection_exec;
- ot->poll = selection_poll;
+ ot->poll = editable_curves_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-namespace select_all {
-
static bool varray_contains_nonzero(const VArray<float> &data)
{
bool contains_nonzero = false;
@@ -841,6 +849,19 @@ static bool varray_contains_nonzero(const VArray<float> &data)
return contains_nonzero;
}
+bool has_anything_selected(const Curves &curves_id)
+{
+ const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT:
+ return varray_contains_nonzero(curves.selection_point_float());
+ case ATTR_DOMAIN_CURVE:
+ return varray_contains_nonzero(curves.selection_curve_float());
+ }
+ BLI_assert_unreachable();
+ return false;
+}
+
static bool any_point_selected(const CurvesGeometry &curves)
{
return varray_contains_nonzero(curves.selection_point_float());
@@ -856,6 +877,8 @@ static bool any_point_selected(const Span<Curves *> curves_ids)
return false;
}
+namespace select_all {
+
static void invert_selection(MutableSpan<float> selection)
{
threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
@@ -876,25 +899,14 @@ static int select_all_exec(bContext *C, wmOperator *op)
}
for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
if (action == SEL_SELECT) {
- /* The optimization to avoid storing the selection when everything is selected causes too
- * many problems at the moment, since there is no proper visualization yet. Keep the code but
- * disable it for now. */
-#if 0
- CurveComponent component;
- component.replace(curves_id, GeometryOwnershipType::Editable);
- component.attribute_try_delete(".selection_point_float");
- component.attribute_try_delete(".selection_curve_float");
-#else
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
- MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
- curves.selection_point_float_for_write() :
- curves.selection_curve_float_for_write();
- selection.fill(1.0f);
-#endif
+ /* As an optimization, just remove the selection attributes when everything is selected. */
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+ attributes.remove(".selection_point_float");
+ attributes.remove(".selection_curve_float");
}
else {
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
curves.selection_point_float_for_write() :
curves.selection_curve_float_for_write();
@@ -924,13 +936,95 @@ static void SCULPT_CURVES_OT_select_all(wmOperatorType *ot)
ot->description = "(De)select all control points";
ot->exec = select_all::select_all_exec;
- ot->poll = selection_poll;
+ ot->poll = editable_curves_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
+namespace surface_set {
+
+static bool surface_set_poll(bContext *C)
+{
+ const Object *object = CTX_data_active_object(C);
+ if (object == nullptr) {
+ return false;
+ }
+ if (object->type != OB_MESH) {
+ return false;
+ }
+ return true;
+}
+
+static int surface_set_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ Object &new_surface_ob = *CTX_data_active_object(C);
+
+ Mesh &new_surface_mesh = *static_cast<Mesh *>(new_surface_ob.data);
+ const char *new_uv_map_name = CustomData_get_active_layer_name(&new_surface_mesh.ldata,
+ CD_MLOOPUV);
+
+ CTX_DATA_BEGIN (C, Object *, selected_ob, selected_objects) {
+ if (selected_ob->type != OB_CURVES) {
+ continue;
+ }
+ Object &curves_ob = *selected_ob;
+ Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+
+ MEM_SAFE_FREE(curves_id.surface_uv_map);
+ if (new_uv_map_name != nullptr) {
+ curves_id.surface_uv_map = BLI_strdup(new_uv_map_name);
+ }
+
+ bool missing_uvs;
+ bool invalid_uvs;
+ snap_curves_to_surface::snap_curves_to_surface_exec_object(
+ curves_ob,
+ new_surface_ob,
+ snap_curves_to_surface::AttachMode::Nearest,
+ &invalid_uvs,
+ &missing_uvs);
+
+ /* Add deformation modifier if necessary. */
+ blender::ed::curves::ensure_surface_deformation_node_exists(*C, curves_ob);
+
+ curves_id.surface = &new_surface_ob;
+ ED_object_parent_set(
+ op->reports, C, scene, &curves_ob, &new_surface_ob, PAR_OBJECT, false, true, nullptr);
+
+ DEG_id_tag_update(&curves_ob.id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
+
+ /* Required for deformation. */
+ new_surface_ob.modifier_flag |= OB_MODIFIER_FLAG_ADD_REST_POSITION;
+ DEG_id_tag_update(&new_surface_ob.id, ID_RECALC_GEOMETRY);
+ }
+ CTX_DATA_END;
+
+ DEG_relations_tag_update(bmain);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace surface_set
+
+static void CURVES_OT_surface_set(wmOperatorType *ot)
+{
+ ot->name = "Set Curves Surface Object";
+ ot->idname = __func__;
+ ot->description =
+ "Use the active object as surface for selected curves objects and set it as the parent";
+
+ ot->exec = surface_set::surface_set_exec;
+ ot->poll = surface_set::surface_set_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
} // namespace blender::ed::curves
void ED_operatortypes_curves()
@@ -942,4 +1036,5 @@ void ED_operatortypes_curves()
WM_operatortype_append(CURVES_OT_set_selection_domain);
WM_operatortype_append(SCULPT_CURVES_OT_select_all);
WM_operatortype_append(CURVES_OT_disable_selection);
+ WM_operatortype_append(CURVES_OT_surface_set);
}
diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt
index e0c440b09b4..6e28bb3e8ec 100644
--- a/source/blender/editors/geometry/CMakeLists.txt
+++ b/source/blender/editors/geometry/CMakeLists.txt
@@ -10,6 +10,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../bmesh
)
set(INC_SYS
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index c7e782b7b89..14f2f8c6af5 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -275,15 +275,14 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
ID *ob_data = static_cast<ID *>(ob->data);
- CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
const std::string name = layer->name;
const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
RNA_enum_get(op->ptr, "mode"));
Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
/* General conversion steps are always the same:
* 1. Convert old data to right domain and data type.
@@ -301,33 +300,33 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+ GVArray src_varray = attributes.lookup_or_default(name, dst_domain, dst_type);
const CPPType &cpp_type = src_varray.type();
void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
src_varray.materialize_to_uninitialized(new_data);
- mesh_component.attribute_try_delete(name);
- mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data));
+ attributes.remove(name);
+ attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMoveArray(new_data));
break;
}
case ConvertAttributeMode::UVMap: {
MLoopUV *dst_uvs = static_cast<MLoopUV *>(
MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__));
- VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>(
+ VArray<float2> src_varray = attributes.lookup_or_default<float2>(
name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
for (const int i : IndexRange(mesh->totloop)) {
copy_v2_v2(dst_uvs[i].uv, src_varray[i]);
}
- mesh_component.attribute_try_delete(name);
+ attributes.remove(name);
CustomData_add_layer_named(
&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
break;
}
case ConvertAttributeMode::VertexGroup: {
Array<float> src_weights(mesh->totvert);
- VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
+ VArray<float> src_varray = attributes.lookup_or_default<float>(
name, ATTR_DOMAIN_POINT, 0.0f);
src_varray.materialize(src_weights);
- mesh_component.attribute_try_delete(name);
+ attributes.remove(name);
bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str());
const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup);
@@ -406,7 +405,7 @@ void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
prop = RNA_def_float_color(
ot->srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
- RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
+ RNA_def_property_subtype(prop, PROP_COLOR);
RNA_def_property_float_array_default(prop, default_color);
}
@@ -472,11 +471,6 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (GS(id->name) == ID_ME) {
- Mesh *me = static_cast<Mesh *>(ob->data);
- BKE_mesh_update_customdata_pointers(me, true);
- }
-
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@@ -652,15 +646,15 @@ bool ED_geometry_attribute_convert(Mesh *mesh,
return false;
}
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_type);
+ blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
+
+ GVArray src_varray = attributes.lookup_or_default(name, new_domain, new_type);
const CPPType &cpp_type = src_varray.type();
void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
src_varray.materialize_to_uninitialized(new_data);
- mesh_component.attribute_try_delete(name);
- mesh_component.attribute_try_create(name, new_domain, new_type, AttributeInitMove(new_data));
+ attributes.remove(name);
+ attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMoveArray(new_data));
int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
if (*active_index > 0) {
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index 0484c47f081..84181b5f95d 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -13,7 +13,6 @@ set(INC
../../windowmanager
../../../../intern/clog
../../../../intern/eigen
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index 11309402220..6eac235a191 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -177,6 +177,7 @@ static void button2d_draw_intern(const bContext *C,
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
+ float screen_scale = 200.0f;
if (is_3d) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float matrix_align[4][4];
@@ -187,8 +188,9 @@ static void button2d_draw_intern(const bContext *C,
transpose_m4(matrix_align);
GPU_matrix_mul(matrix_align);
}
-
- const float screen_scale = mat4_to_scale(matrix_final);
+ else {
+ screen_scale = mat4_to_scale(matrix_final);
+ }
if (select) {
BLI_assert(is_3d);
@@ -215,7 +217,7 @@ static void button2d_draw_intern(const bContext *C,
GPU_batch_uniform_1f(button->shape_batch[i], "lineWidth", gz->line_width * U.pixelsize);
}
else {
- GPU_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_3D_UNIFORM_COLOR);
}
/* Invert line color for wire. */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index 54aa5d16941..600abaf3737 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -388,7 +388,7 @@ static void cage2d_draw_box_interaction(const float color[4],
.pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
.col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT),
};
- immBindBuiltinProgram(is_solid ? GPU_SHADER_2D_FLAT_COLOR : GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
+ immBindBuiltinProgram(is_solid ? GPU_SHADER_3D_FLAT_COLOR : GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
{
if (is_solid) {
@@ -546,7 +546,7 @@ static void cage2d_draw_circle_handles(const rctf *r,
const int resolu = 12;
const float rad[2] = {margin[0] / 3, margin[1] / 3};
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(color);
/* should really divide by two, but looks too bulky. */
@@ -598,7 +598,7 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
if (false) {
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv((const float[4]){1, 1, 1, 0.5f});
float s = 0.5f;
immRectf(pos, -s, -s, s, s);
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 1ce67185c1e..af1f09d7e25 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -278,12 +278,13 @@ static int gizmo_move_modal(bContext *C,
CTX_data_ensure_evaluated_depsgraph(C),
region,
CTX_wm_view3d(C),
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST),
&(const struct SnapObjectParams){
.snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_EDIT,
.use_occlusion_test = true,
},
+ NULL,
mval_fl,
NULL,
&dist_px,
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index d468906f127..c5a542c0bf3 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -345,7 +345,7 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
prop = RNA_def_enum_flag(gzt->srna,
"snap_elements_force",
rna_enum_snap_element_items,
- SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST,
"Snap Elements",
"");
RNA_def_property_enum_funcs_runtime(prop,
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 09a3cac0d48..866df16f3d6 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -12,8 +12,8 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
+ ../../bmesh
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index f720f261ad5..ae09aea28d3 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -841,7 +841,8 @@ void ED_annotation_draw_2dimage(const bContext *C)
}
/* draw it! */
- annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
+ annotation_draw_data_all(
+ scene, gpd, offsx, offsy, sizex, sizey, scene->r.cfra, dflag, area->spacetype);
}
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
@@ -877,7 +878,7 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
}
annotation_draw_data_all(
- scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
+ scene, gpd, 0, 0, region->winx, region->winy, scene->r.cfra, dflag, area->spacetype);
}
void ED_annotation_draw_view3d(
@@ -928,7 +929,8 @@ void ED_annotation_draw_view3d(
}
/* draw it! */
- annotation_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+ annotation_draw_data_all(
+ scene, gpd, offsx, offsy, winx, winy, scene->r.cfra, dflag, v3d->spacetype);
}
void ED_annotation_draw_ex(
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 8c393cc4f3f..287dce1a509 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1568,7 +1568,7 @@ static void annotation_paint_initstroke(tGPsdata *p,
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -1715,7 +1715,7 @@ static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_pt
if (p->paintmode == GP_PAINTMODE_ERASER) {
GPUVertFormat *format = immVertexFormat();
const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1725,7 +1725,7 @@ static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_pt
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1782,7 +1782,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_width(1.25f);
@@ -2062,11 +2062,18 @@ static void annotation_draw_apply_event(
PointerRNA itemptr;
float mousef[2];
- /* convert from window-space to area-space mouse coordinates
- * add any x,y override position for fake events
- */
- p->mval[0] = (float)event->mval[0] - x;
- p->mval[1] = (float)event->mval[1] - y;
+ /* Convert from window-space to area-space mouse coordinates
+ * add any x,y override position for fake events. */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ /* The first run may be a drag event, see: T99368. */
+ WM_event_drag_start_mval_fl(event, p->region, p->mval);
+ p->mval[0] -= x;
+ p->mval[1] -= y;
+ }
+ else {
+ p->mval[0] = (float)event->mval[0] - x;
+ p->mval[1] = (float)event->mval[1] - y;
+ }
/* Key to toggle stabilization. */
if ((event->modifier & KM_SHIFT) && (p->paintmode == GP_PAINTMODE_DRAW)) {
@@ -2634,7 +2641,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
/* handle mode-specific events */
if (p->status == GP_STATUS_PAINTING) {
/* handle painting mouse-movements? */
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
+ if (ISMOUSE_MOTION(event->type) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
/* handle drawing event */
if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
annotation_add_missing_events(C, op, event, p);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 949043e4be1..8a98dcb57fc 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -214,6 +214,18 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
}
}
+void ED_gpencil_set_active_channel(bGPdata *gpd, bGPDlayer *gpl)
+{
+ gpl->flag |= GP_LAYER_SELECT;
+
+ /* Update other layer status. */
+ if (BKE_gpencil_layer_active_get(gpd) != gpl) {
+ BKE_gpencil_layer_active_set(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
@@ -316,8 +328,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* assume that each of these is a GP layer */
for (ale = anim_data.first; ale; ale = ale->next) {
+ /* This function only deals with grease pencil layer frames.
+ * This check is needed in the case of a call from the main dopesheet. */
+ if (ale->type != ANIMTYPE_GPLAYER) {
+ continue;
+ }
+
ListBase copied_frames = {NULL, NULL};
bGPDlayer *gpl = (bGPDlayer *)ale->data;
@@ -354,19 +371,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
}
/* in case 'relative' paste method is used */
- gpencil_anim_copy_cfra = CFRA;
+ gpencil_anim_copy_cfra = scene->r.cfra;
/* clean up */
ANIM_animdata_freelist(&anim_data);
- /* check if anything ended up in the buffer */
- if (ELEM(NULL, gpencil_anim_copybuf.first, gpencil_anim_copybuf.last)) {
- BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
- return false;
- }
-
/* report success */
- return true;
+ return !BLI_listbase_is_empty(&gpencil_anim_copybuf);
}
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
@@ -381,7 +392,6 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* check if buffer is empty */
if (BLI_listbase_is_empty(&gpencil_anim_copybuf)) {
- BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste");
return false;
}
@@ -393,13 +403,13 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* methods of offset (eKeyPasteOffset) */
switch (offset_mode) {
case KEYFRAME_PASTE_OFFSET_CFRA_START:
- offset = (CFRA - gpencil_anim_copy_firstframe);
+ offset = (scene->r.cfra - gpencil_anim_copy_firstframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_END:
- offset = (CFRA - gpencil_anim_copy_lastframe);
+ offset = (scene->r.cfra - gpencil_anim_copy_lastframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
- offset = (CFRA - gpencil_anim_copy_cfra);
+ offset = (scene->r.cfra - gpencil_anim_copy_cfra);
break;
case KEYFRAME_PASTE_OFFSET_NONE:
offset = 0;
@@ -414,6 +424,11 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* from selected channels */
for (ale = anim_data.first; ale; ale = ale->next) {
+ /* only deal with GPlayers (case of calls from general dopesheet) */
+ if (ale->type != ANIMTYPE_GPLAYER) {
+ continue;
+ }
+
bGPDlayer *gpld = (bGPDlayer *)ale->data;
bGPDlayer *gpls = NULL;
bGPDframe *gpfs, *gpf;
@@ -503,7 +518,7 @@ static bool gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene)
static bool gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene)
{
if (gpf->flag & GP_FRAME_SELECT) {
- gpf->framenum = (int)CFRA;
+ gpf->framenum = (int)scene->r.cfra;
}
return false;
}
@@ -545,8 +560,8 @@ static bool gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene)
int diff;
if (gpf->flag & GP_FRAME_SELECT) {
- diff = CFRA - gpf->framenum;
- gpf->framenum = CFRA + diff;
+ diff = scene->r.cfra - gpf->framenum;
+ gpf->framenum = scene->r.cfra + diff;
}
return false;
diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c
index 2f22fad53e7..b88b33913ac 100644
--- a/source/blender/editors/gpencil/gpencil_add_blank.c
+++ b/source/blender/editors/gpencil/gpencil_add_blank.c
@@ -19,6 +19,8 @@
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BLT_translation.h"
+
#include "DEG_depsgraph.h"
#include "ED_gpencil.h"
@@ -34,7 +36,7 @@ typedef struct ColorTemplate {
static int gpencil_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct)
{
int index;
- Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index);
+ Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index);
copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
@@ -52,7 +54,7 @@ static int gpencil_stroke_material(Main *bmain, Object *ob, const ColorTemplate
/* Color Data */
static const ColorTemplate gp_stroke_material_black = {
- "Black",
+ N_("Black"),
{0.0f, 0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
@@ -76,7 +78,7 @@ void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4]))
bGPDlayer *layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false);
/* frames */
- BKE_gpencil_frame_addnew(layer, CFRA);
+ BKE_gpencil_frame_addnew(layer, scene->r.cfra);
/* update depsgraph */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c
index 964a57a8ced..2ac26c927f4 100644
--- a/source/blender/editors/gpencil/gpencil_add_lineart.c
+++ b/source/blender/editors/gpencil/gpencil_add_lineart.c
@@ -21,6 +21,8 @@
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BLT_translation.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -40,7 +42,7 @@ static int gpencil_lineart_material(Main *bmain,
const bool fill)
{
int index;
- Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index);
+ Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index);
copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
@@ -59,7 +61,7 @@ static int gpencil_lineart_material(Main *bmain,
/* Color Data */
static const ColorTemplate gp_stroke_material_black = {
- "Black",
+ N_("Black"),
{0.0f, 0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index 65ee732f6a9..00066d5f2b8 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -19,6 +19,8 @@
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BLT_translation.h"
+
#include "DEG_depsgraph.h"
#include "ED_gpencil.h"
@@ -54,7 +56,7 @@ static int gpencil_monkey_color(
Main *bmain, Object *ob, const ColorTemplate *pct, bool stroke, bool fill)
{
int index;
- Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index);
+ Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index);
copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
@@ -781,37 +783,37 @@ static const float data27[33 * GP_PRIM_DATABUF_SIZE] = {
/* Monkey Color Data */
static const ColorTemplate gp_monkey_pct_black = {
- "Black",
+ N_("Black"),
{0.0f, 0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_monkey_pct_skin = {
- "Skin",
+ N_("Skin"),
{0.733f, 0.569f, 0.361f, 1.0f},
{0.745f, 0.502f, 0.278f, 1.0f},
};
static const ColorTemplate gp_monkey_pct_skin_light = {
- "Skin_Light",
+ N_("Skin_Light"),
{0.914f, 0.827f, 0.635f, 1.0f},
{0.913f, 0.828f, 0.637f, 0.0f},
};
static const ColorTemplate gp_monkey_pct_skin_shadow = {
- "Skin_Shadow",
+ N_("Skin_Shadow"),
{0.322f, 0.29f, 0.224f, 0.5f},
{0.32f, 0.29f, 0.223f, 0.3f},
};
static const ColorTemplate gp_monkey_pct_eyes = {
- "Eyes",
+ N_("Eyes"),
{0.553f, 0.39f, 0.266f, 0.0f},
{0.847f, 0.723f, 0.599f, 1.0f},
};
static const ColorTemplate gp_monkey_pct_pupils = {
- "Pupils",
+ N_("Pupils"),
{0.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f},
};
@@ -821,6 +823,8 @@ static const ColorTemplate gp_monkey_pct_pupils = {
void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
{
+ /* Original model created by Matias Mendiola. */
+
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bGPdata *gpd = (bGPdata *)ob->data;
@@ -844,8 +848,8 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
/* frames */
/* NOTE: No need to check for existing, as this will take care of it for us */
- bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, CFRA);
- bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, CFRA);
+ bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, scene->r.cfra);
+ bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, scene->r.cfra);
/* generate strokes */
gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false);
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index bc5fe9b5cfb..8522c81cb39 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -19,6 +19,8 @@
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BLT_translation.h"
+
#include "DEG_depsgraph.h"
#include "ED_gpencil.h"
@@ -37,7 +39,7 @@ static int gpencil_stroke_material(Main *bmain,
const bool fill)
{
int index;
- Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index);
+ Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index);
copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
@@ -150,37 +152,37 @@ static const float data0[175 * GP_PRIM_DATABUF_SIZE] = {
/* Color Data */
static const ColorTemplate gp_stroke_material_black = {
- "Black",
+ N_("Black"),
{0.0f, 0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_white = {
- "White",
+ N_("White"),
{1.0f, 1.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_red = {
- "Red",
+ N_("Red"),
{1.0f, 0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_green = {
- "Green",
+ N_("Green"),
{0.0f, 1.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_blue = {
- "Blue",
+ N_("Blue"),
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 0.0f, 0.0f},
};
static const ColorTemplate gp_stroke_material_grey = {
- "Grey",
+ N_("Grey"),
{0.358f, 0.358f, 0.358f, 1.0f},
{0.5f, 0.5f, 0.5f, 1.0f},
};
@@ -190,6 +192,8 @@ static const ColorTemplate gp_stroke_material_grey = {
void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
{
+ /* Original design created by Daniel M. Lara and Matias Mendiola. */
+
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bGPdata *gpd = (bGPdata *)ob->data;
@@ -211,8 +215,8 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true, false);
/* frames */
- bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, CFRA);
- bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, CFRA);
+ bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, scene->r.cfra);
+ bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, scene->r.cfra);
UNUSED_VARS(frame_color);
/* generate stroke */
diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc
index 66f53bea326..e480852a9bb 100644
--- a/source/blender/editors/gpencil/gpencil_bake_animation.cc
+++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc
@@ -265,7 +265,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
}
/* Move scene to new frame. */
- CFRA = i;
+ scene->r.cfra = i;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Loop all objects in the list. */
@@ -285,7 +285,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
/* Apply time modifier. */
int remap_cfra = BKE_gpencil_time_modifier_cfra(
- depsgraph, scene, elem->ob, gpl_src, CFRA, false);
+ depsgraph, scene, elem->ob, gpl_src, scene->r.cfra, false);
/* Duplicate frame. */
bGPDframe *gpf_src = BKE_gpencil_layer_frame_get(
gpl_src, remap_cfra, GP_GETFRAME_USE_PREV);
@@ -293,7 +293,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
continue;
}
bGPDframe *gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, true);
- gpf_dst->framenum = CFRA + frame_offset;
+ gpf_dst->framenum = scene->r.cfra + frame_offset;
gpf_dst->flag &= ~GP_FRAME_SELECT;
BLI_addtail(&gpl_dst->frames, gpf_dst);
@@ -337,7 +337,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
}
}
/* Return scene frame state and DB to original state. */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Free memory. */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 0601d009bf7..e02a82f4555 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -588,7 +588,7 @@ static void gpencil_stroke_path_animation(bContext *C,
}
/* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1271,7 +1271,7 @@ static void gpencil_layer_to_curve(bContext *C,
Collection *collection = CTX_data_collection(C);
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
bGPDstroke *prev_gps = NULL;
Object *ob;
Curve *cu;
@@ -1414,7 +1414,7 @@ static bool gpencil_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl,
int i;
bool valid = true;
- if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) ||
+ if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) ||
!(gps = gpf->strokes.first)) {
return false;
}
@@ -1481,7 +1481,7 @@ static bool gpencil_convert_poll(bContext *C)
* and if we are not in edit mode!
*/
return ((area && area->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
- (gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) &&
+ (gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) &&
(gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
}
@@ -1811,7 +1811,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op)
/* Add layer and frame. */
bGPdata *gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true, false);
- bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, CFRA);
+ bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, scene->r.cfra);
done = BKE_gpencil_from_image(sima, gpd, gpf, size, is_mask);
if (done) {
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 6843c42d2d0..340288b2d74 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -226,7 +226,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op)
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false);
/* Add a new frame to make it visible in Dopesheet. */
if (gpl != NULL) {
- gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
}
}
}
@@ -646,12 +646,12 @@ static int gpencil_frame_duplicate_exec(bContext *C, wmOperator *op)
}
if (mode == 0) {
- BKE_gpencil_frame_addcopy(gpl_active, CFRA);
+ BKE_gpencil_frame_addcopy(gpl_active, scene->r.cfra);
}
else {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
- BKE_gpencil_frame_addcopy(gpl, CFRA);
+ BKE_gpencil_frame_addcopy(gpl, scene->r.cfra);
}
}
}
@@ -2076,6 +2076,9 @@ static void gpencil_brush_delete_mode_brushes(Main *bmain,
}
BKE_brush_delete(bmain, brush);
+ if (brush == brush_active) {
+ brush_active = NULL;
+ }
}
}
@@ -2109,8 +2112,8 @@ static int gpencil_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op))
char tool = '0';
if (paint) {
- Brush *brush_active = paint->brush;
- if (brush_active) {
+ if (paint->brush) {
+ Brush *brush_active = paint->brush;
switch (mode) {
case CTX_MODE_PAINT_GPENCIL: {
tool = brush_active->gpencil_tool;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 5028baf1589..120c806c727 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1718,7 +1718,7 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op)
* we are obliged to add a new frame if one
* doesn't exist already
*/
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
if (gpf) {
/* Create new stroke */
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true);
@@ -1971,7 +1971,7 @@ static int gpencil_blank_frame_add_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
bGPDlayer *active_gpl = BKE_gpencil_layer_active_get(gpd);
@@ -2075,7 +2075,7 @@ static int gpencil_actframe_delete_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -2150,7 +2150,7 @@ static int gpencil_actframe_delete_all_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
/* try to get the "active" frame - but only if it actually occurs on this frame */
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
@@ -3395,6 +3395,7 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
const int type = RNA_enum_get(op->ptr, "type");
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* sanity checks */
if (ELEM(NULL, gpd)) {
@@ -3404,46 +3405,57 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
bool changed = false;
/* loop all selected strokes */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- if (gpl->actframe == NULL) {
- continue;
- }
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
+ continue;
+ }
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) || (ED_gpencil_stroke_can_use(C, gps) == false)) {
- continue;
- }
- /* skip hidden or locked colors */
- if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) ||
- (gp_style->flag & GP_MATERIAL_LOCKED)) {
- continue;
- }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- short prev_first = gps->caps[0];
- short prev_last = gps->caps[1];
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) ||
+ (ED_gpencil_stroke_can_use(C, gps) == false)) {
+ continue;
+ }
+ /* skip hidden or locked colors */
+ if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) ||
+ (gp_style->flag & GP_MATERIAL_LOCKED)) {
+ continue;
+ }
+
+ short prev_first = gps->caps[0];
+ short prev_last = gps->caps[1];
+
+ if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_START)) {
+ ++gps->caps[0];
+ if (gps->caps[0] >= GP_STROKE_CAP_MAX) {
+ gps->caps[0] = GP_STROKE_CAP_ROUND;
+ }
+ }
+ if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_END)) {
+ ++gps->caps[1];
+ if (gps->caps[1] >= GP_STROKE_CAP_MAX) {
+ gps->caps[1] = GP_STROKE_CAP_ROUND;
+ }
+ }
+ if (type == GP_STROKE_CAPS_TOGGLE_DEFAULT) {
+ gps->caps[0] = GP_STROKE_CAP_ROUND;
+ gps->caps[1] = GP_STROKE_CAP_ROUND;
+ }
- if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_START)) {
- ++gps->caps[0];
- if (gps->caps[0] >= GP_STROKE_CAP_MAX) {
- gps->caps[0] = GP_STROKE_CAP_ROUND;
+ if (prev_first != gps->caps[0] || prev_last != gps->caps[1]) {
+ changed = true;
+ }
}
- }
- if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_END)) {
- ++gps->caps[1];
- if (gps->caps[1] >= GP_STROKE_CAP_MAX) {
- gps->caps[1] = GP_STROKE_CAP_ROUND;
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
}
}
- if (type == GP_STROKE_CAPS_TOGGLE_DEFAULT) {
- gps->caps[0] = GP_STROKE_CAP_ROUND;
- gps->caps[1] = GP_STROKE_CAP_ROUND;
- }
-
- if (prev_first != gps->caps[0] || prev_last != gps->caps[1]) {
- changed = true;
- }
}
}
CTX_DATA_END;
@@ -3550,9 +3562,9 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *activegpl = BKE_gpencil_layer_active_get(gpd);
Object *ob = CTX_data_active_object(C);
- /* Limit the number of strokes to join. It makes no sense to allow an very high number of strokes
- * for CPU time and because to have a stroke with thousands of points is unpractical, so limit
- * this number avoid to joining a full frame scene in one single stroke. */
+ /* Limit the number of strokes to join. It makes no sense to allow an very high number of
+ * strokes for CPU time and because to have a stroke with thousands of points is unpractical,
+ * so limit this number avoid to joining a full frame scene in one single stroke. */
const int max_join_strokes = 128;
const int type = RNA_enum_get(op->ptr, "type");
@@ -3638,7 +3650,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
}
elem = &strokes_list[i];
/* Join new_stroke and stroke B. */
- BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true, false);
+ BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true, false, true);
elem->used = true;
}
@@ -3709,35 +3721,44 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
bool changed = false;
- /* read all selected strokes */
+ /* Read all selected strokes. */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
continue;
}
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
+ continue;
+ }
- if (is_curve_edit) {
- BKE_report(op->reports, RPT_ERROR, "Not implemented!");
- }
- else {
- /* Flip stroke. */
- BKE_gpencil_stroke_flip(gps);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* Flip stroke. */
+ BKE_gpencil_stroke_flip(gps);
+ changed = true;
+ }
+ }
}
-
- changed = true;
+ }
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
}
}
}
@@ -3818,7 +3839,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
/* update frame to get the new location of objects */
if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf->framenum)) {
cfra_prv = gpf->framenum;
- CFRA = gpf->framenum;
+ scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
}
@@ -3846,7 +3867,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* return frame state and DB to original state */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
if (sctx != NULL) {
@@ -3939,6 +3960,284 @@ static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+/* -------------------------------------------------------------------- */
+/** \name Stroke Perimeter from View Operator
+ * \{ */
+
+enum {
+ GP_PERIMETER_VIEW = 0,
+ GP_PERIMETER_FRONT = 1,
+ GP_PERIMETER_SIDE = 2,
+ GP_PERIMETER_TOP = 3,
+ GP_PERIMETER_CAMERA = 4,
+};
+
+enum {
+ GP_STROKE_USE_ACTIVE_MATERIAL = 0,
+ GP_STROKE_USE_CURRENT_MATERIAL = 1,
+ GP_STROKE_USE_NEW_MATERIAL = 2,
+};
+
+static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const int subdivisions = RNA_int_get(op->ptr, "subdivisions");
+ const float length = RNA_float_get(op->ptr, "length");
+ const bool keep = RNA_boolean_get(op->ptr, "keep");
+ const int thickness = RNA_int_get(op->ptr, "thickness");
+
+ const int view_mode = RNA_enum_get(op->ptr, "view_mode");
+ const int material_mode = RNA_enum_get(op->ptr, "material_mode");
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bool changed = false;
+
+ float viewmat[4][4];
+ copy_m4_m4(viewmat, rv3d->viewmat);
+
+ switch (view_mode) {
+ case GP_PERIMETER_FRONT:
+ unit_m4(rv3d->viewmat);
+ viewmat[1][1] = 0.0f;
+ viewmat[1][2] = -1.0f;
+
+ viewmat[2][1] = 1.0f;
+ viewmat[2][2] = 0.0f;
+
+ viewmat[3][2] = -10.0f;
+ break;
+ case GP_PERIMETER_SIDE:
+ zero_m4(viewmat);
+ viewmat[0][2] = 1.0f;
+ viewmat[1][0] = 1.0f;
+ viewmat[2][1] = 1.0f;
+ viewmat[3][3] = 1.0f;
+ break;
+ case GP_PERIMETER_TOP:
+ unit_m4(viewmat);
+ break;
+ case GP_PERIMETER_CAMERA: {
+ Scene *scene = CTX_data_scene(C);
+ Object *cam_ob = scene->camera;
+ if (cam_ob != NULL) {
+ invert_m4_m4(viewmat, cam_ob->obmat);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Untag strokes to be sure nothing is pending. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ gps->flag &= ~GP_STROKE_TAG;
+ }
+ }
+ }
+ /* Create a new material. */
+ int mat_idx = 0;
+ if (material_mode == GP_STROKE_USE_NEW_MATERIAL) {
+ Material *ma = BKE_gpencil_object_material_new(bmain, ob, "Material", NULL);
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ mat_idx = ob->totcol - 1;
+ }
+
+ /* loop all selected strokes */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ if (gpl->flag & GP_LAYER_HIDE) {
+ continue;
+ }
+ /* Prepare transform matrix. */
+ float diff_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
+
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
+ continue;
+ }
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if ((gps->flag & GP_STROKE_SELECT) == 0) {
+ continue;
+ }
+ if (gps->totpoints == 0) {
+ continue;
+ }
+ if (!ED_gpencil_stroke_material_visible(ob, gps)) {
+ continue;
+ }
+
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0);
+
+ if (!is_stroke) {
+ continue;
+ }
+
+ /* Duplicate the stroke to apply any layer thickness change. */
+ bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
+
+ /* Apply layer thickness change. */
+ gps_duplicate->thickness += gpl->line_change;
+ /* Apply object scale to thickness. */
+ gps_duplicate->thickness *= mat4_to_scale(ob->obmat);
+ CLAMP_MIN(gps_duplicate->thickness, 1.0f);
+
+ /* Stroke. */
+ const float ovr_thickness = keep ? thickness : 0.0f;
+ bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
+ viewmat, gpd, gpl, gps_duplicate, subdivisions, diff_mat, ovr_thickness);
+ gps_perimeter->flag &= ~GP_STROKE_SELECT;
+ /* Assign material. */
+ switch (material_mode) {
+ case GP_STROKE_USE_ACTIVE_MATERIAL: {
+ if (ob->actcol - 1 < 0) {
+ gps_perimeter->mat_nr = 0;
+ }
+ else {
+ gps_perimeter->mat_nr = ob->actcol - 1;
+ }
+ break;
+ }
+ case GP_STROKE_USE_CURRENT_MATERIAL:
+ gps_perimeter->mat_nr = gps->mat_nr;
+ break;
+ case GP_STROKE_USE_NEW_MATERIAL:
+ gps_perimeter->mat_nr = mat_idx;
+ break;
+ default:
+ break;
+ }
+
+ /* Sample stroke. */
+ if (length > 0.0f) {
+ BKE_gpencil_stroke_sample(gpd, gps_perimeter, length, false, 0);
+ }
+ /* Set stroke thickness. */
+ gps_perimeter->thickness = thickness;
+
+ /* Set pressure constant. */
+ bGPDspoint *pt;
+ for (int i = 0; i < gps_perimeter->totpoints; i++) {
+ pt = &gps_perimeter->points[i];
+ pt->pressure = 1.0f;
+ }
+
+ /* Add perimeter stroke to frame. */
+ BLI_insertlinkafter(&gpf->strokes, gps, gps_perimeter);
+
+ /* Tag original stroke to be removed. */
+ gps->flag |= GP_STROKE_TAG;
+
+ /* Free Temp stroke. */
+ BKE_gpencil_free_stroke(gps_duplicate);
+ changed = true;
+ }
+
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+ /* Free old strokes. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_TAG) {
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_outline(wmOperatorType *ot)
+{
+ static const EnumPropertyItem view_mode[] = {
+ {GP_PERIMETER_VIEW, "VIEW", 0, "View", ""},
+ {GP_PERIMETER_FRONT, "FRONT", 0, "Front", ""},
+ {GP_PERIMETER_SIDE, "SIDE", 0, "Side", ""},
+ {GP_PERIMETER_TOP, "TOP", 0, "Top", ""},
+ {GP_PERIMETER_CAMERA, "CAMERA", 0, "Camera", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+ static const EnumPropertyItem material_mode[] = {
+ {GP_STROKE_USE_ACTIVE_MATERIAL, "ACTIVE", 0, "Active Material", ""},
+ {GP_STROKE_USE_CURRENT_MATERIAL, "KEEP", 0, "Keep Material", "Keep current stroke material"},
+ {GP_STROKE_USE_NEW_MATERIAL, "NEW", 0, "New Material", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Convert Stroke to Outline";
+ ot->idname = "GPENCIL_OT_stroke_outline";
+ ot->description = "Convert stroke to perimeter";
+
+ /* api callbacks */
+ ot->exec = gpencil_stroke_outline_exec;
+ ot->poll = gpencil_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "view_mode", view_mode, GP_PERIMETER_VIEW, "View", "");
+ RNA_def_enum(ot->srna,
+ "material_mode",
+ material_mode,
+ GP_STROKE_USE_ACTIVE_MATERIAL,
+ "Material Mode",
+ "");
+
+ RNA_def_int(ot->srna,
+ "thickness",
+ 1,
+ 1,
+ 1000,
+ "Thickness",
+ "Thickness of the stroke perimeter",
+ 1,
+ 1000);
+ RNA_def_boolean(ot->srna,
+ "keep",
+ true,
+ "Keep Shape",
+ "Try to keep global shape when the stroke thickness change");
+
+ RNA_def_int(ot->srna, "subdivisions", 3, 0, 10, "Subdivisions", "", 0, 10);
+
+ RNA_def_float(ot->srna, "length", 0.0f, 0.0f, 100.0f, "Sample Length", "", 0.0f, 100.0f);
+}
+
+/** \} */
+
void GPENCIL_OT_recalc_geometry(wmOperatorType *ot)
{
/* identifiers */
@@ -3980,6 +4279,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* TODO use `BKE_gpencil_stroke_smooth` when the weights are better used. */
bGPDstroke gps_old = *gps;
gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points);
+ bool need_update = false;
/* Here the iteration needs to be done outside the smooth functions,
* as there are points that don't get smoothed. */
for (int n = 0; n < repeat; n++) {
@@ -3991,6 +4291,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* Perform smoothing. */
if (smooth_position) {
BKE_gpencil_stroke_smooth_point(&gps_old, i, factor, 1, false, false, gps);
+ need_update = true;
}
if (smooth_strength) {
BKE_gpencil_stroke_smooth_strength(&gps_old, i, factor, 1, gps);
@@ -4000,6 +4301,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
}
if (smooth_uv) {
BKE_gpencil_stroke_smooth_uv(&gps_old, i, factor, 1, gps);
+ need_update = true;
}
}
if (n < repeat - 1) {
@@ -4007,6 +4309,11 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
}
}
MEM_freeN(gps_old.points);
+
+ if (need_update) {
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd_, gps);
+ }
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -4454,6 +4761,8 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot)
/* properties */
prop = RNA_def_float(ot->srna, "length", 0.1f, 0.0f, 100.0f, "Length", "", 0.0f, 100.0f);
+ prop = RNA_def_float(
+ ot->srna, "sharp_threshold", 0.1f, 0.0f, M_PI, "Sharp Threshold", "", 0.0f, M_PI);
/* avoid re-using last var */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 3f06dbfdbb3..5305c764b3a 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1748,7 +1748,7 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op)
tgpf->v3d = tgpf->area->spacedata.first;
tgpf->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpf->win = CTX_wm_window(C);
- tgpf->active_cfra = CFRA;
+ tgpf->active_cfra = scene->r.cfra;
tgpf->reports = op->reports;
/* Setup space conversions. */
@@ -2222,8 +2222,8 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Hash of selected frames. */
GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64);
- /* If not multi-frame and there is no frame in CFRA for the active layer, create
- * a new frame. */
+ /* If not multi-frame and there is no frame in scene->r.cfra for the active layer,
+ * create a new frame. */
if (!is_multiedit) {
tgpf->gpf = BKE_gpencil_layer_frame_get(
tgpf->gpl,
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index d656241c463..3cb3a50e702 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -608,6 +608,7 @@ void GPENCIL_OT_stroke_merge_by_distance(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_merge_material(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_reset_vertex_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_normalize(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_outline(struct wmOperatorType *ot);
void GPENCIL_OT_material_to_vertex_color(struct wmOperatorType *ot);
void GPENCIL_OT_extract_palette_vertex(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 0039dbae674..dc63acf5136 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -483,10 +483,10 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
tgpil->gpl = gpl;
- bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, CFRA);
+ bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, scene->r.cfra);
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf, true);
- gpf = gpencil_get_next_keyframe(gpl, CFRA);
+ gpf = gpencil_get_next_keyframe(gpl, scene->r.cfra);
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf, true);
BLI_addtail(&tgpi->ilayers, tgpil);
@@ -750,7 +750,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tGPDinterpolate *tgpi = NULL;
/* Cannot interpolate if not between 2 frames. */
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra);
if (ELEM(NULL, gpf_prv, gpf_next)) {
@@ -1221,7 +1221,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
GP_SpaceConversion gsc;
gpencil_point_conversion_init(C, &gsc);
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
const int step = RNA_int_get(op->ptr, "step");
@@ -1483,7 +1483,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
*/
static const EnumPropertyItem gpencil_interpolation_type_items[] = {
/* Interpolation. */
- RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"),
+ RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Interpolation"),
+ N_("Standard transitions between keyframes")),
{GP_IPO_LINEAR,
"LINEAR",
ICON_IPO_LINEAR,
@@ -1496,9 +1497,9 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
"Custom interpolation defined using a curve map"},
/* Easing. */
- RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"),
- "Predefined inertial transitions, useful for motion graphics "
- "(from least to most \"dramatic\")"),
+ RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Easing (by strength)"),
+ N_("Predefined inertial transitions, useful for motion graphics "
+ "(from least to most \"dramatic\")")),
{GP_IPO_SINE,
"SINE",
ICON_IPO_SINE,
@@ -1515,7 +1516,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
"Circular",
"Circular easing (strongest and most dynamic)"},
- RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"),
+ RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Dynamic Effects"),
+ N_("Simple physics-inspired easing effects")),
{GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
{GP_IPO_BOUNCE,
"BOUNCE",
@@ -1569,6 +1571,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
/* identifiers */
ot->name = "Interpolate Sequence";
ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->translation_context = BLT_I18NCONTEXT_ID_GPENCIL;
ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
/* api callbacks */
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 06343dcad43..8ff3f20cef3 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -113,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
else {
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
/* stroke */
bGPDstroke *gps = BKE_gpencil_stroke_new(MAX2(ob->actcol - 1, 0), totpoints, brush->size);
diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc
index aee00d4ede3..b27e1c75746 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.cc
+++ b/source/blender/editors/gpencil/gpencil_mesh.cc
@@ -283,7 +283,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
}
/* Move scene to new frame. */
- CFRA = i;
+ scene->r.cfra = i;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Loop all objects in the list. */
@@ -325,7 +325,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
}
/* Return scene frame state and DB to original state. */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Remove unused materials. */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 99e28270c3e..3d92fbabfc4 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -635,6 +635,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_stroke_merge_material);
WM_operatortype_append(GPENCIL_OT_stroke_reset_vertex_color);
WM_operatortype_append(GPENCIL_OT_stroke_normalize);
+ WM_operatortype_append(GPENCIL_OT_stroke_outline);
WM_operatortype_append(GPENCIL_OT_material_to_vertex_color);
WM_operatortype_append(GPENCIL_OT_extract_palette_vertex);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 7c7f532f087..8e33a029229 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -918,6 +918,67 @@ static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps)
}
}
+static bGPDstroke *gpencil_stroke_to_outline(tGPsdata *p, bGPDstroke *gps)
+{
+ bGPDlayer *gpl = p->gpl;
+ RegionView3D *rv3d = p->region->regiondata;
+ Brush *brush = p->brush;
+ BrushGpencilSettings *gpencil_settings = brush->gpencil_settings;
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(p->ob, gps->mat_nr + 1);
+ const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0);
+
+ if (!is_stroke) {
+ return gps;
+ }
+
+ /* Duplicate the stroke to apply any layer thickness change. */
+ bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
+
+ /* Apply layer thickness change. */
+ gps_duplicate->thickness += gpl->line_change;
+ /* Apply object scale to thickness. */
+ gps_duplicate->thickness *= mat4_to_scale(p->ob->obmat);
+ CLAMP_MIN(gps_duplicate->thickness, 1.0f);
+
+ /* Stroke. */
+ float diff_mat[4][4];
+ unit_m4(diff_mat);
+ const float outline_thickness = (float)brush->size * gpencil_settings->outline_fac * 0.5f;
+ bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
+ rv3d->viewmat, p->gpd, gpl, gps_duplicate, 3, diff_mat, outline_thickness);
+ /* Assign material. */
+ if (gpencil_settings->material_alt == NULL) {
+ gps_perimeter->mat_nr = gps->mat_nr;
+ }
+ else {
+ Material *ma = gpencil_settings->material_alt;
+ int mat_idx = BKE_gpencil_material_find_index_by_name_prefix(p->ob, ma->id.name + 2);
+ if (mat_idx > -1) {
+ gps_perimeter->mat_nr = mat_idx;
+ }
+ else {
+ gps_perimeter->mat_nr = gps->mat_nr;
+ }
+ }
+
+ /* Set pressure constant. */
+ gps_perimeter->thickness = max_ii((int)outline_thickness, 1);
+
+ bGPDspoint *pt;
+ for (int i = 0; i < gps_perimeter->totpoints; i++) {
+ pt = &gps_perimeter->points[i];
+ pt->pressure = 1.0f;
+ }
+
+ /* Remove original stroke. */
+ BKE_gpencil_free_stroke(gps);
+
+ /* Free Temp stroke. */
+ BKE_gpencil_free_stroke(gps_duplicate);
+
+ return gps_perimeter;
+}
+
/* make a new stroke from the buffer data */
static void gpencil_stroke_newfrombuffer(tGPsdata *p)
{
@@ -1221,6 +1282,23 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
BKE_gpencil_stroke_simplify_adaptive(gpd, gps, brush->gpencil_settings->simplify_f);
}
+ /* Set material index. */
+ gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
+ if (gps->mat_nr < 0) {
+ if (p->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = p->ob->actcol - 1;
+ }
+ }
+
+ /* Convert to Outline. */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->flag & GP_BRUSH_OUTLINE_STROKE)) {
+ gps = gpencil_stroke_to_outline(p, gps);
+ }
+
/* reproject to plane (only in 3d space) */
gpencil_reproject_toplane(p, gps);
/* change position relative to parent object */
@@ -1235,17 +1313,6 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
}
}
- /* Save material index */
- gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
- if (gps->mat_nr < 0) {
- if (p->ob->actcol - 1 < 0) {
- gps->mat_nr = 0;
- }
- else {
- gps->mat_nr = p->ob->actcol - 1;
- }
- }
-
/* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke
* is added on listbase head because the drawing order is inverse and the head stroke is the
* first to draw. This is very useful for artist when drawing the background.
@@ -2166,7 +2233,7 @@ static void gpencil_paint_initstroke(tGPsdata *p,
if (gpl->actframe && gpl->actframe->strokes.first) {
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV;
- gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, frame_mode);
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, frame_mode);
}
has_layer_to_erase = true;
break;
@@ -2204,7 +2271,7 @@ static void gpencil_paint_initstroke(tGPsdata *p,
bool need_tag = p->gpl->actframe == NULL;
bGPDframe *actframe = p->gpl->actframe;
- p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode);
/* Only if there wasn't an active frame, need update. */
if (need_tag) {
DEG_id_tag_update(&p->gpd->id, ID_RECALC_GEOMETRY);
@@ -2343,7 +2410,7 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
if (p->paintmode == GP_PAINTMODE_ERASER) {
GPUVertFormat *format = immVertexFormat();
const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
@@ -2353,7 +2420,7 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -3658,9 +3725,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- /* Exit painting mode (and/or end current stroke).
- *
- */
+ /* Exit painting mode (and/or end current stroke). */
if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, EVT_ESCKEY, EVT_SPACEKEY)) {
p->status = GP_STATUS_DONE;
@@ -3755,7 +3820,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* handle mode-specific events */
if (p->status == GP_STATUS_PAINTING) {
/* handle painting mouse-movements? */
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
+ if (ISMOUSE_MOTION(event->type) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
/* handle drawing event */
bool is_speed_guide = ((guide->use_guide) &&
(p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index b57b8145749..4a4fffc9638 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -292,7 +292,7 @@ static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
Brush *brush = tgpi->brush;
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -1024,8 +1024,10 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
/* add small offset to keep stroke over the surface */
- if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) {
- depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f));
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
+ if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) {
+ depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f));
+ }
}
/* convert screen-coordinates to 3D coordinates */
@@ -1107,7 +1109,7 @@ static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive
/* Initialize mouse points. */
static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
{
- copy_v2fl_v2i(tgpi->mval, event->mval);
+ WM_event_drag_start_mval_fl(event, tgpi->region, tgpi->mval);
copy_v2_v2(tgpi->origin, tgpi->mval);
copy_v2_v2(tgpi->start, tgpi->mval);
copy_v2_v2(tgpi->end, tgpi->mval);
@@ -1195,7 +1197,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->orign_type = RNA_enum_get(op->ptr, "type");
/* set current frame number */
- tgpi->cframe = CFRA;
+ tgpi->cframe = scene->r.cfra;
/* set GP datablock */
tgpi->gpd = gpd;
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 6d0848de36d..e27cd255217 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -1013,7 +1013,7 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
gpl = CTX_data_active_gpencil_layer(C);
}
bGPDframe *gpf = BKE_gpencil_layer_frame_get(
- gpl, CFRA, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV);
+ gpl, scene->r.cfra, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
}
@@ -1161,6 +1161,7 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->is_painting = false;
gso->first = true;
+ gso->mval_prev[0] = -1.0f;
gso->gpd = ED_gpencil_data_get_active(C);
gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
@@ -1335,7 +1336,7 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso
bGPdata *gpd = gso->gpd;
Scene *scene = gso->scene;
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
/* only try to add a new frame if this is the first stroke, or the frame has changed */
if ((gpd == NULL) || (cfra == gso->cfra)) {
@@ -1442,6 +1443,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
char tool = gso->brush->gpencil_sculpt_tool;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
+ const bool is_masking = GPENCIL_ANY_SCULPT_MASK(gso->mask);
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt_active = NULL;
@@ -1459,7 +1461,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
pt = &gps->points[0];
- if (GPENCIL_ANY_SCULPT_MASK(gso->mask) && (pt->flag & GP_SPOINT_SELECT) != 0) {
+ if ((is_masking && (pt->flag & GP_SPOINT_SELECT) != 0) || (!is_masking)) {
gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
@@ -1516,7 +1518,8 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- if ((pt->runtime.pt_orig == NULL) && (tool != GPSCULPT_TOOL_GRAB)) {
+ if ((i != gps->totpoints - 2) && (pt->runtime.pt_orig == NULL) &&
+ (tool != GPSCULPT_TOOL_GRAB)) {
continue;
}
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
@@ -1618,7 +1621,8 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
}
/* Check if the stroke collide with brush. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
+ if ((gps->totpoints > 1) &&
+ (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat))) {
continue;
}
@@ -1982,7 +1986,7 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
}
/* Store coordinates as reference, if operator just started running */
- if (gso->first) {
+ if (gso->mval_prev[0] == -1.0f) {
gso->mval_prev[0] = gso->mval[0];
gso->mval_prev[1] = gso->mval[1];
gso->pressure_prev = gso->pressure;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index e903d11a1e0..a19265720e8 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -759,7 +759,7 @@ static bool gpencil_select_same_layer(bContext *C)
bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
bGPDstroke *gps;
bool found = false;
diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c
index 24a0dab24c9..f6e88e05d46 100644
--- a/source/blender/editors/gpencil/gpencil_trace_ops.c
+++ b/source/blender/editors/gpencil/gpencil_trace_ops.c
@@ -295,7 +295,7 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op)
job->base_active = CTX_data_active_base(C);
job->ob_active = job->base_active->object;
job->image = (Image *)job->ob_active->data;
- job->frame_target = CFRA;
+ job->frame_target = scene->r.cfra;
job->use_current_frame = RNA_boolean_get(op->ptr, "use_current_frame");
/* Create a new grease pencil object or reuse selected. */
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index fc5b3838900..e47f16ac466 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -388,6 +388,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
+ {
+ /* "New Layer" entry */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ADD;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
const int tot = BLI_listbase_count(&gpd->layers);
/* Existing layers */
@@ -405,17 +416,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
- {
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
-
- /* "New Layer" entry */
- item_tmp.identifier = "__CREATE__";
- item_tmp.name = "New Layer";
- item_tmp.value = -1;
- item_tmp.icon = ICON_ADD;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1683,7 +1683,7 @@ void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
GPUVertFormat *format = immVertexFormat();
const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1693,7 +1693,7 @@ void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1865,7 +1865,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
/* draw icon */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
@@ -3189,7 +3189,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
/* Join both strokes. */
int totpoint = gps_final->totpoints;
- BKE_gpencil_stroke_join(gps_final, gps, false, true, true);
+ BKE_gpencil_stroke_join(gps_final, gps, false, true, true, true);
/* Select the join points and merge if the distance is very small. */
pt = &gps_final->points[totpoint - 1];
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index da40eef87fd..ee87de5774a 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -324,12 +324,17 @@ typedef enum eAnimFilter_Flags {
/** duplicate entries for animation data attached to multi-user blocks must not occur */
ANIMFILTER_NODUPLIS = (1 << 11),
+ /** avoid channel that does not have any F-curve data */
+ ANIMFILTER_FCURVESONLY = (1 << 12),
+
/** for checking if we should keep some collapsed channel around (internal use only!) */
ANIMFILTER_TMP_PEEK = (1 << 30),
/** Ignore ONLYSEL flag from #bDopeSheet.filterflag (internal use only!) */
ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31),
+
} eAnimFilter_Flags;
+ENUM_OPERATORS(eAnimFilter_Flags, ANIMFILTER_TMP_IGNORE_ONLYSEL);
/** \} */
@@ -1042,6 +1047,8 @@ void ED_keymap_anim(struct wmKeyConfig *keyconf);
void ED_operatormacros_graph(void);
/* space_action */
void ED_operatormacros_action(void);
+/* space_nla*/
+void ED_operatormacros_nla(void);
/** \} */
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index c5a45f8b73e..0f981e270a0 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -22,15 +22,53 @@ struct bScreen;
/* ** clip_editor.c ** */
-/* common poll functions */
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - There is a movie clip opened in it. */
bool ED_space_clip_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Clip view.
+ *
+ * It is not required to have movie clip opened for editing. */
bool ED_space_clip_view_clip_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Tracking mode.
+ *
+ * It is not required to have movie clip opened for editing. */
bool ED_space_clip_tracking_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ *
+ * It is not required to have mask opened for editing. */
bool ED_space_clip_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_space_clip_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - The space has mask opened. */
bool ED_space_clip_maskedit_mask_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_space_clip_maskedit_mask_visible_splines_poll(struct bContext *C);
+
void ED_space_clip_get_size(struct SpaceClip *sc, int *width, int *height);
void ED_space_clip_get_size_fl(struct SpaceClip *sc, float size[2]);
void ED_space_clip_get_zoom(struct SpaceClip *sc,
diff --git a/source/blender/editors/include/ED_curves.h b/source/blender/editors/include/ED_curves.h
index 9233b65b2ce..00831ff7cc3 100644
--- a/source/blender/editors/include/ED_curves.h
+++ b/source/blender/editors/include/ED_curves.h
@@ -6,6 +6,8 @@
#pragma once
+struct bContext;
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -19,10 +21,19 @@ void ED_operatortypes_curves(void);
#ifdef __cplusplus
# include "BKE_curves.hh"
+# include "BLI_vector_set.hh"
namespace blender::ed::curves {
bke::CurvesGeometry primitive_random_sphere(int curves_size, int points_per_curve);
+bool has_anything_selected(const Curves &curves_id);
+VectorSet<Curves *> get_unique_editable_curves(const bContext &C);
+void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob);
-}
+bool editable_curves_with_surface_poll(bContext *C);
+bool curves_with_surface_poll(bContext *C);
+bool editable_curves_poll(bContext *C);
+bool curves_poll(bContext *C);
+
+} // namespace blender::ed::curves
#endif
diff --git a/source/blender/editors/include/ED_curves_sculpt.h b/source/blender/editors/include/ED_curves_sculpt.h
index 8aab1533e25..b1c0b649d2b 100644
--- a/source/blender/editors/include/ED_curves_sculpt.h
+++ b/source/blender/editors/include/ED_curves_sculpt.h
@@ -10,8 +10,33 @@
extern "C" {
#endif
+struct Curves;
+
void ED_operatortypes_sculpt_curves(void);
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+# include "BLI_index_mask.hh"
+# include "BLI_vector.hh"
+
+namespace blender::ed::sculpt_paint {
+
+/**
+ * Find curves that have any point selected (a selection factor greater than zero),
+ * or curves that have their own selection factor greater than zero.
+ */
+IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
+
+/**
+ * Find points that are selected (a selection factor greater than zero),
+ * or points in curves with a selection factor greater than zero).
+ */
+IndexMask retrieve_selected_points(const Curves &curves_id, Vector<int64_t> &r_indices);
+
+} // namespace blender::ed::sculpt_paint
+
+#endif
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index e9fcd2bd5fe..9d5d8dd54cb 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -175,6 +175,14 @@ struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
*/
struct ScrArea *ED_fileselect_handler_area_find_any_with_op(const struct wmWindow *win);
+/**
+ * If filepath property is not set on the operator, sets it to
+ * the blend file path (or untitled if file is not saved yet) with the given extension.
+ */
+void ED_fileselect_ensure_default_filepath(struct bContext *C,
+ struct wmOperator *op,
+ const char *extension);
+
/* TODO: Maybe we should move this to BLI?
* On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 0943636a452..bf021d68cec 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -239,7 +239,7 @@ void ED_annotation_draw_ex(
/* ----------- Grease-Pencil AnimEdit API ------------------ */
/**
- * Loops over the gp-frames for a gp-layer, and applies the given callback.
+ * Loops over the GP-frames for a GP-layer, and applies the given callback.
*/
bool ED_gpencil_layer_frames_looper(struct bGPDlayer *gpl,
struct Scene *scene,
@@ -281,6 +281,11 @@ void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
/**
+ * Set the layer's channel as active
+ */
+void ED_gpencil_set_active_channel(struct bGPdata *gpd, struct bGPDlayer *gpl);
+
+/**
* Delete selected frames.
*/
bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl);
@@ -398,12 +403,11 @@ void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
*/
void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]);
/**
- * Add a 2D Suzanne (original model created by Matias Mendiola).
+ * Add a 2D Suzanne.
*/
void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]);
/**
- * Add a Simple stroke with colors
- * (original design created by Daniel M. Lara and Matias Mendiola).
+ * Add a Simple stroke with colors.
*/
void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]);
/**
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index b16844c01ea..91ae8286531 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -137,8 +137,39 @@ bool ED_space_image_paint_curve(const struct bContext *C);
* Matches clip function.
*/
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct Object *obedit);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not a UV Editor.
+ * - It is set to Mask mode.
+ *
+ * It is not required to have mask opened for editing. */
bool ED_space_image_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not a UV Editor.
+ * - It is set to Mask mode.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_space_image_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not an UV Editor.
+ * - It is set to Mask mode.
+ * - The space has mask opened. */
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not an UV Editor.
+ * - It is set to Mask mode.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_space_image_maskedit_mask_visible_splines_poll(struct bContext *C);
+
bool ED_space_image_cursor_poll(struct bContext *C);
/**
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 163797d395d..1d63e01c84b 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -229,6 +229,16 @@ typedef enum eKeyMergeMode {
KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL,
} eKeyMergeMode;
+/* Possible errors occurring while pasting keys. */
+typedef enum eKeyPasteError {
+ /* No errors occurred */
+ KEYFRAME_PASTE_OK,
+ /* Nothing was copied */
+ KEYFRAME_PASTE_NOTHING_TO_PASTE,
+ /* No F-curves was selected to paste into*/
+ KEYFRAME_PASTE_NOWHERE_TO_PASTE
+} eKeyPasteError;
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -378,9 +388,6 @@ bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, con
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
-void delete_fcurve_key(struct FCurve *fcu, int index, bool do_recalc);
-bool delete_fcurve_keys(struct FCurve *fcu);
-void clear_fcurve_keys(struct FCurve *fcu);
bool duplicate_fcurve_keys(struct FCurve *fcu);
float get_default_rna_value(struct FCurve *fcu, struct PropertyRNA *prop, struct PointerRNA *ptr);
@@ -416,11 +423,11 @@ void sample_fcurve(struct FCurve *fcu);
void ANIM_fcurves_copybuf_free(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
-short paste_animedit_keys(struct bAnimContext *ac,
- ListBase *anim_data,
- eKeyPasteOffset offset_mode,
- eKeyMergeMode merge_mode,
- bool flip);
+eKeyPasteError paste_animedit_keys(struct bAnimContext *ac,
+ ListBase *anim_data,
+ eKeyPasteOffset offset_mode,
+ eKeyMergeMode merge_mode,
+ bool flip);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 7039d6d9fc7..8cadbfde185 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -22,6 +22,34 @@ struct wmKeyConfig;
/* mask_edit.c */
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - The space has mask open for editing. */
+bool ED_maskedit_mask_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_maskedit_mask_visible_splines_poll(struct bContext *C);
+
void ED_mask_deselect_all(const struct bContext *C);
void ED_operatortypes_mask(void);
@@ -73,6 +101,7 @@ void ED_mask_draw_region(struct Depsgraph *depsgraph,
char draw_flag,
char draw_type,
eMaskOverlayMode overlay_mode,
+ float blend_factor,
int width_i,
int height_i,
float aspx,
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 30a98129ee6..b6a652bd3ab 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -137,14 +137,16 @@ void EDBM_update_extern(struct Mesh *me, bool do_tessellation, bool is_destructi
*/
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
- bool face_selected,
bool uv_selected,
bool use_winding,
bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *element_map);
-struct UvElement *BM_uv_element_get(struct UvElementMap *map,
- struct BMFace *efa,
- struct BMLoop *l);
+struct UvElement *BM_uv_element_get(const struct UvElementMap *map,
+ const struct BMFace *efa,
+ const struct BMLoop *l);
+struct UvElement *BM_uv_element_get_head(struct UvElementMap *map, struct UvElement *child);
+
+struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *element_map);
/**
* Can we edit UV's for this mesh?
@@ -181,9 +183,13 @@ void EDBM_project_snap_verts(struct bContext *C,
/* editmesh_automerge.c */
-void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist);
-void EDBM_automerge_and_split(
- struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist);
+void EDBM_automerge(struct Object *obedit, bool update, char hflag, float dist);
+void EDBM_automerge_and_split(struct Object *obedit,
+ bool split_edges,
+ bool split_faces,
+ bool update,
+ char hflag,
+ float dist);
/* editmesh_undo.c */
@@ -390,7 +396,10 @@ void ED_keymap_mesh(struct wmKeyConfig *keyconf);
* Copy the face flags, most importantly selection from the mesh to the final derived mesh,
* use in object mode when selecting faces (while painting).
*/
-void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
+void paintface_flush_flags(struct bContext *C,
+ struct Object *ob,
+ bool flush_selection,
+ bool flush_hidden);
/**
* \return True when pick finds an element or the selection changed.
*/
@@ -425,6 +434,9 @@ void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags
void paintvert_flush_flags(struct Object *ob);
void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
+void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
+void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);
+
/* mirrtopo */
typedef struct MirrTopoStore_t {
intptr_t *index_lookup;
@@ -442,7 +454,7 @@ void ED_mesh_mirrtopo_init(struct BMEditMesh *em,
bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
-/* object_vgroup.c */
+/* object_vgroup.cc */
#define WEIGHT_REPLACE 1
#define WEIGHT_ADD 2
@@ -550,16 +562,10 @@ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, int layernum);
bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
int ED_mesh_color_add(
struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
-bool ED_mesh_color_remove_index(struct Mesh *me, int n);
-bool ED_mesh_color_remove_active(struct Mesh *me);
-bool ED_mesh_color_remove_named(struct Mesh *me, const char *name);
-
-bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_sculpt_color_add(
- struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
-bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, int n);
-bool ED_mesh_sculpt_color_remove_active(struct Mesh *me);
-bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name);
+int ED_mesh_sculpt_color_add(struct Mesh *me,
+ const char *name,
+ bool do_init,
+ struct ReportList *reports);
void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail);
void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode);
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index ba5834fd508..048424cdee1 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -22,6 +22,7 @@ struct UndoType;
struct bContext;
struct wmKeyConfig;
struct wmOperator;
+typedef struct PaintTileMap PaintTileMap;
/* paint_ops.c */
@@ -76,7 +77,7 @@ void ED_image_undo_restore(struct UndoStep *us);
/** Export for ED_undo_sys. */
void ED_image_undosys_type(struct UndoType *ut);
-void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
+void *ED_image_paint_tile_find(PaintTileMap *paint_tile_map,
struct Image *image,
struct ImBuf *ibuf,
struct ImageUser *iuser,
@@ -84,7 +85,7 @@ void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
int y_tile,
unsigned short **r_mask,
bool validate);
-void *ED_image_paint_tile_push(struct ListBase *paint_tiles,
+void *ED_image_paint_tile_push(PaintTileMap *paint_tile_map,
struct Image *image,
struct ImBuf *ibuf,
struct ImBuf **tmpibuf,
@@ -98,7 +99,7 @@ void *ED_image_paint_tile_push(struct ListBase *paint_tiles,
void ED_image_paint_tile_lock_init(void);
void ED_image_paint_tile_lock_end(void);
-struct ListBase *ED_image_paint_tile_list_get(void);
+struct PaintTileMap *ED_image_paint_tile_map_get(void);
#define ED_IMAGE_UNDO_TILE_BITS 6
#define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS)
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index aa62a6209e4..eeed1c9b286 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -294,7 +294,7 @@ void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
struct wmWindow *win,
struct bScreen *screen);
-void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
+void ED_screen_do_listen(struct bContext *C, const struct wmNotifier *note);
/**
* \brief Change the active screen.
*
@@ -595,7 +595,6 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
-bool ED_operator_mask(struct bContext *C);
bool ED_operator_camera_poll(struct bContext *C);
/* screen_user_menu.c */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 550040d2bc6..1e220d33ff4 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -20,6 +20,7 @@ struct rcti;
struct wmMsgSubscribeKey;
struct wmMsgSubscribeValue;
struct wmRegionMessageSubscribeParams;
+struct wmOperator;
/* sculpt.c */
@@ -33,7 +34,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
/* sculpt_transform.c */
void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob);
-void ED_sculpt_init_transform(struct bContext *C, struct Object *ob);
+void ED_sculpt_init_transform(struct bContext *C, struct Object *ob, const char *undo_name);
void ED_sculpt_end_transform(struct bContext *C, struct Object *ob);
/* sculpt_undo.c */
@@ -41,7 +42,13 @@ void ED_sculpt_end_transform(struct bContext *C, struct Object *ob);
/** Export for ED_undo_sys. */
void ED_sculpt_undosys_type(struct UndoType *ut);
-void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
+/**
+ * Pushes an undo step using the operator name. This is necessary for
+ * redo panels to work; operators that do not support that may use
+ * #ED_sculpt_undo_geometry_begin_ex instead if so desired.
+ */
+void ED_sculpt_undo_geometry_begin(struct Object *ob, const struct wmOperator *op);
+void ED_sculpt_undo_geometry_begin_ex(struct Object *ob, const char *name);
void ED_sculpt_undo_geometry_end(struct Object *ob);
/* Face sets. */
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index fa02ebe18f6..8c856794ec8 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -40,11 +40,11 @@ typedef enum {
} eSelectOp;
/* Select Similar */
-enum {
+typedef enum {
SIM_CMP_EQ = 0,
SIM_CMP_GT,
SIM_CMP_LT,
-};
+} eSimilarCmp;
#define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND))
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
@@ -63,11 +63,11 @@ int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside);
*/
int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside);
-int ED_select_similar_compare_float(float delta, float thresh, int compare);
+bool ED_select_similar_compare_float(float delta, float thresh, eSimilarCmp compare);
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
float length,
float thresh,
- int compare);
+ eSimilarCmp compare);
/**
* Utility to use for selection operations that run multiple times (circle select).
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 20353c21f93..f9ca578f282 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -57,9 +57,13 @@ struct SnapObjectParams {
/* Geometry for snapping in edit mode. */
eSnapEditType edit_mode_type;
/* snap to the closest element, use when using more than one snap type */
- bool use_occlusion_test : true;
+ bool use_occlusion_test : 1;
/* exclude back facing geometry from snapping */
- bool use_backface_culling : true;
+ bool use_backface_culling : 1;
+ /* Break nearest face snapping into steps to improve transformations across U-shaped targets. */
+ short face_nearest_steps;
+ /* Enable to force nearest face snapping to snap to target the source was initially near. */
+ bool keep_on_same_target : 1;
};
typedef struct SnapObjectContext SnapObjectContext;
@@ -114,12 +118,33 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
struct ListBase *r_hit_list);
+/**
+ * Perform snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face/grid.
+ *
+ * \param sctx: Snap context.
+ * \param snap_to: Target elements to snap source to.
+ * \param params: Addition snapping options.
+ * \param init_co: Initial world-space coordinate of source (optional).
+ * \param mval: Current transformed screen-space coordinate or mouse position (optional).
+ * \param prev_co: Current transformed world-space coordinate of source (optional).
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param r_loc: Snapped world-space coordinate.
+ * \param r_no: Snapped world-space normal (optional).
+ * \param r_index: Index of snapped-to target element (optional).
+ * \param r_ob: Snapped-to target object (optional).
+ * \param r_obmat: Matrix of snapped-to target object (optional).
+ * \param r_face_nor: World-space normal of snapped-to target face (optional).
+ * \return Snapped-to element, #eSnapMode.
+ */
eSnapMode ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
- eSnapMode snap_to,
+ const eSnapMode snap_to,
const struct SnapObjectParams *params,
+ const float init_co[3],
const float mval[2],
const float prev_co[3],
float *dist_px,
@@ -135,19 +160,23 @@ eSnapMode ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *s
* Given a 2D region value, snap to vert/edge/face.
*
* \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
- * \param prev_co: Coordinate for perpendicular point calculation (optional).
+ * \param snap_to: Target elements to snap source to.
+ * \param params: Addition snapping options.
+ * \param init_co: Initial world-space coordinate of source (optional).
+ * \param mval: Current transformed screen-space coordinate or mouse position (optional).
+ * \param prev_co: Current transformed world-space coordinate of source (optional).
* \param dist_px: Maximum distance to snap (in pixels).
- * \param r_loc: hit location.
- * \param r_no: hit normal (optional).
- * \return Snap success.
+ * \param r_loc: Snapped world-space coordinate.
+ * \param r_no: Snapped world-space normal (optional).
+ * \return Snapped-to element, #eSnapMode.
*/
eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
- eSnapMode snap_to,
+ const eSnapMode snap_to,
const struct SnapObjectParams *params,
+ const float init_co[3],
const float mval[2],
const float prev_co[3],
float *dist_px,
diff --git a/source/blender/editors/include/ED_types.h b/source/blender/editors/include/ED_types.h
deleted file mode 100644
index eba93ed6744..00000000000
--- a/source/blender/editors/include/ED_types.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2008 Blender Foundation. All rights reserved. */
-
-/** \file
- * \ingroup editors
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* **************** GENERAL EDITOR-WIDE TYPES AND DEFINES ************************** */
-
-/* old blender defines... should be deprecated? */
-#define DESELECT 0
-#define SELECT 1
-#define ACTIVE 2
-
-/* proposal = put scene pointers on function calls? */
-// #define BASACT (scene->basact)
-// #define OBACT (BASACT ? BASACT->object : NULL)
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 80a75da27f8..38e542fc0ca 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -107,7 +107,7 @@ bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_l
* Changes selection state of a single UV Face.
*/
void uvedit_face_select_set(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *em,
struct BMFace *efa,
bool select,
bool do_history,
@@ -118,7 +118,7 @@ void uvedit_face_select_set(const struct Scene *scene,
* Changes selection state of a single UV Edge.
*/
void uvedit_edge_select_set(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *em,
struct BMLoop *l,
bool select,
bool do_history,
@@ -129,7 +129,7 @@ void uvedit_edge_select_set(const struct Scene *scene,
* Changes selection state of a single UV vertex.
*/
void uvedit_uv_select_set(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *em,
struct BMLoop *l,
bool select,
bool do_history,
@@ -139,30 +139,30 @@ void uvedit_uv_select_set(const struct Scene *scene,
* use. */
void uvedit_face_select_enable(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *bm,
struct BMFace *efa,
bool do_history,
int cd_loop_uv_offset);
void uvedit_face_select_disable(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *bm,
struct BMFace *efa,
int cd_loop_uv_offset);
void uvedit_edge_select_enable(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *bm,
struct BMLoop *l,
bool do_history,
int cd_loop_uv_offset);
void uvedit_edge_select_disable(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *bm,
struct BMLoop *l,
int cd_loop_uv_offset);
void uvedit_uv_select_enable(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *bm,
struct BMLoop *l,
bool do_history,
int cd_loop_uv_offset);
void uvedit_uv_select_disable(const struct Scene *scene,
- struct BMEditMesh *em,
+ struct BMesh *bm,
struct BMLoop *l,
int cd_loop_uv_offset);
@@ -179,13 +179,13 @@ void uvedit_edge_select_set_with_sticky(const struct Scene *scene,
struct BMLoop *l,
bool select,
bool do_history,
- uint cd_loop_uv_offset);
+ int cd_loop_uv_offset);
void uvedit_uv_select_set_with_sticky(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
bool select,
bool do_history,
- uint cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* Low level functions for sticky element selection (sticky mode independent). Type of sticky
* selection is specified explicitly (using sticky_flag, except for face selection). */
@@ -305,6 +305,29 @@ void ED_uvedit_buttons_register(struct ARegionType *art);
/* uvedit_islands.c */
+struct FaceIsland {
+ struct FaceIsland *next;
+ struct FaceIsland *prev;
+ struct BMFace **faces;
+ int faces_len;
+ rctf bounds_rect;
+ /**
+ * \note While this is duplicate information,
+ * it allows islands from multiple meshes to be stored in the same list.
+ */
+ int cd_loop_uv_offset;
+ float aspect_y;
+};
+
+int bm_mesh_calc_uv_islands(const Scene *scene,
+ struct BMesh *bm,
+ ListBase *island_list,
+ const bool only_selected_faces,
+ const bool only_selected_uvs,
+ const bool use_seams,
+ const float aspect_y,
+ const int cd_loop_uv_offset);
+
struct UVMapUDIM_Params {
const struct Image *image;
/** Copied from #SpaceImage.tile_grid_shape */
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index ddd0cb252cb..4b74f687951 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -711,7 +711,7 @@ bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph,
float r_ray_start[3],
float r_ray_end[3],
bool do_clip_planes);
-void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
+void ED_view3d_ob_project_mat_get(const struct RegionView3D *rv3d,
const struct Object *ob,
float r_pmat[4][4]);
void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d,
@@ -950,7 +950,7 @@ int view3d_opengl_select_with_id_filter(struct ViewContext *vc,
eV3DSelectObjectFilter select_filter,
uint select_id);
-/* view3d_select.c */
+/* view3d_select.cc */
float ED_view3d_select_dist_px(void);
void ED_view3d_viewcontext_init(struct bContext *C,
@@ -1175,7 +1175,7 @@ void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph,
*
* Apply the 3D Viewport transformation back to the camera object.
*
- * \return true if the camera is moved.
+ * \return true if the camera (or one of it's parents) was moved.
*/
bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
struct View3D *v3d,
@@ -1200,6 +1200,36 @@ bool ED_view3d_camera_lock_autokey(struct View3D *v3d,
void ED_view3d_lock_clear(struct View3D *v3d);
+/**
+ * Check if creating an undo step should be performed if the viewport moves.
+ * \return true if #ED_view3d_camera_lock_undo_push would do an undo push.
+ */
+bool ED_view3d_camera_lock_undo_test(const View3D *v3d,
+ const RegionView3D *rv3d,
+ struct bContext *C);
+
+/**
+ * Create an undo step when the camera is locked to the view.
+ * \param str: The name of the undo step (typically #wmOperatorType.name should be used).
+ *
+ * \return true when the call to push an undo step was made.
+ */
+bool ED_view3d_camera_lock_undo_push(const char *str,
+ const View3D *v3d,
+ const struct RegionView3D *rv3d,
+ struct bContext *C);
+
+/**
+ * A version of #ED_view3d_camera_lock_undo_push that performs a grouped undo push.
+ *
+ * \note use for actions that are likely to be repeated such as mouse wheel to zoom,
+ * where adding a separate undo step each time isn't desirable.
+ */
+bool ED_view3d_camera_lock_undo_grouped_push(const char *str,
+ const View3D *v3d,
+ const struct RegionView3D *rv3d,
+ struct bContext *C);
+
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
diff --git a/source/blender/editors/include/UI_abstract_view.hh b/source/blender/editors/include/UI_abstract_view.hh
new file mode 100644
index 00000000000..dfddace8899
--- /dev/null
+++ b/source/blender/editors/include/UI_abstract_view.hh
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editorui
+ *
+ * Base class for all views (UIs to display data sets) and view items, supporting common features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views
+ *
+ * One of the most important responsibilities of the base class is managing reconstruction,
+ * enabling state that is persistent over reconstructions/redraws. Other features:
+ * - Renaming
+ * - Custom context menus
+ * - Notifier listening
+ * - Drag controllers (dragging view items)
+ * - Drop controllers (dropping onto/into view items)
+ */
+
+#pragma once
+
+#include <array>
+#include <memory>
+
+#include "DNA_defs.h"
+
+#include "BLI_span.hh"
+#include "BLI_string_ref.hh"
+
+struct bContext;
+struct uiBlock;
+struct uiBut;
+struct uiLayout;
+struct uiViewItemHandle;
+struct wmDrag;
+struct wmNotifier;
+
+namespace blender::ui {
+
+class AbstractViewItem;
+class AbstractViewItemDropController;
+class AbstractViewItemDragController;
+
+class AbstractView {
+ friend class AbstractViewItem;
+
+ bool is_reconstructed_ = false;
+ /**
+ * Only one item can be renamed at a time. So rather than giving each item an own rename buffer
+ * (which just adds unused memory in most cases), have one here that is managed by the view.
+ *
+ * This fixed-size buffer is needed because that's what the rename button requires. In future we
+ * may be able to bind the button to a `std::string` or similar.
+ */
+ std::unique_ptr<std::array<char, MAX_NAME>> rename_buffer_;
+
+ public:
+ virtual ~AbstractView() = default;
+
+ /** Listen to a notifier, returning true if a redraw is needed. */
+ virtual bool listen(const wmNotifier &) const;
+
+ /**
+ * Makes \a item valid for display in this view. Behavior is undefined for items not registered
+ * with this.
+ */
+ void register_item(AbstractViewItem &item);
+
+ /** Only one item can be renamed at a time. */
+ bool is_renaming() const;
+ /** \return If renaming was started successfully. */
+ bool begin_renaming();
+ void end_renaming();
+ Span<char> get_rename_buffer() const;
+ MutableSpan<char> get_rename_buffer();
+
+ protected:
+ AbstractView() = default;
+
+ virtual void update_children_from_old(const AbstractView &old_view) = 0;
+
+ /**
+ * Match the view and its items against an earlier version of itself (if any) and copy the old UI
+ * state (e.g. collapsed, active, selected, renaming, etc.) to the new one. See
+ * #AbstractViewItem.update_from_old().
+ * After this, reconstruction is complete (see #is_reconstructed()).
+ */
+ void update_from_old(uiBlock &new_block);
+ /**
+ * Check if the view is fully (re-)constructed. That means, both the build function and
+ * #update_from_old() have finished.
+ */
+ bool is_reconstructed() const;
+};
+
+class AbstractViewItem {
+ friend class AbstractView;
+ friend class ViewItemAPIWrapper;
+
+ protected:
+ /**
+ * The view this item is a part of, and was registered for using #AbstractView::register_item().
+ * If this wasn't done, the behavior of items is undefined.
+ */
+ AbstractView *view_ = nullptr;
+ bool is_active_ = false;
+ bool is_renaming_ = false;
+
+ public:
+ virtual ~AbstractViewItem() = default;
+
+ virtual void build_context_menu(bContext &C, uiLayout &column) const;
+
+ /**
+ * Queries if the view item supports renaming in principle. Renaming may still fail, e.g. if
+ * another item is already being renamed.
+ */
+ virtual bool supports_renaming() const;
+ /**
+ * Try renaming the item, or the data it represents. Can assume
+ * #AbstractViewItem::supports_renaming() returned true. Sub-classes that override this should
+ * usually call this, unless they have a custom #AbstractViewItem.matches() implementation.
+ *
+ * \return True if the renaming was successful.
+ */
+ virtual bool rename(StringRefNull new_name);
+ /**
+ * Get the string that should be used for renaming, typically the item's label. This string will
+ * not be modified, but if the renaming is canceled, the value will be reset to this.
+ */
+ virtual StringRef get_rename_string() const;
+
+ /**
+ * If an item wants to support being dragged, it has to return a drag controller here.
+ * That is an object implementing #AbstractViewItemDragController.
+ */
+ virtual std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const;
+ /**
+ * If an item wants to support dropping data into it, it has to return a drop controller here.
+ * That is an object implementing #AbstractViewItemDropController.
+ *
+ * \note This drop controller may be requested for each event. The view doesn't keep a drop
+ * controller around currently. So it can not contain persistent state.
+ */
+ virtual std::unique_ptr<AbstractViewItemDropController> create_drop_controller() const;
+
+ /** Get the view this item is registered for using #AbstractView::register_item(). */
+ AbstractView &get_view() const;
+
+ /**
+ * Requires the view to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ bool is_renaming() const;
+ void begin_renaming();
+ void end_renaming();
+ void rename_apply();
+
+ template<typename ToType = AbstractViewItem>
+ static ToType *from_item_handle(uiViewItemHandle *handle);
+
+ protected:
+ AbstractViewItem() = default;
+
+ /**
+ * Compare this item's identity to \a other to check if they represent the same data.
+ * Implementations can assume that the types match already (caller must check).
+ *
+ * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
+ * renaming, etc.).
+ */
+ virtual bool matches(const AbstractViewItem &other) const = 0;
+
+ /**
+ * Copy persistent state (e.g. active, selection, etc.) from a matching item of
+ * the last redraw to this item. If sub-classes introduce more advanced state they should
+ * override this and make it update their state accordingly.
+ *
+ * \note Always call the base class implementation when overriding this!
+ */
+ virtual void update_from_old(const AbstractViewItem &old);
+
+ /**
+ * Add a text button for renaming the item to \a block. This must be used for the built-in
+ * renaming to work. This button is meant to appear temporarily. It is removed when renaming is
+ * done.
+ */
+ void add_rename_button(uiBlock &block);
+};
+
+template<typename ToType> ToType *AbstractViewItem::from_item_handle(uiViewItemHandle *handle)
+{
+ static_assert(std::is_base_of<AbstractViewItem, ToType>::value,
+ "Type must derive from and implement the AbstractViewItem interface");
+
+ return dynamic_cast<ToType *>(reinterpret_cast<AbstractViewItem *>(handle));
+}
+
+/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+/**
+ * Class to enable dragging a view item. An item can return a drop controller for itself by
+ * implementing #AbstractViewItem::create_drag_controller().
+ */
+class AbstractViewItemDragController {
+ protected:
+ AbstractView &view_;
+
+ public:
+ AbstractViewItemDragController(AbstractView &view);
+ virtual ~AbstractViewItemDragController() = default;
+
+ virtual int get_drag_type() const = 0;
+ virtual void *create_drag_data() const = 0;
+ virtual void on_drag_start();
+
+ /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
+ * exception if the view is not of the requested type. */
+ template<class ViewType> inline ViewType &get_view() const;
+};
+
+/**
+ * Class to define the behavior when dropping something onto/into a view item, plus the behavior
+ * when dragging over this item. An item can return a drop controller for itself via a custom
+ * implementation of #AbstractViewItem::create_drop_controller().
+ */
+class AbstractViewItemDropController {
+ protected:
+ AbstractView &view_;
+
+ public:
+ AbstractViewItemDropController(AbstractView &view);
+ virtual ~AbstractViewItemDropController() = default;
+
+ /**
+ * Check if the data dragged with \a drag can be dropped on the item this controller is for.
+ * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
+ * isn't possible on this item. Shouldn't be done too aggressively, e.g.
+ * don't set this if the drag-type can't be dropped here; only if it can
+ * but there's another reason it can't be dropped.
+ * Can assume this is a non-null pointer.
+ */
+ virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
+ /**
+ * Custom text to display when dragging over a view item. Should explain what happens when
+ * dropping the data onto this item. Will only be used if #AbstractViewItem::can_drop()
+ * returns true, so the implementing override doesn't have to check that again.
+ * The returned value must be a translated string.
+ */
+ virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
+ /**
+ * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
+ * controller is for.
+ */
+ virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
+
+ /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
+ * exception if the view is not of the requested type. */
+ template<class ViewType> inline ViewType &get_view() const;
+};
+
+template<class ViewType> ViewType &AbstractViewItemDragController::get_view() const
+{
+ static_assert(std::is_base_of<AbstractView, ViewType>::value,
+ "Type must derive from and implement the ui::AbstractView interface");
+ return dynamic_cast<ViewType &>(view_);
+}
+
+template<class ViewType> ViewType &AbstractViewItemDropController::get_view() const
+{
+ static_assert(std::is_base_of<AbstractView, ViewType>::value,
+ "Type must derive from and implement the ui::AbstractView interface");
+ return dynamic_cast<ViewType &>(view_);
+}
+
+/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
index 6f553f4fad1..402c0c8512f 100644
--- a/source/blender/editors/include/UI_grid_view.hh
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -13,12 +13,13 @@
#include "BLI_map.hh"
#include "BLI_vector.hh"
+#include "UI_abstract_view.hh"
#include "UI_resources.h"
struct bContext;
struct PreviewImage;
struct uiBlock;
-struct uiButGridTile;
+struct uiButViewItem;
struct uiLayout;
struct View2D;
struct wmNotifier;
@@ -31,43 +32,29 @@ class AbstractGridView;
/** \name Grid-View Item Type
* \{ */
-class AbstractGridViewItem {
+class AbstractGridViewItem : public AbstractViewItem {
friend class AbstractGridView;
friend class GridViewLayoutBuilder;
- const AbstractGridView *view_;
-
- bool is_active_ = false;
-
protected:
/** Reference to a string that uniquely identifies this item in the view. */
StringRef identifier_{};
- /** Every visible item gets a button of type #UI_BTYPE_GRID_TILE during the layout building. */
- uiButGridTile *grid_tile_but_ = nullptr;
+ /** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
+ uiButViewItem *view_item_but_ = nullptr;
public:
virtual ~AbstractGridViewItem() = default;
virtual void build_grid_tile(uiLayout &layout) const = 0;
- /**
- * Compare this item's identifier to \a other to check if they represent the same data.
- * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
- * renaming, etc.).
- */
- bool matches(const AbstractGridViewItem &other) const;
-
const AbstractGridView &get_view() const;
- /**
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
- * can't be sure about the item state.
- */
- bool is_active() const;
-
protected:
AbstractGridViewItem(StringRef identifier);
+ /** See AbstractViewItem::matches(). */
+ virtual bool matches(const AbstractViewItem &other) const override;
+
/** Called when the item's state changes from inactive to active. */
virtual void on_activate();
/**
@@ -77,13 +64,6 @@ class AbstractGridViewItem {
virtual std::optional<bool> should_be_active() const;
/**
- * Copy persistent state (e.g. active, selection, etc.) from a matching item of
- * the last redraw to this item. If sub-classes introduce more advanced state they should
- * override this and make it update their state accordingly.
- */
- virtual void update_from_old(const AbstractGridViewItem &old);
-
- /**
* Activates this item, deactivates other items, and calls the
* #AbstractGridViewItem::on_activate() function.
* Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
@@ -111,7 +91,7 @@ struct GridViewStyle {
int tile_height = 0;
};
-class AbstractGridView {
+class AbstractGridView : public AbstractView {
friend class AbstractGridViewItem;
friend class GridViewBuilder;
friend class GridViewLayoutBuilder;
@@ -122,7 +102,6 @@ class AbstractGridView {
* #update_from_old(). */
Map<StringRef, AbstractGridViewItem *> item_map_;
GridViewStyle style_;
- bool is_reconstructed_ = false;
public:
AbstractGridView();
@@ -131,9 +110,6 @@ class AbstractGridView {
using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>;
void foreach_item(ItemIterFn iter_fn) const;
- /** Listen to a notifier, returning true if a redraw is needed. */
- virtual bool listen(const wmNotifier &) const;
-
/**
* Convenience wrapper constructing the item by forwarding given arguments to the constructor of
* the type (\a ItemT).
@@ -154,19 +130,8 @@ class AbstractGridView {
protected:
virtual void build_items() = 0;
- /**
- * Check if the view is fully (re-)constructed. That means, both #build_items() and
- * #update_from_old() have finished.
- */
- bool is_reconstructed() const;
-
private:
- /**
- * Match the grid-view against an earlier version of itself (if any) and copy the old UI state
- * (e.g. active, selected, renaming, etc.) to the new one. See
- * #AbstractGridViewItem.update_from_old().
- */
- void update_from_old(uiBlock &new_block);
+ void update_children_from_old(const AbstractView &old_view) override;
AbstractGridViewItem *find_matching_item(const AbstractGridViewItem &item_to_match,
const AbstractGridView &view_to_search_in) const;
/**
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index f1c0acf43f7..09057fd846e 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -652,7 +652,7 @@ DEF_ICON(PARTICLE_TIP)
DEF_ICON(PARTICLE_PATH)
/* EDITING */
-DEF_ICON_BLANK(669)
+DEF_ICON(SNAP_FACE_NEAREST)
DEF_ICON(SNAP_FACE_CENTER)
DEF_ICON(SNAP_PERPENDICULAR)
DEF_ICON(SNAP_MIDPOINT)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 984d3409554..bc4b484f777 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -72,14 +72,10 @@ typedef struct uiBut uiBut;
typedef struct uiButExtraOpIcon uiButExtraOpIcon;
typedef struct uiLayout uiLayout;
typedef struct uiPopupBlockHandle uiPopupBlockHandle;
-/* C handle for C++ #ui::AbstractTreeView type. */
-typedef struct uiTreeViewHandle uiTreeViewHandle;
-/* C handle for C++ #ui::AbstractTreeViewItem type. */
-typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
-/* C handle for C++ #ui::AbstractGridView type. */
-typedef struct uiGridViewHandle uiGridViewHandle;
-/* C handle for C++ #ui::AbstractGridViewItem type. */
-typedef struct uiGridViewItemHandle uiGridViewItemHandle;
+/* C handle for C++ #ui::AbstractView type. */
+typedef struct uiViewHandle uiViewHandle;
+/* C handle for C++ #ui::AbstractViewItem type. */
+typedef struct uiViewItemHandle uiViewItemHandle;
/* Defines */
@@ -89,7 +85,7 @@ typedef struct uiGridViewItemHandle uiGridViewItemHandle;
/* Separator for text in search menus (right pointing arrow).
* keep in sync with `string_search.cc`. */
-#define UI_MENU_ARROW_SEP "\xe2\x96\xb6"
+#define UI_MENU_ARROW_SEP "\xe2\x96\xb8"
/* names */
#define UI_MAX_DRAW_STR 400
@@ -358,7 +354,7 @@ typedef enum {
UI_BTYPE_LABEL = 20 << 9,
UI_BTYPE_KEY_EVENT = 24 << 9,
UI_BTYPE_HSVCUBE = 26 << 9,
- /** menu (often used in headers), **_MENU /w different draw-type */
+ /** Menu (often used in headers), `*_MENU` with different draw-type. */
UI_BTYPE_PULLDOWN = 27 << 9,
UI_BTYPE_ROUNDBOX = 28 << 9,
UI_BTYPE_COLORBAND = 30 << 9,
@@ -393,10 +389,8 @@ typedef enum {
/** Resize handle (resize uilist). */
UI_BTYPE_GRIP = 57 << 9,
UI_BTYPE_DECORATOR = 58 << 9,
- /* An item in a tree view. Parent items may be collapsible. */
- UI_BTYPE_TREEROW = 59 << 9,
- /* An item in a grid view. */
- UI_BTYPE_GRID_TILE = 60 << 9,
+ /* An item a view (see #ui::AbstractViewItem). */
+ UI_BTYPE_VIEW_ITEM = 59 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -1687,8 +1681,6 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name);
*/
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
-void UI_but_treerow_indentation_set(uiBut *but, int indentation);
-
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
void UI_but_number_step_size_set(uiBut *but, float step_size);
@@ -2491,7 +2483,7 @@ enum uiTemplateListFlags {
ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST);
void uiTemplateList(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
@@ -2505,7 +2497,7 @@ void uiTemplateList(uiLayout *layout,
int columns,
enum uiTemplateListFlags flags);
struct uiList *uiTemplateList_ex(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
@@ -2575,7 +2567,7 @@ enum {
UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY = (1 << 2),
};
void uiTemplateAssetView(struct uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
const char *list_id,
struct PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
@@ -3204,54 +3196,44 @@ void UI_interface_tag_script_reload(void);
void UI_block_views_listen(const uiBlock *block,
const struct wmRegionListenerParams *listener_params);
-bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle);
-bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
-bool UI_grid_view_item_matches(const uiGridViewItemHandle *a, const uiGridViewItemHandle *b);
-bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
-/**
- * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
- * support dragging, i.e. it won't create a drag-controller upon request.
- * \return True if dragging started successfully, otherwise false.
- */
-bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
-bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
- const struct wmDrag *drag,
- const char **r_disabled_hint);
-char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item, const struct wmDrag *drag);
-/**
- * Let a tree-view item handle a drop event.
- * \return True if the drop was handled by the tree-view item.
- */
-bool UI_tree_view_item_drop_handle(struct bContext *C,
- const uiTreeViewItemHandle *item_,
- const struct ListBase *drags);
+bool UI_view_item_is_active(const uiViewItemHandle *item_handle);
+bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle);
/**
- * Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
- * #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
+ * Can \a item_handle be renamed right now? Note that this isn't just a mere wrapper around
+ * #AbstractViewItem::supports_renaming(). This also checks if there is another item being renamed,
* and returns false if so.
*/
-bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
-void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
+bool UI_view_item_can_rename(const uiViewItemHandle *item_handle);
+void UI_view_item_begin_rename(uiViewItemHandle *item_handle);
-void UI_tree_view_item_context_menu_build(struct bContext *C,
- const uiTreeViewItemHandle *item,
- uiLayout *column);
+void UI_view_item_context_menu_build(struct bContext *C,
+ const uiViewItemHandle *item_handle,
+ uiLayout *column);
/**
- * \param xy: Coordinate to find a tree-row item at, in window space.
+ * Attempt to start dragging \a item_. This will not work if the view item doesn't
+ * support dragging, i.e. if it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
*/
-uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region,
- const int xy[2]) ATTR_NONNULL(1, 2);
-uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
-
+bool UI_view_item_drag_start(struct bContext *C, const uiViewItemHandle *item_);
+bool UI_view_item_can_drop(const uiViewItemHandle *item_,
+ const struct wmDrag *drag,
+ const char **r_disabled_hint);
+char *UI_view_item_drop_tooltip(const uiViewItemHandle *item, const struct wmDrag *drag);
/**
- * Listen to \a notifier, returning true if the region should redraw.
+ * Let a view item handle a drop event.
+ * \return True if the drop was handled by the view item.
*/
-bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view, const wmNotifier *notifier);
+bool UI_view_item_drop_handle(struct bContext *C,
+ const uiViewItemHandle *item_,
+ const struct ListBase *drags);
+
/**
- * Listen to \a notifier, returning true if the region should redraw.
+ * \param xy: Coordinate to find a view item at, in window space.
*/
-bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view, const wmNotifier *notifier);
+uiViewItemHandle *UI_region_views_find_item_at(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL();
+uiViewItemHandle *UI_region_views_find_active_item(const struct ARegion *region);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index 3dc56b01993..82bfdd7e212 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -46,7 +46,7 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path);
void attribute_search_add_items(
StringRefNull str,
- bool is_output,
+ bool can_create_attribute,
Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos,
uiSearchItems *items,
bool is_first);
@@ -54,12 +54,12 @@ void attribute_search_add_items(
} // namespace blender::ui
/**
- * Override this for all available tree types.
+ * Override this for all available view types.
*/
blender::ui::AbstractGridView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
- std::unique_ptr<blender::ui::AbstractGridView> tree_view);
+ std::unique_ptr<blender::ui::AbstractGridView> grid_view);
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 22e747e37ad..9a46728097c 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -291,6 +291,8 @@ typedef enum ThemeColorID {
TH_WIDGET_EMBOSS,
TH_WIDGET_TEXT_CURSOR,
+ TH_WIDGET_TEXT_SELECTION,
+ TH_WIDGET_TEXT_HIGHLIGHT,
TH_EDITOR_OUTLINE,
TH_TRANSPARENT_CHECKER_PRIMARY,
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 1aeb13ca5cc..872a6085060 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -9,7 +9,6 @@
#pragma once
-#include <array>
#include <functional>
#include <memory>
#include <string>
@@ -19,23 +18,19 @@
#include "BLI_function_ref.hh"
#include "BLI_vector.hh"
+#include "UI_abstract_view.hh"
#include "UI_resources.h"
struct bContext;
struct uiBlock;
struct uiBut;
-struct uiButTreeRow;
+struct uiButViewItem;
struct uiLayout;
-struct wmDrag;
-struct wmEvent;
-struct wmNotifier;
namespace blender::ui {
class AbstractTreeView;
class AbstractTreeViewItem;
-class AbstractTreeViewItemDropController;
-class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
@@ -112,45 +107,20 @@ using TreeViewOrItem = TreeViewItemContainer;
/** \name Tree-View Base Class
* \{ */
-class AbstractTreeView : public TreeViewItemContainer {
+class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
friend class AbstractTreeViewItem;
friend class TreeViewBuilder;
- /**
- * Only one item can be renamed at a time. So the tree is informed about the renaming state to
- * enforce that.
- */
- std::unique_ptr<std::array<char, MAX_NAME>> rename_buffer_;
-
- bool is_reconstructed_ = false;
-
public:
virtual ~AbstractTreeView() = default;
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
- /** Listen to a notifier, returning true if a redraw is needed. */
- virtual bool listen(const wmNotifier &) const;
-
- /** Only one item can be renamed at a time. */
- bool is_renaming() const;
-
protected:
virtual void build_tree() = 0;
- /**
- * Check if the tree is fully (re-)constructed. That means, both #build_tree() and
- * #update_from_old() have finished.
- */
- bool is_reconstructed() const;
-
private:
- /**
- * Match the tree-view against an earlier version of itself (if any) and copy the old UI state
- * (e.g. collapsed, active, selected, renaming, etc.) to the new one. See
- * #AbstractTreeViewItem.update_from_old().
- */
- void update_from_old(uiBlock &new_block);
+ void update_children_from_old(const AbstractView &old_view) override;
static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
const TreeViewOrItem &old_items);
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
@@ -177,7 +147,7 @@ class AbstractTreeView : public TreeViewItemContainer {
* It also stores state information that needs to be persistent over redraws, like the collapsed
* state.
*/
-class AbstractTreeViewItem : public TreeViewItemContainer {
+class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContainer {
friend class AbstractTreeView;
friend class TreeViewLayoutBuilder;
/* Higher-level API. */
@@ -185,20 +155,17 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
private:
bool is_open_ = false;
- bool is_active_ = false;
- bool is_renaming_ = false;
protected:
/** This label is used as the default way to identifying an item within its parent. */
std::string label_{};
- /** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
- uiButTreeRow *tree_row_but_ = nullptr;
+ /** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
+ uiButViewItem *view_item_but_ = nullptr;
public:
virtual ~AbstractTreeViewItem() = default;
virtual void build_row(uiLayout &row) = 0;
- virtual void build_context_menu(bContext &C, uiLayout &column) const;
AbstractTreeView &get_tree_view() const;
@@ -210,11 +177,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* can't be sure about the item state.
*/
bool is_collapsed() const;
- /**
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
- * can't be sure about the item state.
- */
- bool is_active() const;
protected:
/**
@@ -227,31 +189,21 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
virtual std::optional<bool> should_be_active() const;
- /**
- * Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
- * another item is already being renamed.
- */
- virtual bool supports_renaming() const;
- /**
- * Try renaming the item, or the data it represents. Can assume
- * #AbstractTreeViewItem::supports_renaming() returned true. Sub-classes that override this
- * should usually call this, unless they have a custom #AbstractTreeViewItem.matches().
- *
- * \return True if the renaming was successful.
- */
- virtual bool rename(StringRefNull new_name);
+ /** See AbstractViewItem::get_rename_string(). */
+ virtual StringRef get_rename_string() const override;
+ /** See AbstractViewItem::rename(). */
+ virtual bool rename(StringRefNull new_name) override;
/**
* Return whether the item can be collapsed. Used to disable collapsing for items with children.
*/
virtual bool supports_collapsing() const;
- /**
- * Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of
- * the last redraw to this item. If sub-classes introduce more advanced state they should
- * override this and make it update their state accordingly.
- */
- virtual void update_from_old(const AbstractTreeViewItem &old);
+ /** See #AbstractViewItem::matches(). */
+ virtual bool matches(const AbstractViewItem &other) const override;
+
+ /** See #AbstractViewItem::update_from_old(). */
+ virtual void update_from_old(const AbstractViewItem &old) override;
/**
* Compare this item to \a other to check if they represent the same data.
@@ -259,22 +211,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* open/closed, active, etc.). Items are only matched if their parents also match.
* By default this just matches the item's label (if the parents match!). If that isn't
* good enough for a sub-class, that can override it.
- */
- virtual bool matches(const AbstractTreeViewItem &other) const;
-
- /**
- * If an item wants to support being dragged, it has to return a drag controller here.
- * That is an object implementing #AbstractTreeViewItemDragController.
- */
- virtual std::unique_ptr<AbstractTreeViewItemDragController> create_drag_controller() const;
- /**
- * If an item wants to support dropping data into it, it has to return a drop controller here.
- * That is an object implementing #AbstractTreeViewItemDropController.
*
- * \note This drop controller may be requested for each event. The tree-view doesn't keep a drop
- * controller around currently. So it can not contain persistent state.
+ * TODO #matches_single() is a rather temporary name, used to indicate that this only compares
+ * the item itself, not the parents. Item matching is expected to change quite a bit anyway.
*/
- virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
+ virtual bool matches_single(const AbstractTreeViewItem &other) const;
/**
* Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
@@ -292,29 +233,24 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
bool is_hovered() const;
bool is_collapsible() const;
- bool is_renaming() const;
void ensure_parents_uncollapsed();
- uiButTreeRow *tree_row_button();
+ uiButViewItem *view_item_button();
private:
- static void rename_button_fn(bContext *, void *, char *);
- static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but);
static void tree_row_click_fn(struct bContext *, void *, void *);
static void collapse_chevron_click_fn(bContext *, void *but_arg1, void *);
static bool is_collapse_chevron_but(const uiBut *but);
/** See #AbstractTreeView::change_state_delayed() */
void change_state_delayed();
- void end_renaming();
void add_treerow_button(uiBlock &block);
void add_indent(uiLayout &row) const;
void add_collapse_chevron(uiBlock &block) const;
void add_rename_button(uiLayout &row);
- bool matches_including_parents(const AbstractTreeViewItem &other) const;
bool has_active_child() const;
int count_parents() const;
};
@@ -322,69 +258,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Drag 'n Drop
- * \{ */
-
-/**
- * Class to enable dragging a tree-item. An item can return a drop controller for itself via a
- * custom implementation of #AbstractTreeViewItem::create_drag_controller().
- */
-class AbstractTreeViewItemDragController {
- protected:
- AbstractTreeView &tree_view_;
-
- public:
- AbstractTreeViewItemDragController(AbstractTreeView &tree_view);
- virtual ~AbstractTreeViewItemDragController() = default;
-
- virtual int get_drag_type() const = 0;
- virtual void *create_drag_data() const = 0;
- virtual void on_drag_start();
-
- template<class TreeViewType> inline TreeViewType &tree_view() const;
-};
-
-/**
- * Class to customize the drop behavior of a tree-item, plus the behavior when dragging over this
- * item. An item can return a drop controller for itself via a custom implementation of
- * #AbstractTreeViewItem::create_drop_controller().
- */
-class AbstractTreeViewItemDropController {
- protected:
- AbstractTreeView &tree_view_;
-
- public:
- AbstractTreeViewItemDropController(AbstractTreeView &tree_view);
- virtual ~AbstractTreeViewItemDropController() = default;
-
- /**
- * Check if the data dragged with \a drag can be dropped on the item this controller is for.
- * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
- * isn't possible on this item. Shouldn't be done too aggressively, e.g.
- * don't set this if the drag-type can't be dropped here; only if it can
- * but there's another reason it can't be dropped.
- * Can assume this is a non-null pointer.
- */
- virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
- /**
- * Custom text to display when dragging over a tree item. Should explain what happens when
- * dropping the data onto this item. Will only be used if #AbstractTreeViewItem::can_drop()
- * returns true, so the implementing override doesn't have to check that again.
- * The returned value must be a translated string.
- */
- virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
- /**
- * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
- * controller is for.
- */
- virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
-
- template<class TreeViewType> inline TreeViewType &tree_view() const;
-};
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
/** \name Predefined Tree-View Item Types
*
* Common, Basic Tree-View Item Types.
@@ -455,18 +328,4 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
}
-template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const
-{
- static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
- "Type must derive from and implement the AbstractTreeView interface");
- return static_cast<TreeViewType &>(tree_view_);
-}
-
-template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const
-{
- static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
- "Type must derive from and implement the AbstractTreeView interface");
- return static_cast<TreeViewType &>(tree_view_);
-}
-
} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 23dbd3ed36f..e508c96b4f1 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -49,8 +49,21 @@ enum eView2D_CommonViewTypes {
/* ------ Defines for Scrollers ----- */
/** Scroll bar area. */
-#define V2D_SCROLL_HEIGHT (0.45f * U.widget_unit)
-#define V2D_SCROLL_WIDTH (0.45f * U.widget_unit)
+
+/* Maximum has to include outline which varies with line width. */
+#define V2D_SCROLL_HEIGHT ((0.45f * U.widget_unit) + (2.0f * U.pixelsize))
+#define V2D_SCROLL_WIDTH ((0.45f * U.widget_unit) + (2.0f * U.pixelsize))
+
+/* Alpha of scrollbar when at minimum size. */
+#define V2D_SCROLL_MIN_ALPHA (0.4f)
+
+/* Minimum size needs to include outline which varies with line width. */
+#define V2D_SCROLL_MIN_WIDTH ((5.0f * U.dpi_fac) + (2.0f * U.pixelsize))
+
+/* When to start showing the full-width scroller. */
+#define V2D_SCROLL_HIDE_WIDTH (AREAMINX * U.dpi_fac)
+#define V2D_SCROLL_HIDE_HEIGHT (HEADERY * U.dpi_fac)
+
/** Scroll bars with 'handles' used for scale (zoom). */
#define V2D_SCROLL_HANDLE_HEIGHT (0.6f * U.widget_unit)
#define V2D_SCROLL_HANDLE_WIDTH (0.6f * U.widget_unit)
@@ -236,9 +249,13 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *region,
void UI_view2d_scrollers_calc(struct View2D *v2d,
const struct rcti *mask_custom,
struct View2DScrollers *r_scrollers);
+
/**
* Draw scroll-bars in the given 2D-region.
*/
+void UI_view2d_scrollers_draw_ex(struct View2D *v2d,
+ const struct rcti *mask_custom,
+ bool use_full_hide);
void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom);
/* List view tools. */
@@ -292,6 +309,12 @@ float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
bool UI_view2d_view_to_region_clip(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+bool UI_view2d_view_to_region_segment_clip(const View2D *v2d,
+ const float xy_a[2],
+ const float xy_b[2],
+ int r_region_a[2],
+ int r_region_b[2]) ATTR_NONNULL();
+
/**
* Convert from 2d-view space to screen/region space
*
@@ -329,8 +352,10 @@ struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
/**
* Get scrollbar sizes of the current 2D view.
* The size will be zero if the view has its scrollbars disabled.
+ *
+ * \param mapped: whether to use view2d_scroll_mapped which changes flags
*/
-void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_scroller_size_get(const struct View2D *v2d, bool mapped, float *r_x, float *r_y);
/**
* Calculate the scale per-axis of the drawing-area
*
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index a140ee27d3c..d9aabb12ad3 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
+ .
../include
../../blenfont
../../blenkernel
@@ -18,36 +19,35 @@ set(INC
../../python
../../render
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
+ ../../bmesh
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
set(SRC
- grid_view.cc
+ eyedroppers/eyedropper_color.c
+ eyedroppers/eyedropper_colorband.c
+ eyedroppers/eyedropper_datablock.c
+ eyedroppers/eyedropper_depth.c
+ eyedroppers/eyedropper_driver.c
+ eyedroppers/eyedropper_gpencil_color.c
+ eyedroppers/interface_eyedropper.c
interface.cc
interface_align.c
- interface_anim.c
+ interface_anim.cc
interface_button_group.c
interface_context_menu.c
interface_context_path.cc
interface_drag.cc
interface_draw.c
interface_dropboxes.cc
- interface_eyedropper.c
- interface_eyedropper_color.c
- interface_eyedropper_colorband.c
- interface_eyedropper_datablock.c
- interface_eyedropper_depth.c
- interface_eyedropper_driver.c
- interface_eyedropper_gpencil_color.c
interface_handlers.c
interface_icons.c
interface_icons_event.c
interface_layout.c
- interface_ops.c
- interface_panel.c
+ interface_ops.cc
+ interface_panel.cc
interface_query.cc
interface_region_color_picker.cc
interface_region_hud.cc
@@ -56,30 +56,33 @@ set(SRC
interface_region_popover.cc
interface_region_popup.cc
interface_region_search.cc
- interface_region_tooltip.c
+ interface_region_tooltip.cc
interface_regions.cc
interface_style.cc
interface_template_asset_view.cc
interface_template_attribute_search.cc
interface_template_list.cc
interface_template_search_menu.cc
- interface_template_search_operator.c
+ interface_template_search_operator.cc
interface_templates.c
- interface_undo.c
+ interface_undo.cc
interface_utils.cc
- interface_view.cc
interface_widgets.c
resources.c
- tree_view.cc
view2d.cc
view2d_draw.cc
view2d_edge_pan.cc
view2d_gizmo_navigate.cc
view2d_ops.cc
+ views/abstract_view.cc
+ views/abstract_view_item.cc
+ views/grid_view.cc
+ views/interface_view.cc
+ views/tree_view.cc
- interface_eyedropper_intern.h
+ eyedroppers/eyedropper_intern.h
interface_intern.h
- interface_regions_intern.h
+ interface_regions_intern.hh
)
set(LIB
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/eyedroppers/eyedropper_color.c
index c015a60de89..9c430afd5f0 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_color.c
@@ -50,7 +50,7 @@
#include "RE_pipeline.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
typedef struct Eyedropper {
struct ColorManagedDisplay *display;
@@ -479,7 +479,7 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
}
- else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ else if (ISMOUSE_MOTION(event->type)) {
if (eye->accum_start) {
/* button is pressed so keep sampling */
eyedropper_color_sample(C, eye, event->xy);
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c
index a69c36fefbd..3f63a8020ed 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c
@@ -35,7 +35,7 @@
#include "interface_intern.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
typedef struct Colorband_RNAUpdateCb {
PointerRNA ptr;
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/eyedroppers/eyedropper_datablock.c
index 01b958576b6..1710d0faa4d 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_datablock.c
@@ -38,7 +38,7 @@
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
/**
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
index 3c6f127582a..3fb5a74944b 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
@@ -38,7 +38,7 @@
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
/**
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
index 0cacb55c60c..0f3062c3f61 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
@@ -24,6 +24,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "UI_interface.h"
@@ -32,7 +33,7 @@
#include "ED_keyframing.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
typedef struct DriverDropper {
@@ -83,14 +84,14 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve
if (but == NULL) {
return;
}
- /* Get paths for src... */
+ /* Get paths for the source. */
PointerRNA *target_ptr = &but->rnapoin;
PropertyRNA *target_prop = but->rnaprop;
const int target_index = but->rnaindex;
char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
- /* ... and destination */
+ /* Get paths for the destination. */
char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop);
/* Now create driver(s) */
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.c
index f3c70e6a96a..c3879fe8bbd 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.c
@@ -46,7 +46,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
typedef struct EyedropperGPencil {
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/eyedroppers/eyedropper_intern.h
index 76316a85807..946f2145d1d 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_intern.h
@@ -3,7 +3,7 @@
/** \file
* \ingroup edinterface
*
- * Share between interface_eyedropper_*.c files.
+ * Share between `interface/eyedropper/` files.
*/
#pragma once
@@ -35,7 +35,7 @@ void datadropper_win_area_find(const struct bContext *C,
*
* Special check for image or nodes where we MAY have HDR pixels which don't display.
*
- * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
+ * \note Exposed by 'eyedropper_intern.h' for use with color band picking.
*/
void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/eyedroppers/interface_eyedropper.c
index eaec1e249b7..c6fb8f0ab68 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/eyedroppers/interface_eyedropper.c
@@ -21,7 +21,7 @@
#include "interface_intern.h"
-#include "interface_eyedropper_intern.h" /* own include */
+#include "eyedropper_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/* Keymap
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index 3f623566807..ca4918b2e8d 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -153,8 +153,8 @@ void ui_block_to_window(const ARegion *region, uiBlock *block, int *r_x, int *r_
ui_block_to_window_fl(region, block, &fx, &fy);
- *r_x = (int)(fx + 0.5f);
- *r_y = (int)(fy + 0.5f);
+ *r_x = (int)lround(fx);
+ *r_y = (int)lround(fy);
}
void ui_block_to_region_rctf(const ARegion *region,
@@ -232,8 +232,8 @@ void ui_window_to_block(const ARegion *region, uiBlock *block, int *r_x, int *r_
ui_window_to_block_fl(region, block, &fx, &fy);
- *r_x = (int)(fx + 0.5f);
- *r_y = (int)(fy + 0.5f);
+ *r_x = (int)lround(fx);
+ *r_y = (int)lround(fy);
}
void ui_window_to_region(const ARegion *region, int *r_x, int *r_y)
@@ -769,20 +769,11 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
return false;
}
- if ((but->type == UI_BTYPE_TREEROW) && (oldbut->type == UI_BTYPE_TREEROW)) {
- uiButTreeRow *but_treerow = (uiButTreeRow *)but;
- uiButTreeRow *oldbut_treerow = (uiButTreeRow *)oldbut;
- if (!but_treerow->tree_item || !oldbut_treerow->tree_item ||
- !UI_tree_view_item_matches(but_treerow->tree_item, oldbut_treerow->tree_item)) {
- return false;
- }
- }
-
- if ((but->type == UI_BTYPE_GRID_TILE) && (oldbut->type == UI_BTYPE_GRID_TILE)) {
- uiButGridTile *but_gridtile = (uiButGridTile *)but;
- uiButGridTile *oldbut_gridtile = (uiButGridTile *)oldbut;
- if (!but_gridtile->view_item || !oldbut_gridtile->view_item ||
- !UI_grid_view_item_matches(but_gridtile->view_item, oldbut_gridtile->view_item)) {
+ if ((but->type == UI_BTYPE_VIEW_ITEM) && (oldbut->type == UI_BTYPE_VIEW_ITEM)) {
+ uiButViewItem *but_item = (uiButViewItem *)but;
+ uiButViewItem *oldbut_item = (uiButViewItem *)oldbut;
+ if (!but_item->view_item || !oldbut_item->view_item ||
+ !UI_view_item_matches(but_item->view_item, oldbut_item->view_item)) {
return false;
}
}
@@ -907,16 +898,10 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
progress_oldbut->progress = progress_but->progress;
break;
}
- case UI_BTYPE_TREEROW: {
- uiButTreeRow *treerow_oldbut = (uiButTreeRow *)oldbut;
- uiButTreeRow *treerow_newbut = (uiButTreeRow *)but;
- SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item);
- break;
- }
- case UI_BTYPE_GRID_TILE: {
- uiButGridTile *gridtile_oldbut = (uiButGridTile *)oldbut;
- uiButGridTile *gridtile_newbut = (uiButGridTile *)but;
- SWAP(uiGridViewItemHandle *, gridtile_newbut->view_item, gridtile_oldbut->view_item);
+ case UI_BTYPE_VIEW_ITEM: {
+ uiButViewItem *view_item_oldbut = (uiButViewItem *)oldbut;
+ uiButViewItem *view_item_newbut = (uiButViewItem *)but;
+ SWAP(uiViewItemHandle *, view_item_newbut->view_item, view_item_oldbut->view_item);
break;
}
default:
@@ -1013,7 +998,7 @@ static bool ui_but_update_from_old_block(const bContext *C,
/* Stupid special case: The active button may be inside (as in, overlapped on top) a view-item
* button which we also want to keep highlighted then. */
- if (ui_but_is_view_item(but)) {
+ if (but->type == UI_BTYPE_VIEW_ITEM) {
flag_copy |= UI_ACTIVE;
}
@@ -1325,7 +1310,7 @@ static bool ui_but_event_operator_string_from_panel(const bContext *C,
IDP_AddToGroup(prop_panel, IDP_New(IDP_INT, &region_type_val, "region_type"));
for (int i = 0; i < 2; i++) {
- /* FIXME(campbell): We can't reasonably search all configurations - long term. */
+ /* FIXME(@campbellbarton): We can't reasonably search all configurations - long term. */
IDPropertyTemplate val = {0};
val.i = i;
@@ -2245,21 +2230,12 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
}
}
break;
- case UI_BTYPE_TREEROW: {
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+ case UI_BTYPE_VIEW_ITEM: {
+ const uiButViewItem *view_item_but = (const uiButViewItem *)but;
is_push = -1;
- if (tree_row_but->tree_item) {
- is_push = UI_tree_view_item_is_active(tree_row_but->tree_item);
- }
- break;
- }
- case UI_BTYPE_GRID_TILE: {
- uiButGridTile *grid_tile_but = (uiButGridTile *)but;
-
- is_push = -1;
- if (grid_tile_but->view_item) {
- is_push = UI_grid_view_item_is_active(grid_tile_but->view_item);
+ if (view_item_but->view_item) {
+ is_push = UI_view_item_is_active(view_item_but->view_item);
}
break;
}
@@ -2387,9 +2363,9 @@ void ui_but_v3_set(uiBut *but, const float vec[3])
}
else if (but->pointype == UI_BUT_POIN_CHAR) {
char *cp = (char *)but->poin;
- cp[0] = (char)(0.5f + vec[0] * 255.0f);
- cp[1] = (char)(0.5f + vec[1] * 255.0f);
- cp[2] = (char)(0.5f + vec[2] * 255.0f);
+ cp[0] = (char)lround(vec[0] * 255.0f);
+ cp[1] = (char)lround(vec[1] * 255.0f);
+ cp[2] = (char)lround(vec[2] * 255.0f);
}
else if (but->pointype == UI_BUT_POIN_FLOAT) {
float *fp = (float *)but->poin;
@@ -4011,17 +3987,13 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButCurveProfile);
alloc_str = "uiButCurveProfile";
break;
- case UI_BTYPE_TREEROW:
- alloc_size = sizeof(uiButTreeRow);
- alloc_str = "uiButTreeRow";
- break;
case UI_BTYPE_HOTKEY_EVENT:
alloc_size = sizeof(uiButHotkeyEvent);
alloc_str = "uiButHotkeyEvent";
break;
- case UI_BTYPE_GRID_TILE:
- alloc_size = sizeof(uiButGridTile);
- alloc_str = "uiButGridTile";
+ case UI_BTYPE_VIEW_ITEM:
+ alloc_size = sizeof(uiButViewItem);
+ alloc_str = "uiButViewItem";
break;
default:
alloc_size = sizeof(uiBut);
@@ -4214,7 +4186,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_TREEROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -6469,15 +6440,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
-void UI_but_treerow_indentation_set(uiBut *but, int indentation)
-{
- uiButTreeRow *but_row = (uiButTreeRow *)but;
- BLI_assert(but->type == UI_BTYPE_TREEROW);
-
- but_row->indentation = indentation;
- BLI_assert(indentation >= 0);
-}
-
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
{
ui_but_add_shortcut(but, string, false);
@@ -6623,7 +6585,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
MenuType *mt = UI_but_menutype_get(but);
if (mt) {
if (type == BUT_GET_RNA_LABEL) {
- tmp = BLI_strdup(mt->label);
+ tmp = BLI_strdup(CTX_TIP_(mt->translation_context, mt->label));
}
else {
/* Not all menus are from Python. */
@@ -6653,7 +6615,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
PanelType *pt = UI_but_paneltype_get(but);
if (pt) {
if (type == BUT_GET_RNA_LABEL) {
- tmp = BLI_strdup(pt->label);
+ tmp = BLI_strdup(CTX_TIP_(pt->translation_context, pt->label));
}
else {
/* Not all panels are from Python. */
@@ -6792,10 +6754,11 @@ void UI_but_extra_icon_string_info_get(struct bContext *C, uiButExtraOpIcon *ext
if (ui_but_extra_icon_event_operator_string(C, extra_icon, buf, sizeof(buf))) {
tmp = BLI_strdup(buf);
}
+ break;
}
+ default:
/* Other types not supported. The caller should expect that outcome, no need to message or
* assert here. */
- default:
break;
}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.cc
index 0e69b4bb358..4da6cefd8de 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.cc
@@ -4,9 +4,9 @@
* \ingroup edinterface
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -35,6 +35,7 @@
#include "UI_interface.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -48,8 +49,14 @@ static FCurve *ui_but_get_fcurve(
* but works well enough in typical cases */
const int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return BKE_fcurve_find_by_rna_context_ui(
- but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
+ return BKE_fcurve_find_by_rna_context_ui(static_cast<bContext *>(but->block->evil_C),
+ &but->rnapoin,
+ but->rnaprop,
+ rnaindex,
+ adt,
+ action,
+ r_driven,
+ r_special);
}
void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
@@ -92,7 +99,7 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
}
/* XXX: this feature is totally broken and useless with NLA */
- if (adt == NULL || adt->nla_tracks.first == NULL) {
+ if (adt == nullptr || adt->nla_tracks.first == nullptr) {
const AnimationEvalContext remapped_context = BKE_animsys_eval_context_construct_at(
anim_eval_context, cfra);
if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, &remapped_context)) {
@@ -108,13 +115,13 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_decorate)
{
- uiBut *but_iter = NULL;
+ uiBut *but_iter = nullptr;
BLI_assert(UI_but_is_decorator(&but_decorate->but));
BLI_assert(but_decorate->rnapoin.data && but_decorate->rnaprop);
LISTBASE_CIRCULAR_BACKWARD_BEGIN (
- &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) {
+ uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) {
if (but_iter != (uiBut *)but_decorate &&
ui_but_rna_equals_ex(
but_iter, &but_decorate->rnapoin, but_decorate->rnaprop, but_decorate->rnaindex)) {
@@ -122,9 +129,9 @@ static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_deco
}
}
LISTBASE_CIRCULAR_BACKWARD_END(
- &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev);
+ uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev);
- return NULL;
+ return nullptr;
}
void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
@@ -172,7 +179,7 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
ChannelDriver *driver;
bool driven, special;
- fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
+ fcu = ui_but_get_fcurve(but, nullptr, nullptr, &driven, &special);
if (fcu && driven) {
driver = fcu->driver;
@@ -194,13 +201,13 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
ChannelDriver *driver;
bool driven, special;
- fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
+ fcu = ui_but_get_fcurve(but, nullptr, nullptr, &driven, &special);
if (fcu && driven) {
driver = fcu->driver;
if (driver && (driver->type == DRIVER_TYPE_PYTHON)) {
- bContext *C = but->block->evil_C;
+ bContext *C = static_cast<bContext *>(but->block->evil_C);
BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
@@ -212,7 +219,7 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
fcu->flag &= ~FCURVE_DISABLED;
/* this notifier should update the Graph Editor and trigger depsgraph refresh? */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, nullptr);
DEG_relations_tag_update(CTX_data_main(C));
@@ -225,14 +232,14 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
bool ui_but_anim_expression_create(uiBut *but, const char *str)
{
- bContext *C = but->block->evil_C;
+ bContext *C = static_cast<bContext *>(but->block->evil_C);
ID *id;
FCurve *fcu;
char *path;
bool ok = false;
/* button must have RNA-pointer to a numeric-capable property */
- if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
+ if (ELEM(nullptr, but->rnapoin.data, but->rnaprop)) {
if (G.debug & G_DEBUG) {
printf("ERROR: create expression failed - button has no RNA info attached\n");
}
@@ -252,7 +259,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* FIXME: until materials can be handled by depsgraph,
* don't allow drivers to be created for them */
id = but->rnapoin.owner_id;
- if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
+ if ((id == nullptr) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
if (G.debug & G_DEBUG) {
printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id);
}
@@ -261,7 +268,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* get path */
path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
- if (path == NULL) {
+ if (path == nullptr) {
return false;
}
@@ -281,7 +288,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* updates */
BKE_driver_invalidate_expression(driver, true, false);
DEG_relations_tag_update(CTX_data_main(C));
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, nullptr);
ok = true;
}
}
@@ -299,26 +306,26 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
void ui_but_anim_copy_driver(bContext *C)
{
/* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL);
+ WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
}
void ui_but_anim_paste_driver(bContext *C)
{
/* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL);
+ WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
}
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
{
wmWindowManager *wm = CTX_wm_manager(C);
- uiButDecorator *but_decorate = arg_but;
+ uiButDecorator *but_decorate = static_cast<uiButDecorator *>(arg_but);
uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate);
if (!but_anim) {
return;
}
- /* FIXME(campbell), swapping active pointer is weak. */
+ /* FIXME(@campbellbarton): swapping active pointer is weak. */
SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->but.active);
wm->op_undo_depth++;
@@ -331,7 +338,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
WM_operator_properties_free(&props_ptr);
}
else {
@@ -339,7 +346,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
WM_operator_properties_free(&props_ptr);
}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index e58298cdaee..7ed9488950e 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -927,11 +927,11 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
{
const ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
- uiButTreeRow *treerow_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, event->xy);
- if (treerow_but) {
- BLI_assert(treerow_but->but.type == UI_BTYPE_TREEROW);
- UI_tree_view_item_context_menu_build(
- C, treerow_but->tree_item, uiLayoutColumn(layout, false));
+ uiButViewItem *view_item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region,
+ event->xy);
+ if (view_item_but) {
+ BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM);
+ UI_view_item_context_menu_build(C, view_item_but->view_item, uiLayoutColumn(layout, false));
uiItemS(layout);
}
}
@@ -952,6 +952,12 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
uiItemS(layout);
}
+ MenuType *mt_idtemplate_liboverride = WM_menutype_find("UI_MT_idtemplate_liboverride", true);
+ if (mt_idtemplate_liboverride && mt_idtemplate_liboverride->poll(C, mt_idtemplate_liboverride)) {
+ uiItemM_ptr(layout, mt_idtemplate_liboverride, IFACE_("Library Override"), ICON_NONE);
+ uiItemS(layout);
+ }
+
/* Pointer properties and string properties with
* prop_search support jumping to target object/bone. */
if (but->rnapoin.data && but->rnaprop) {
@@ -1224,7 +1230,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
}
}
- MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
+ MenuType *mt = WM_menutype_find("UI_MT_button_context_menu", true);
if (mt) {
UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
}
diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc
index 4c68870b2c7..0c7c3a238ec 100644
--- a/source/blender/editors/interface/interface_drag.cc
+++ b/source/blender/editors/interface/interface_drag.cc
@@ -122,7 +122,7 @@ bool ui_but_drag_is_draggable(const uiBut *but)
void ui_but_drag_start(bContext *C, uiBut *but)
{
- wmDrag *drag = WM_event_start_drag(C,
+ wmDrag *drag = WM_drag_data_create(C,
but->icon,
but->dragtype,
but->dragpoin,
@@ -130,15 +130,17 @@ void ui_but_drag_start(bContext *C, uiBut *but)
(but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA :
WM_DRAG_NOP);
/* wmDrag has ownership over dragpoin now, stop messing with it. */
- but->dragpoin = NULL;
+ but->dragpoin = nullptr;
if (but->imb) {
WM_event_drag_image(drag, but->imb, but->imb_scale);
}
+ WM_event_start_prepared_drag(C, drag);
+
/* Special feature for assets: We add another drag item that supports multiple assets. It
* gets the assets from context. */
if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
- WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP);
+ WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, nullptr, 0, WM_DRAG_NOP);
}
}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index d201820fbb6..190830568e3 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -171,7 +171,7 @@ void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const flo
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
immRecti(pos, pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
@@ -205,7 +205,7 @@ void ui_draw_but_TAB_outline(const rcti *rect,
mul_v2_fl(vec[a], rad);
}
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
immBeginAtMost(GPU_PRIM_LINE_STRIP, 25);
immAttr3ubv(col, highlight);
@@ -309,7 +309,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
rgba_uchar_to_float(col, but->col);
}
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexTiled(&state,
(float)rect->xmin,
(float)rect->ymin,
@@ -490,7 +490,7 @@ void ui_draw_but_HISTOGRAM(ARegion *UNUSED(region),
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
/* draw grid lines here */
@@ -559,7 +559,7 @@ static void waveform_draw_one(float *waveform, int waveform_num, const float col
/* TODO: store the #GPUBatch inside the scope. */
GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
GPU_batch_draw(batch);
@@ -653,7 +653,7 @@ void ui_draw_but_WAVEFORM(ARegion *UNUSED(region),
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
@@ -977,7 +977,7 @@ void ui_draw_but_VECTORSCOPE(ARegion *UNUSED(region),
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
/* draw grid elements */
@@ -1128,7 +1128,7 @@ static void ui_draw_colorband_handle(uint shdr_pos,
if (active || half_width < min_width) {
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1147,7 +1147,7 @@ static void ui_draw_colorband_handle(uint shdr_pos,
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* hide handles when zoomed out too far */
if (half_width < min_width) {
@@ -1242,7 +1242,7 @@ void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *UNUSED(wcol), const
format = immVertexFormat();
pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
/* layer: color ramp */
GPU_blend(GPU_BLEND_ALPHA);
@@ -1298,7 +1298,7 @@ void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *UNUSED(wcol), const
/* New format */
format = immVertexFormat();
pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* layer: box outline */
immUniformColor4f(0.0f, 0.0f, 0.0f, 1.0f);
@@ -1400,7 +1400,7 @@ void ui_draw_but_UNITVEC(uiBut *but,
/* AA circle */
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3ubv(wcol->inner);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1534,7 +1534,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* backdrop */
float color_backdrop[4] = {0, 0, 0, 1};
@@ -1657,7 +1657,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
}
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
/* Curve filled. */
@@ -1698,7 +1698,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
/* Calculate vertex colors based on text theme. */
float color_vert[4], color_vert_select[4];
@@ -1730,7 +1730,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
/* outline */
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3ubv(wcol->outline);
imm_draw_box_wire_2d(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
@@ -1790,7 +1790,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw the backdrop. */
float color_backdrop[4] = {0, 0, 0, 1};
@@ -1948,7 +1948,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
/* Calculate vertex colors based on text theme. */
float color_vert[4], color_vert_select[4], color_sample[4];
@@ -2025,7 +2025,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
/* Outline */
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3ubv((const uchar *)wcol->outline);
imm_draw_box_wire_2d(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
@@ -2132,7 +2132,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
color);
}
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexTiled(&state,
rect.xmin,
rect.ymin + 1,
@@ -2152,7 +2152,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
UI_GetThemeColor4fv(TH_SEL_MARKER, col_sel);
UI_GetThemeColor4fv(TH_MARKER_OUTLINE, col_outline);
@@ -2288,7 +2288,7 @@ void UI_draw_box_shadow(const rctf *rect, uchar alpha)
uint color = GPU_vertformat_attr_add(
format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
immBegin(GPU_PRIM_TRIS, 54);
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index 9d3c1372b15..b72d8d2c238 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -22,15 +22,14 @@
#include "UI_interface.h"
/* -------------------------------------------------------------------- */
-/** \name Tree View Drag/Drop Callbacks
+/** \name View Drag/Drop Callbacks
* \{ */
-static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
const ARegion *region = CTX_wm_region(C);
- const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region,
- event->xy);
- if (!hovered_tree_item) {
+ const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy);
+ if (!hovered_item) {
return false;
}
@@ -39,21 +38,21 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
}
drag->drop_state.free_disabled_info = false;
- return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->drop_state.disabled_info);
+ return UI_view_item_can_drop(hovered_item, drag, &drag->drop_state.disabled_info);
}
-static char *ui_tree_view_drop_tooltip(bContext *C,
- wmDrag *drag,
- const int xy[2],
- wmDropBox *UNUSED(drop))
+static char *ui_view_drop_tooltip(bContext *C,
+ wmDrag *drag,
+ const int xy[2],
+ wmDropBox *UNUSED(drop))
{
const ARegion *region = CTX_wm_region(C);
- const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, xy);
- if (!hovered_tree_item) {
+ const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, xy);
+ if (!hovered_item) {
return nullptr;
}
- return UI_tree_view_item_drop_tooltip(hovered_tree_item, drag);
+ return UI_view_item_drop_tooltip(hovered_item, drag);
}
/** \} */
@@ -140,12 +139,7 @@ void ED_dropboxes_ui()
{
ListBase *lb = WM_dropboxmap_find("User Interface", SPACE_EMPTY, 0);
- WM_dropbox_add(lb,
- "UI_OT_tree_view_drop",
- ui_tree_view_drop_poll,
- nullptr,
- nullptr,
- ui_tree_view_drop_tooltip);
+ WM_dropbox_add(lb, "UI_OT_view_drop", ui_view_drop_poll, nullptr, nullptr, ui_view_drop_tooltip);
WM_dropbox_add(lb,
"UI_OT_drop_name",
ui_drop_name_poll,
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 341d5e78872..6ee421fb4d2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1151,7 +1151,10 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
data->applied = true;
}
-static void ui_apply_but_TREEROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
+static void ui_apply_but_VIEW_ITEM(bContext *C,
+ uiBlock *block,
+ uiBut *but,
+ uiHandleButtonData *data)
{
if (data->apply_through_extra_icon) {
/* Don't apply this, it would cause unintended tree-row toggling when clicking on extra icons.
@@ -2128,10 +2131,10 @@ static bool ui_but_drag_init(bContext *C,
return false;
}
}
- else if (but->type == UI_BTYPE_TREEROW) {
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
- if (tree_row_but->tree_item) {
- UI_tree_view_item_drag_start(C, tree_row_but->tree_item);
+ else if (but->type == UI_BTYPE_VIEW_ITEM) {
+ const uiButViewItem *view_item_but = (uiButViewItem *)but;
+ if (view_item_but->view_item) {
+ UI_view_item_drag_start(C, view_item_but->view_item);
}
}
else {
@@ -2289,11 +2292,8 @@ static void ui_apply_but(
case UI_BTYPE_ROW:
ui_apply_but_ROW(C, block, but, data);
break;
- case UI_BTYPE_GRID_TILE:
- ui_apply_but_ROW(C, block, but, data);
- break;
- case UI_BTYPE_TREEROW:
- ui_apply_but_TREEROW(C, block, but, data);
+ case UI_BTYPE_VIEW_ITEM:
+ ui_apply_but_VIEW_ITEM(C, block, but, data);
break;
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
@@ -3172,19 +3172,11 @@ static bool ui_textedit_insert_buf(uiBut *but,
return changed;
}
-static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
+static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, const char ascii)
{
+ BLI_assert(isascii(ascii));
const char buf[2] = {ascii, '\0'};
-
- if (UI_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
- printf(
- "%s: entering invalid ascii char into an ascii key (%d)\n", __func__, (int)(uchar)ascii);
-
- return false;
- }
-
- /* in some cases we want to allow invalid utf8 chars */
- return ui_textedit_insert_buf(but, data, buf, 1);
+ return ui_textedit_insert_buf(but, data, buf, sizeof(buf) - 1);
}
static void ui_textedit_move(uiBut *but,
@@ -3897,30 +3889,27 @@ static void ui_do_but_textedit(
}
}
- if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
+ if ((event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
#ifdef WITH_INPUT_IME
&& !is_ime_composing && !WM_event_is_ime_switch(event)
#endif
) {
- char ascii = event->ascii;
+ char utf8_buf_override[2] = {'\0', '\0'};
const char *utf8_buf = event->utf8_buf;
/* Exception that's useful for number buttons, some keyboard
* numpads have a comma instead of a period. */
if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* Could use `data->min`. */
- if (event->type == EVT_PADPERIOD && ascii == ',') {
- ascii = '.';
- utf8_buf = NULL; /* force ascii fallback */
+ if ((event->type == EVT_PADPERIOD) && (utf8_buf[0] == ',')) {
+ utf8_buf_override[0] = '.';
+ utf8_buf = utf8_buf_override;
}
}
- if (utf8_buf && utf8_buf[0]) {
+ if (utf8_buf[0]) {
const int utf8_buf_len = BLI_str_utf8_size(utf8_buf);
BLI_assert(utf8_buf_len != -1);
- changed = ui_textedit_insert_buf(but, data, event->utf8_buf, utf8_buf_len);
- }
- else {
- changed = ui_textedit_insert_ascii(but, data, ascii);
+ changed = ui_textedit_insert_buf(but, data, utf8_buf, utf8_buf_len);
}
retval = WM_UI_HANDLER_BREAK;
@@ -3952,6 +3941,9 @@ static void ui_do_but_textedit(
else if (event->type == WM_IME_COMPOSITE_END) {
changed = true;
}
+#else
+ /* Prevent the function from being unused. */
+ (void)ui_textedit_insert_ascii;
#endif
if (changed) {
@@ -4352,15 +4344,18 @@ static uiButExtraOpIcon *ui_but_extra_operator_icon_mouse_over_get(uiBut *but,
ARegion *region,
const wmEvent *event)
{
- float xmax = but->rect.xmax;
- const float icon_size = 0.8f * BLI_rctf_size_y(&but->rect); /* ICON_SIZE_FROM_BUTRECT */
- int x = event->xy[0], y = event->xy[1];
+ if (BLI_listbase_is_empty(&but->extra_op_icons)) {
+ return NULL;
+ }
+ int x = event->xy[0], y = event->xy[1];
ui_window_to_block(region, but->block, &x, &y);
if (!BLI_rctf_isect_pt(&but->rect, x, y)) {
return NULL;
}
+ const float icon_size = 0.8f * BLI_rctf_size_y(&but->rect); /* ICON_SIZE_FROM_BUTRECT */
+ float xmax = but->rect.xmax;
/* Same as in 'widget_draw_extra_icons', icon padding from the right edge. */
xmax -= 0.2 * icon_size;
@@ -4517,7 +4512,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
}
}
else if (data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (ISMOUSE_MOTION(event->type)) {
return WM_UI_HANDLER_CONTINUE;
}
if (event->type == EVT_UNKNOWNKEY) {
@@ -4583,7 +4578,7 @@ static int ui_do_but_KEYEVT(bContext *C,
}
}
else if (data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (ISMOUSE_MOTION(event->type)) {
return WM_UI_HANDLER_CONTINUE;
}
@@ -4772,54 +4767,13 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_TREEROW(bContext *C,
- uiBut *but,
- uiHandleButtonData *data,
- const wmEvent *event)
-{
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
- BLI_assert(tree_row_but->but.type == UI_BTYPE_TREEROW);
-
- if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (event->type == LEFTMOUSE) {
- switch (event->val) {
- case KM_PRESS:
- /* Extra icons have priority, don't mess with them. */
- if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
- return WM_UI_HANDLER_BREAK;
- }
- button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->xy[0];
- data->dragstarty = event->xy[1];
- return WM_UI_HANDLER_CONTINUE;
-
- case KM_CLICK:
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
-
- case KM_DBL_CLICK:
- data->cancel = true;
- UI_tree_view_item_begin_rename(tree_row_but->tree_item);
- ED_region_tag_redraw(CTX_wm_region(C));
- return WM_UI_HANDLER_BREAK;
- }
- }
- }
- else if (data->state == BUTTON_STATE_WAIT_DRAG) {
- /* Let "default" button handling take care of the drag logic. */
- return ui_do_but_EXIT(C, but, data, event);
- }
-
- return WM_UI_HANDLER_CONTINUE;
-}
-
-static int ui_do_but_GRIDTILE(bContext *C,
- uiBut *but,
- uiHandleButtonData *data,
- const wmEvent *event)
+static int ui_do_but_VIEW_ITEM(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
{
- uiButGridTile *grid_tile_but = (uiButGridTile *)but;
- BLI_assert(grid_tile_but->but.type == UI_BTYPE_GRID_TILE);
+ uiButViewItem *view_item_but = (uiButViewItem *)but;
+ BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) {
@@ -4840,7 +4794,7 @@ static int ui_do_but_GRIDTILE(bContext *C,
case KM_DBL_CLICK:
data->cancel = true;
- // UI_tree_view_item_begin_rename(grid_tile_but->tree_item);
+ UI_view_item_begin_rename(view_item_but->view_item);
ED_region_tag_redraw(CTX_wm_region(C));
return WM_UI_HANDLER_BREAK;
}
@@ -7988,7 +7942,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
* to spawn the context menu should also activate the item. This makes it clear which item
* will be operated on.
* Apply the button immediately, so context menu polls get the right active item. */
- if (ELEM(but->type, UI_BTYPE_TREEROW)) {
+ if (ELEM(but->type, UI_BTYPE_VIEW_ITEM)) {
ui_apply_but(C, but->block, but, but->active, true);
}
@@ -8053,11 +8007,8 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_ROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
- case UI_BTYPE_GRID_TILE:
- retval = ui_do_but_GRIDTILE(C, but, data, event);
- break;
- case UI_BTYPE_TREEROW:
- retval = ui_do_but_TREEROW(C, but, data, event);
+ case UI_BTYPE_VIEW_ITEM:
+ retval = ui_do_but_VIEW_ITEM(C, but, data, event);
break;
case UI_BTYPE_SCROLL:
retval = ui_do_but_SCROLL(C, block, but, data, event);
@@ -8149,7 +8100,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
#ifdef USE_DRAG_MULTINUM
data = but->active;
if (data) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) ||
+ if (ISMOUSE_MOTION(event->type) ||
/* if we started dragging, progress on any event */
(data->multi_data.init == BUTTON_MULTI_INIT_SETUP)) {
if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) &&
@@ -8862,7 +8813,7 @@ void UI_context_active_but_prop_handle(bContext *C, const bool handle_undo)
{
uiBut *activebut = ui_context_rna_button_active(C);
if (activebut) {
- /* TODO(campbell): look into a better way to handle the button change
+ /* TODO(@campbellbarton): look into a better way to handle the button change
* currently this is mainly so reset defaults works for the
* operator redo panel. */
uiBlock *block = activebut->block;
@@ -9487,7 +9438,7 @@ static int ui_list_activate_hovered_row(bContext *C,
}
/* Simulate click on listrow button itself (which may be overlapped by another button). Also
- * calls the custom activate operator (ui_list->custom_activate_opname). */
+ * calls the custom activate operator (#uiListDyn::custom_activate_optype). */
UI_but_execute(C, region, listrow);
((uiList *)ui_list)->dyn_data->custom_activate_optype = custom_activate_optype;
@@ -9558,13 +9509,13 @@ static void ui_list_activate_row_from_index(
uiBut *new_active_row = ui_list_row_find_from_index(region, index, listbox);
if (new_active_row) {
/* Preferred way to update the active item, also calls the custom activate operator
- * (#uiList.custom_activate_opname). */
+ * (#uiListDyn::custom_activate_optype). */
UI_but_execute(C, region, new_active_row);
}
else {
/* A bit ugly, set the active index in RNA directly. That's because a button that's
* scrolled away in the list box isn't created at all.
- * The custom activate operator (#uiList.custom_activate_opname) is not called in this case
+ * The custom activate operator (#uiListDyn::custom_activate_optype) is not called in this case
* (which may need the row button context). */
RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, index);
RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop);
@@ -9733,7 +9684,7 @@ static int ui_handle_view_items_hover(const wmEvent *event, const ARegion *regio
}
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- if (ui_but_is_view_item(but)) {
+ if (but->type == UI_BTYPE_VIEW_ITEM) {
but->flag &= ~UI_ACTIVE;
has_view_item = true;
}
@@ -9760,7 +9711,7 @@ static int ui_handle_view_item_event(bContext *C,
ARegion *region,
uiBut *view_but)
{
- BLI_assert(ui_but_is_view_item(view_but));
+ BLI_assert(view_but->type == UI_BTYPE_VIEW_ITEM);
if (event->type == LEFTMOUSE) {
/* Will free active button if there already is one. */
ui_handle_button_activate(C, region, view_but, BUTTON_ACTIVATE_OVER);
@@ -10148,8 +10099,7 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
/* Pass, needed to click-exit outside of non-floating menus. */
ui_region_auto_open_clear(but->active->region);
}
- else if ((!ELEM(event->type, MOUSEMOVE, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN)) &&
- ISMOUSE(event->type)) {
+ else if (ISMOUSE_BUTTON(event->type)) {
if (!ui_but_contains_point_px(but, but->active->region, event->xy)) {
but = NULL;
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c19e842aad8..ad2c08194aa 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -360,7 +360,7 @@ static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNU
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* XXX: Include alpha into this... */
/* normal */
@@ -505,7 +505,7 @@ static void vicon_gplayer_color_draw(Icon *icon, int x, int y, int w, int h)
*/
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(gpl->color);
immRecti(pos, x, y, x + w - 1, y + h - 1);
@@ -1546,7 +1546,7 @@ static void icon_draw_rect(float x,
shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR;
}
else {
- shader = GPU_SHADER_2D_IMAGE_COLOR;
+ shader = GPU_SHADER_3D_IMAGE_COLOR;
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader);
@@ -1824,7 +1824,7 @@ static void icon_draw_size(float x,
}
else if (di->type == ICON_TYPE_GEOM) {
#ifdef USE_UI_TOOLBAR_HACK
- /* TODO(campbell): scale icons up for toolbar,
+ /* TODO(@campbellbarton): scale icons up for toolbar,
* we need a way to detect larger buttons and do this automatic. */
{
float scale = (float)ICON_DEFAULT_HEIGHT_TOOLBAR / (float)ICON_DEFAULT_HEIGHT;
@@ -1839,7 +1839,7 @@ static void icon_draw_size(float x,
const bool geom_inverted = di->data.geom.inverted;
/* This could re-generate often if rendered at different sizes in the one interface.
- * TODO(campbell): support caching multiple sizes. */
+ * TODO(@campbellbarton): support caching multiple sizes. */
ImBuf *ibuf = di->data.geom.image_cache;
if ((ibuf == NULL) || (ibuf->x != w) || (ibuf->y != h) || (invert != geom_inverted)) {
if (ibuf) {
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 6ad5fe805ab..e892a989191 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -60,10 +60,8 @@
#include "interface_intern.h"
-static void icon_draw_rect_input_text(const rctf *rect,
- const float color[4],
- const char *str,
- float font_size)
+static void icon_draw_rect_input_text(
+ const rctf *rect, const float color[4], const char *str, float font_size, float v_offset)
{
BLF_batch_draw_flush();
const int font_id = BLF_default();
@@ -71,21 +69,9 @@ static void icon_draw_rect_input_text(const rctf *rect,
BLF_size(font_id, font_size * U.pixelsize, U.dpi);
float width, height;
BLF_width_and_height(font_id, str, BLF_DRAW_STR_DUMMY_MAX, &width, &height);
- const float x = rect->xmin + (((rect->xmax - rect->xmin) - width) / 2.0f);
- const float y = rect->ymin + (((rect->ymax - rect->ymin) - height) / 2.0f);
- BLF_position(font_id, x, y, 0.0f);
- BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_batch_draw_flush();
-}
-
-static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4], const char *str)
-{
- BLF_batch_draw_flush();
- const int font_id = blf_mono_font;
- BLF_color4fv(font_id, color);
- BLF_size(font_id, 19.0f * U.pixelsize, U.dpi);
- const float x = rect->xmin + (2.0f * U.pixelsize);
- const float y = rect->ymin + (1.0f * U.pixelsize);
+ const float x = trunc(rect->xmin + (((rect->xmax - rect->xmin) - width) / 2.0f));
+ const float y = rect->ymin + (((rect->ymax - rect->ymin) - height) / 2.0f) +
+ (v_offset * U.dpi_fac);
BLF_position(font_id, x, y, 0.0f);
BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
BLF_batch_draw_flush();
@@ -99,20 +85,17 @@ void icon_draw_rect_input(float x,
short event_type,
short UNUSED(event_value))
{
+ rctf rect = {
+ .xmin = (int)x - U.pixelsize,
+ .xmax = (int)(x + w + U.pixelsize),
+ .ymin = (int)(y),
+ .ymax = (int)(y + h),
+ };
float color[4];
GPU_line_width(1.0f);
UI_GetThemeColor4fv(TH_TEXT, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = (int)x - U.pixelsize,
- .xmax = (int)(x + w),
- .ymin = (int)y,
- .ymax = (int)(y + h),
- },
- false,
- 3.0f * U.pixelsize,
- color);
+ UI_draw_roundbox_aa(&rect, false, 3.0f * U.pixelsize, color);
const enum {
UNIX,
@@ -129,94 +112,89 @@ void icon_draw_rect_input(float x,
#endif
;
- const rctf rect = {
- .xmin = x,
- .ymin = y,
- .xmax = x + w,
- .ymax = y + h,
- };
-
if ((event_type >= EVT_AKEY) && (event_type <= EVT_ZKEY)) {
const char str[2] = {'A' + (event_type - EVT_AKEY), '\0'};
- icon_draw_rect_input_text(&rect, color, str, 13.0f);
+ icon_draw_rect_input_text(&rect, color, str, 13.0f, 0.0f);
}
- else if ((event_type >= EVT_F1KEY) && (event_type <= EVT_F12KEY)) {
+ else if ((event_type >= EVT_F1KEY) && (event_type <= EVT_F24KEY)) {
char str[4];
SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY));
- icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f);
+ icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.5f : 11.5f, 0.0f);
}
else if (event_type == EVT_LEFTSHIFTKEY) { /* Right Shift has already been converted to left. */
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0}, 16.0f, 0.0f);
}
else if (event_type == EVT_LEFTCTRLKEY) { /* Right Shift has already been converted to left. */
if (platform == MACOS) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0}, 21.0f, -8.0f);
}
else {
- icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f);
+ icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f, 0.0f);
}
}
else if (event_type == EVT_LEFTALTKEY) { /* Right Alt has already been converted to left. */
if (platform == MACOS) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0}, 13.0f, 0.0f);
}
else {
- icon_draw_rect_input_text(&rect, color, "Alt", 10.0f);
+ icon_draw_rect_input_text(&rect, color, "Alt", 10.0f, 0.0f);
}
}
else if (event_type == EVT_OSKEY) {
if (platform == MACOS) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x98, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x8c, 0x98, 0x0}, 16.0f, 0.0f);
}
else if (platform == MSWIN) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0}, 16.0f, 0.0f);
}
else {
- icon_draw_rect_input_text(&rect, color, "OS", 10.0f);
+ icon_draw_rect_input_text(&rect, color, "OS", 10.0f, 0.0f);
}
}
else if (event_type == EVT_DELKEY) {
- icon_draw_rect_input_text(&rect, color, "Del", 9.0f);
+ icon_draw_rect_input_text(&rect, color, "Del", 9.0f, 0.0f);
}
else if (event_type == EVT_TABKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0}, 18.0f, -1.5f);
}
else if (event_type == EVT_HOMEKEY) {
- icon_draw_rect_input_text(&rect, color, "Home", 6.0f);
+ icon_draw_rect_input_text(&rect, color, "Home", 6.0f, 0.0f);
}
else if (event_type == EVT_ENDKEY) {
- icon_draw_rect_input_text(&rect, color, "End", 8.0f);
+ icon_draw_rect_input_text(&rect, color, "End", 8.0f, 0.0f);
}
else if (event_type == EVT_RETKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0}, 17.0f, -1.0f);
}
else if (event_type == EVT_ESCKEY) {
if (platform == MACOS) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0}, 21.0f, -1.0f);
}
else {
- icon_draw_rect_input_text(&rect, color, "Esc", 8.0f);
+ icon_draw_rect_input_text(&rect, color, "Esc", 8.5f, 0.0f);
}
}
else if (event_type == EVT_PAGEUPKEY) {
- icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8.0f);
+ icon_draw_rect_input_text(
+ &rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 12.0f, 0.0f);
}
else if (event_type == EVT_PAGEDOWNKEY) {
- icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8.0f);
+ icon_draw_rect_input_text(
+ &rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 12.0f, 0.0f);
}
else if (event_type == EVT_LEFTARROWKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0}, 18.0f, -1.5f);
}
else if (event_type == EVT_UPARROWKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x91, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x86, 0x91, 0x0}, 16.0f, 0.0f);
}
else if (event_type == EVT_RIGHTARROWKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x92, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x86, 0x92, 0x0}, 18.0f, -1.5f);
}
else if (event_type == EVT_DOWNARROWKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x93, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x86, 0x93, 0x0}, 16.0f, 0.0f);
}
else if (event_type == EVT_SPACEKEY) {
- icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x90, 0xa3, 0x0});
+ icon_draw_rect_input_text(&rect, color, (const char[]){0xe2, 0x90, 0xa3, 0x0}, 20.0f, 2.0f);
}
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 791e51b81a6..0c842084de6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -25,6 +25,7 @@ struct CurveMapping;
struct CurveProfile;
struct ID;
struct ImBuf;
+struct Main;
struct Scene;
struct bContext;
struct bContextStore;
@@ -343,20 +344,12 @@ typedef struct uiButProgressbar {
float progress;
} uiButProgressbar;
-/** Derived struct for #UI_BTYPE_TREEROW. */
-typedef struct uiButTreeRow {
+typedef struct uiButViewItem {
uiBut but;
- uiTreeViewItemHandle *tree_item;
- int indentation;
-} uiButTreeRow;
-
-/** Derived struct for #UI_BTYPE_GRID_TILE. */
-typedef struct uiButGridTile {
- uiBut but;
-
- uiGridViewItemHandle *view_item;
-} uiButGridTile;
+ /* C-Handle to the view item this button was created for. */
+ uiViewItemHandle *view_item;
+} uiButViewItem;
/** Derived struct for #UI_BTYPE_HSVCUBE. */
typedef struct uiButHSVCube {
@@ -476,6 +469,7 @@ typedef enum uiButtonGroupFlag {
/** The buttons in this group are inside a panel header. */
UI_BUTTON_GROUP_PANEL_HEADER = (1 << 1),
} uiButtonGroupFlag;
+ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER);
struct uiBlock {
uiBlock *next, *prev;
@@ -1372,7 +1366,6 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-bool ui_but_is_view_item(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
/**
* Can we mouse over the button or is it hidden/disabled/layout.
* \note ctrl is kind of a hack currently,
@@ -1406,9 +1399,7 @@ uiBut *ui_list_row_find_from_index(const struct ARegion *region,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_view_item_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
-uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
- ATTR_NONNULL(1, 2);
-uiBut *ui_tree_row_find_active(const struct ARegion *region);
+uiBut *ui_view_item_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
/**
@@ -1543,17 +1534,22 @@ void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
void ui_block_free_views(struct uiBlock *block);
-uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(const uiBlock *new_block,
- const uiTreeViewHandle *new_view);
-uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
- const uiBlock *new_block, const uiGridViewHandle *new_view_handle);
-uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
- const uiTreeViewItemHandle *new_item_handle);
+uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiViewHandle *new_view);
+
+uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
+ const uiBlock *new_block, const uiViewItemHandle *new_item_handle);
/* interface_templates.c */
struct uiListType *UI_UL_cache_file_layers(void);
+struct ID *ui_template_id_liboverride_hierarchy_make(struct bContext *C,
+ struct Main *bmain,
+ struct ID *owner_id,
+ struct ID *id,
+ const char **r_undo_push_label);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 3465373c85d..94d17ed3c88 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -3028,7 +3028,14 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
if (WM_menutype_poll(C, mt) == false) {
return;
}
+
+ bContextStore *previous_ctx = CTX_store_get(C);
UI_menutype_draw(C, mt, layout);
+
+ /* Restore context that was cleared by `UI_menutype_draw`. */
+ if (layout->context) {
+ CTX_store_set(C, previous_ctx);
+ }
}
void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.cc
index aafb56119ae..a5b0193a86d 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.cc
@@ -5,7 +5,7 @@
* \ingroup edinterface
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -21,6 +21,7 @@
#include "BLF_api.h"
#include "BLT_lang.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -28,6 +29,7 @@
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
+#include "BKE_lib_remap.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_report.h"
@@ -40,6 +42,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
@@ -127,13 +130,13 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *op)
/* try to create driver using property retrieved from UI */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- if (ptr.owner_id != NULL) {
+ if (ptr.owner_id != nullptr) {
if (full_path) {
if (prop) {
- path = RNA_path_full_property_py_ex(bmain, &ptr, prop, index, true);
+ path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
}
else {
- path = RNA_path_full_struct_py(bmain, &ptr);
+ path = RNA_path_full_struct_py(&ptr);
}
}
else {
@@ -216,7 +219,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *op)
if (ptr.owner_id && ptr.data && prop) {
ID *id;
- const int dim = RNA_property_array_dimension(&ptr, prop, NULL);
+ const int dim = RNA_property_array_dimension(&ptr, prop, nullptr);
char *path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, dim, index, &id);
if (path) {
@@ -260,25 +263,25 @@ static bool copy_python_command_button_poll(bContext *C)
{
uiBut *but = UI_context_active_but_get(C);
- if (but && (but->optype != NULL)) {
- return 1;
+ if (but && (but->optype != nullptr)) {
+ return true;
}
- return 0;
+ return false;
}
static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op))
{
uiBut *but = UI_context_active_but_get(C);
- if (but && (but->optype != NULL)) {
+ if (but && (but->optype != nullptr)) {
PointerRNA *opptr;
char *str;
opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
- str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr);
+ str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
- WM_clipboard_text_set(str, 0);
+ WM_clipboard_text_set(str, false);
MEM_freeN(str);
@@ -390,7 +393,8 @@ static void UI_OT_reset_default_button(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ RNA_def_boolean(
+ ot->srna, "all", true, "All", "Reset to default values all elements of the array");
}
/** \} */
@@ -529,7 +533,7 @@ static EnumPropertyItem override_type_items[] = {
0,
"Factor",
"Store factor to linked data value (useful e.g. for scale)"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool override_type_set_button_poll(bContext *C)
@@ -580,16 +584,16 @@ static int override_type_set_button_exec(bContext *C, wmOperator *op)
/* try to reset the nominated setting to its default value */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- BLI_assert(ptr.owner_id != NULL);
+ BLI_assert(ptr.owner_id != nullptr);
if (all) {
index = -1;
}
IDOverrideLibraryPropertyOperation *opop = RNA_property_override_property_operation_get(
- CTX_data_main(C), &ptr, prop, operation, index, true, NULL, &created);
+ CTX_data_main(C), &ptr, prop, operation, index, true, nullptr, &created);
- if (opop == NULL) {
+ if (opop == nullptr) {
/* Sometimes e.g. RNA cannot generate a path to the given property. */
BKE_reportf(op->reports, RPT_WARNING, "Failed to create the override operation");
return OPERATOR_CANCELLED;
@@ -600,7 +604,7 @@ static int override_type_set_button_exec(bContext *C, wmOperator *op)
}
/* Outliner e.g. has to be aware of this change. */
- WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
+ WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr);
return operator_button_property_finish(C, &ptr, prop);
}
@@ -633,7 +637,8 @@ static void UI_OT_override_type_set_button(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ RNA_def_boolean(
+ ot->srna, "all", true, "All", "Reset to default values all elements of the array");
ot->prop = RNA_def_enum(ot->srna,
"type",
override_type_items,
@@ -670,8 +675,8 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
ID *id = ptr.owner_id;
IDOverrideLibraryProperty *oprop = RNA_property_override_property_find(bmain, &ptr, prop, &id);
- BLI_assert(oprop != NULL);
- BLI_assert(id != NULL && id->override_library != NULL);
+ BLI_assert(oprop != nullptr);
+ BLI_assert(id != nullptr && id->override_library != nullptr);
const bool is_template = ID_IS_OVERRIDE_LIBRARY_TEMPLATE(id);
@@ -690,8 +695,8 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
/* Remove override operation for given item,
* add singular operations for the other items as needed. */
IDOverrideLibraryPropertyOperation *opop = BKE_lib_override_library_property_operation_find(
- oprop, NULL, NULL, index, index, false, &is_strict_find);
- BLI_assert(opop != NULL);
+ oprop, nullptr, nullptr, index, index, false, &is_strict_find);
+ BLI_assert(opop != nullptr);
if (!is_strict_find) {
/* No specific override operation, we have to get generic one,
* and create item-specific override operations for all but given index,
@@ -699,7 +704,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
for (int idx = RNA_property_array_length(&ptr, prop); idx--;) {
if (idx != index) {
BKE_lib_override_library_property_operation_get(
- oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL);
+ oprop, opop->operation, nullptr, nullptr, idx, idx, true, nullptr, nullptr);
}
}
}
@@ -720,7 +725,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
}
/* Outliner e.g. has to be aware of this change. */
- WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
+ WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr);
return operator_button_property_finish(C, &ptr, prop);
}
@@ -740,7 +745,286 @@ static void UI_OT_override_remove_button(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ RNA_def_boolean(
+ ot->srna, "all", true, "All", "Reset to default values all elements of the array");
+}
+
+static void override_idtemplate_ids_get(
+ bContext *C, ID **r_owner_id, ID **r_id, PointerRNA *r_owner_ptr, PropertyRNA **r_prop)
+{
+ PointerRNA owner_ptr;
+ PropertyRNA *prop;
+ UI_context_active_but_prop_get_templateID(C, &owner_ptr, &prop);
+
+ if (owner_ptr.data == nullptr || prop == nullptr) {
+ *r_owner_id = *r_id = nullptr;
+ if (r_owner_ptr != nullptr) {
+ *r_owner_ptr = PointerRNA_NULL;
+ }
+ if (r_prop != nullptr) {
+ *r_prop = nullptr;
+ }
+ return;
+ }
+
+ *r_owner_id = owner_ptr.owner_id;
+ PointerRNA idptr = RNA_property_pointer_get(&owner_ptr, prop);
+ *r_id = static_cast<ID *>(idptr.data);
+ if (r_owner_ptr != nullptr) {
+ *r_owner_ptr = owner_ptr;
+ }
+ if (r_prop != nullptr) {
+ *r_prop = prop;
+ }
+}
+
+static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
+{
+ ID *owner_id, *id;
+ override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
+
+ if (owner_id == nullptr || id == nullptr) {
+ return false;
+ }
+
+ if (is_create_op) {
+ if (!ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ return false;
+ }
+ return true;
+ }
+
+ /* Reset/Clear operations. */
+ if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ return false;
+ }
+ return true;
+}
+
+static bool override_idtemplate_make_poll(bContext *C)
+{
+ return override_idtemplate_poll(C, true);
+}
+
+static int override_idtemplate_make_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ID *owner_id, *id;
+ PointerRNA owner_ptr;
+ PropertyRNA *prop;
+ override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
+ if (ELEM(nullptr, owner_id, id)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ID *id_override = ui_template_id_liboverride_hierarchy_make(
+ C, CTX_data_main(C), owner_id, id, nullptr);
+
+ if (id_override == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ PointerRNA idptr;
+ /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
+ * to ensure remapping of the owner property from the linked data to the newly created
+ * liboverride (note that in theory this remapping has already been done by code above), but
+ * only in case owner ID was already local ID (override or pure local data).
+ *
+ * Otherwise, owner ID will also have been overridden, and remapped already to use it's
+ * override of the data too. */
+ if (!ID_IS_LINKED(owner_id)) {
+ RNA_id_pointer_create(id_override, &idptr);
+ RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
+ }
+ RNA_property_update(C, &owner_ptr, prop);
+
+ /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
+ * used ID, relying on the property update code only is not always enough. */
+ DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_override_idtemplate_make(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Library Override";
+ ot->idname = "UI_OT_override_idtemplate_make";
+ ot->description =
+ "Create a local override of the selected linked data-block, and its hierarchy of "
+ "dependencies";
+
+ /* callbacks */
+ ot->poll = override_idtemplate_make_poll;
+ ot->exec = override_idtemplate_make_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+static bool override_idtemplate_reset_poll(bContext *C)
+{
+ return override_idtemplate_poll(C, false);
+}
+
+static int override_idtemplate_reset_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ID *owner_id, *id;
+ PointerRNA owner_ptr;
+ PropertyRNA *prop;
+ override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
+ if (ELEM(nullptr, owner_id, id)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_lib_override_library_id_reset(CTX_data_main(C), id, false);
+
+ PointerRNA idptr;
+ /* `idptr` is re-assigned to owner property to ensure proper updates etc. */
+ RNA_id_pointer_create(id, &idptr);
+ RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
+ RNA_property_update(C, &owner_ptr, prop);
+
+ /* No need for 'security' extra tagging here, since this process will never affect the owner ID.
+ */
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_override_idtemplate_reset(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reset Library Override";
+ ot->idname = "UI_OT_override_idtemplate_reset";
+ ot->description = "Reset the selected local override to its linked reference values";
+
+ /* callbacks */
+ ot->poll = override_idtemplate_reset_poll;
+ ot->exec = override_idtemplate_reset_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+static bool override_idtemplate_clear_poll(bContext *C)
+{
+ return override_idtemplate_poll(C, false);
+}
+
+static int override_idtemplate_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ID *owner_id, *id;
+ PointerRNA owner_ptr;
+ PropertyRNA *prop;
+ override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
+ if (ELEM(nullptr, owner_id, id)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ID_IS_LINKED(id)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ ID *id_new = id;
+
+ if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) {
+ id_new = id->override_library->reference;
+ bool do_remap_active = false;
+ if (BKE_view_layer_active_object_get(view_layer) == (Object *)id) {
+ BLI_assert(GS(id->name) == ID_OB);
+ BLI_assert(GS(id_new->name) == ID_OB);
+ do_remap_active = true;
+ }
+ BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (do_remap_active) {
+ Object *ref_object = (Object *)id_new;
+ Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
+ if (basact != nullptr) {
+ view_layer->basact = basact;
+ }
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ }
+ BKE_id_delete(bmain, id);
+ }
+ else {
+ BKE_lib_override_library_id_reset(bmain, id, true);
+ }
+
+ /* Here the affected ID may remain the same, or be replaced by its linked reference. In either
+ * case, the owner ID remains unchanged, and remapping is already handled by internal code, so
+ * calling `RNA_property_update` on it is enough to ensure proper notifiers are sent. */
+ RNA_property_update(C, &owner_ptr, prop);
+
+ /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
+ * used ID, relying on the property update code only is not always enough. */
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_override_idtemplate_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Library Override";
+ ot->idname = "UI_OT_override_idtemplate_clear";
+ ot->description =
+ "Delete the selected local override and relink its usages to the linked data-block if "
+ "possible, else reset it and mark it as non editable";
+
+ /* callbacks */
+ ot->poll = override_idtemplate_clear_poll;
+ ot->exec = override_idtemplate_clear_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType *UNUSED(mt))
+{
+ bContext *C = (bContext *)C_const;
+ ID *owner_id, *id;
+ override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
+
+ if (owner_id == nullptr || id == nullptr) {
+ return false;
+ }
+
+ if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY_REAL(id))) {
+ return false;
+ }
+ return true;
+}
+
+static void override_idtemplate_menu_draw(const bContext *UNUSED(C), Menu *menu)
+{
+ uiLayout *layout = menu->layout;
+ uiItemO(layout, IFACE_("Make"), ICON_NONE, "UI_OT_override_idtemplate_make");
+ uiItemO(layout, IFACE_("Reset"), ICON_NONE, "UI_OT_override_idtemplate_reset");
+ uiItemO(layout, IFACE_("Clear"), ICON_NONE, "UI_OT_override_idtemplate_clear");
+}
+
+static void override_idtemplate_menu()
+{
+ MenuType *mt;
+
+ mt = MEM_cnew<MenuType>(__func__);
+ strcpy(mt->idname, "UI_MT_idtemplate_liboverride");
+ strcpy(mt->label, N_("Library Override"));
+ mt->poll = override_idtemplate_menu_poll;
+ mt->draw = override_idtemplate_menu_draw;
+ WM_menutype_add(mt);
}
/** \} */
@@ -749,8 +1033,8 @@ static void UI_OT_override_remove_button(wmOperatorType *ot)
/** \name Copy To Selected Operator
* \{ */
-#define NOT_NULL(assignment) ((assignment) != NULL)
-#define NOT_RNA_NULL(assignment) ((assignment).data != NULL)
+#define NOT_NULL(assignment) ((assignment) != nullptr)
+#define NOT_RNA_NULL(assignment) ((assignment).data != nullptr)
static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb)
{
@@ -759,7 +1043,7 @@ static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb)
if (!BLI_listbase_is_empty(&lb)) {
LISTBASE_FOREACH (CollectionPointerLink *, link, &lb) {
- bPoseChannel *pchan = link->ptr.data;
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(link->ptr.data);
RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr);
}
}
@@ -775,9 +1059,9 @@ bool UI_context_copy_to_selected_list(bContext *C,
char **r_path)
{
*r_use_path_from_id = false;
- *r_path = NULL;
+ *r_path = nullptr;
/* special case for bone constraints */
- char *path_from_bone = NULL;
+ char *path_from_bone = nullptr;
/* Remove links from the collection list which don't contain 'prop'. */
bool ensure_list_items_contain_prop = false;
@@ -791,29 +1075,32 @@ bool UI_context_copy_to_selected_list(bContext *C,
*/
if (!RNA_property_is_idprop(prop) && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
PointerRNA owner_ptr;
- char *idpath = NULL;
+ char *idpath = nullptr;
/* First, check the active PoseBone and PoseBone->Bone. */
if (NOT_RNA_NULL(
owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone))) {
- if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) {
+ if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(
+ &owner_ptr, static_cast<IDProperty *>(ptr->data)))) {
*r_lb = CTX_data_collection_get(C, "selected_pose_bones");
}
else {
- bPoseChannel *pchan = owner_ptr.data;
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(owner_ptr.data);
RNA_pointer_create(owner_ptr.owner_id, &RNA_Bone, pchan->bone, &owner_ptr);
- if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) {
+ if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(
+ &owner_ptr, static_cast<IDProperty *>(ptr->data)))) {
ui_context_selected_bones_via_pose(C, r_lb);
}
}
}
- if (idpath == NULL) {
+ if (idpath == nullptr) {
/* Check the active EditBone if in edit mode. */
if (NOT_RNA_NULL(
owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) &&
- NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) {
+ NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(
+ &owner_ptr, static_cast<IDProperty *>(ptr->data)))) {
*r_lb = CTX_data_collection_get(C, "selected_editable_bones");
}
@@ -866,30 +1153,30 @@ bool UI_context_copy_to_selected_list(bContext *C,
}
else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) &&
(path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) !=
- NULL) {
+ nullptr) {
*r_lb = CTX_data_collection_get(C, "selected_pose_bones");
*r_path = path_from_bone;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
- ListBase lb = {NULL, NULL};
- char *path = NULL;
- bNode *node = NULL;
+ ListBase lb = {nullptr, nullptr};
+ char *path = nullptr;
+ bNode *node = nullptr;
/* Get the node we're editing */
if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = ptr->data;
- if (nodeFindNode(ntree, sock, &node, NULL)) {
- if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) {
+ bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data);
+ if (nodeFindNode(ntree, sock, &node, nullptr)) {
+ if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != nullptr) {
/* we're good! */
}
else {
- node = NULL;
+ node = nullptr;
}
}
}
else {
- node = ptr->data;
+ node = static_cast<bNode *>(ptr->data);
}
/* Now filter by type */
@@ -897,7 +1184,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
lb = CTX_data_collection_get(C, "selected_nodes");
LISTBASE_FOREACH_MUTABLE (CollectionPointerLink *, link, &lb) {
- bNode *node_data = link->ptr.data;
+ bNode *node_data = static_cast<bNode *>(link->ptr.data);
if (node_data->type != node->type) {
BLI_remlink(&lb, link);
@@ -928,17 +1215,17 @@ bool UI_context_copy_to_selected_list(bContext *C,
LISTBASE_FOREACH (CollectionPointerLink *, link, &lb) {
Object *ob = (Object *)link->ptr.owner_id;
if (ob->data) {
- ID *id_data = ob->data;
+ ID *id_data = static_cast<ID *>(ob->data);
id_data->tag |= LIB_TAG_DOIT;
}
}
LISTBASE_FOREACH_MUTABLE (CollectionPointerLink *, link, &lb) {
Object *ob = (Object *)link->ptr.owner_id;
- ID *id_data = ob->data;
+ ID *id_data = static_cast<ID *>(ob->data);
- if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || ID_IS_LINKED(id_data) ||
- (GS(id_data->name) != id_code)) {
+ if ((id_data == nullptr) || (id_data->tag & LIB_TAG_DOIT) == 0 ||
+ ID_IS_LINKED(id_data) || (GS(id_data->name) != id_code)) {
BLI_remlink(&lb, link);
MEM_freeN(link);
}
@@ -960,7 +1247,8 @@ bool UI_context_copy_to_selected_list(bContext *C,
/* Sequencer's ID is scene :/ */
/* Try to recursively find an RNA_Sequence ancestor,
* to handle situations like T41062... */
- if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
+ if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) !=
+ nullptr) {
/* Special case when we do this for 'Sequence.lock'.
* (if the sequence is locked, it won't be in "selected_editable_sequences"). */
const char *prop_id = RNA_property_identifier(prop);
@@ -974,7 +1262,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
ensure_list_items_contain_prop = true;
}
}
- return (*r_path != NULL);
+ return (*r_path != nullptr);
}
else {
return false;
@@ -1012,13 +1300,13 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr,
if (use_path_from_id) {
/* Path relative to ID. */
- lprop = NULL;
+ lprop = nullptr;
RNA_id_pointer_create(ptr_link->owner_id, &idptr);
RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
}
else if (path) {
/* Path relative to elements from list. */
- lprop = NULL;
+ lprop = nullptr;
RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
}
else {
@@ -1033,7 +1321,7 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr,
/* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
* check but we are now more permissive when it comes to ID properties, see below. */
- if (lprop == NULL) {
+ if (lprop == nullptr) {
return false;
}
@@ -1104,13 +1392,13 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* if there is a valid property that is editable... */
- if (ptr.data == NULL || prop == NULL) {
+ if (ptr.data == nullptr || prop == nullptr) {
return false;
}
- char *path = NULL;
+ char *path = nullptr;
bool use_path_from_id;
- ListBase lb = {NULL};
+ ListBase lb = {nullptr};
if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
return false;
@@ -1197,7 +1485,7 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
/* Verify pointer type. */
char bone_name[MAXBONENAME];
- const StructRNA *target_type = NULL;
+ const StructRNA *target_type = nullptr;
if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
RNA_string_get(&ptr, "name", bone_name);
@@ -1209,13 +1497,13 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
target_type = &RNA_Object;
}
- if (target_type == NULL) {
+ if (target_type == nullptr) {
return false;
}
/* Find the containing Object. */
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = NULL;
+ Base *base = nullptr;
const short id_type = GS(ptr.owner_id->name);
if (id_type == ID_OB) {
base = BKE_view_layer_base_find(view_layer, (Object *)ptr.owner_id);
@@ -1225,7 +1513,7 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
}
bool ok = false;
- if ((base == NULL) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) {
+ if ((base == nullptr) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) {
/* pass */
}
else if (poll) {
@@ -1277,16 +1565,22 @@ static bool jump_to_target_button(bContext *C, bool poll)
if (type == PROP_STRING) {
const uiBut *but = UI_context_active_but_get(C);
const uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but :
- NULL;
+ nullptr;
if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) {
- uiRNACollectionSearch *coll_search = search_but->arg;
+ uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(search_but->arg);
char str_buf[MAXBONENAME];
- char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL);
-
- int found = RNA_property_collection_lookup_string(
- &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
+ char *str_ptr = RNA_property_string_get_alloc(
+ &ptr, prop, str_buf, sizeof(str_buf), nullptr);
+
+ int found = 0;
+ /* Jump to target only works with search properties currently, not search callbacks yet.
+ * See ui_but_add_search. */
+ if (coll_search->search_prop != NULL) {
+ found = RNA_property_collection_lookup_string(
+ &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
+ }
if (str_ptr != str_buf) {
MEM_freeN(str_ptr);
@@ -1341,39 +1635,39 @@ static void UI_OT_jump_to_target_button(wmOperatorType *ot)
/* EditSource Utility funcs and operator,
* NOTE: this includes utility functions and button matching checks. */
-typedef struct uiEditSourceStore {
+struct uiEditSourceStore {
uiBut but_orig;
GHash *hash;
-} uiEditSourceStore;
+};
-typedef struct uiEditSourceButStore {
+struct uiEditSourceButStore {
char py_dbg_fn[FILE_MAX];
int py_dbg_line_number;
-} uiEditSourceButStore;
+};
/* should only ever be set while the edit source operator is running */
-static struct uiEditSourceStore *ui_editsource_info = NULL;
+static uiEditSourceStore *ui_editsource_info = nullptr;
bool UI_editsource_enable_check(void)
{
- return (ui_editsource_info != NULL);
+ return (ui_editsource_info != nullptr);
}
static void ui_editsource_active_but_set(uiBut *but)
{
- BLI_assert(ui_editsource_info == NULL);
+ BLI_assert(ui_editsource_info == nullptr);
- ui_editsource_info = MEM_callocN(sizeof(uiEditSourceStore), __func__);
+ ui_editsource_info = MEM_cnew<uiEditSourceStore>(__func__);
memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut));
ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
}
-static void ui_editsource_active_but_clear(void)
+static void ui_editsource_active_but_clear()
{
- BLI_ghash_free(ui_editsource_info->hash, NULL, MEM_freeN);
+ BLI_ghash_free(ui_editsource_info->hash, nullptr, MEM_freeN);
MEM_freeN(ui_editsource_info);
- ui_editsource_info = NULL;
+ ui_editsource_info = nullptr;
}
static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
@@ -1394,11 +1688,14 @@ static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
return false;
}
+extern "C" {
+void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno);
+}
+
void UI_editsource_active_but_test(uiBut *but)
{
- extern void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno);
- struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__);
+ uiEditSourceButStore *but_store = MEM_cnew<uiEditSourceButStore>(__func__);
const char *fn;
int line_number = -1;
@@ -1423,9 +1720,10 @@ void UI_editsource_active_but_test(uiBut *but)
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
{
- uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but);
+ uiEditSourceButStore *but_store = static_cast<uiEditSourceButStore *>(
+ BLI_ghash_lookup(ui_editsource_info->hash, old_but));
if (but_store) {
- BLI_ghash_remove(ui_editsource_info->hash, old_but, NULL, NULL);
+ BLI_ghash_remove(ui_editsource_info->hash, old_but, nullptr, nullptr);
BLI_ghash_insert(ui_editsource_info->hash, new_but, but_store);
}
}
@@ -1435,8 +1733,8 @@ static int editsource_text_edit(bContext *C,
const char filepath[FILE_MAX],
const int line)
{
- struct Main *bmain = CTX_data_main(C);
- Text *text = NULL;
+ Main *bmain = CTX_data_main(C);
+ Text *text = nullptr;
/* Developers may wish to copy-paste to an external editor. */
printf("%s:%d\n", filepath, line);
@@ -1448,11 +1746,11 @@ static int editsource_text_edit(bContext *C,
}
}
- if (text == NULL) {
+ if (text == nullptr) {
text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain));
}
- if (text == NULL) {
+ if (text == nullptr) {
BKE_reportf(op->reports, RPT_WARNING, "File '%s' cannot be opened", filepath);
return OPERATOR_CANCELLED;
}
@@ -1476,7 +1774,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
if (but) {
GHashIterator ghi;
- struct uiEditSourceButStore *but_store = NULL;
+ uiEditSourceButStore *but_store = nullptr;
ARegion *region = CTX_wm_region(C);
int ret;
@@ -1495,9 +1793,9 @@ static int editsource_exec(bContext *C, wmOperator *op)
for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
BLI_ghashIterator_done(&ghi) == false;
BLI_ghashIterator_step(&ghi)) {
- uiBut *but_key = BLI_ghashIterator_getKey(&ghi);
+ uiBut *but_key = static_cast<uiBut *>(BLI_ghashIterator_getKey(&ghi));
if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
- but_store = BLI_ghashIterator_getValue(&ghi);
+ but_store = static_cast<uiEditSourceButStore *>(BLI_ghashIterator_getValue(&ghi));
break;
}
}
@@ -1568,7 +1866,7 @@ static void edittranslation_find_po_file(const char *root,
/* Now try without the second iso code part (_ES in es_ES). */
{
- const char *tc = NULL;
+ const char *tc = nullptr;
size_t szt = 0;
tstr[0] = '\0';
@@ -1602,7 +1900,7 @@ static void edittranslation_find_po_file(const char *root,
static int edittranslation_exec(bContext *C, wmOperator *op)
{
uiBut *but = UI_context_active_but_get(C);
- if (but == NULL) {
+ if (but == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Active button not found");
return OPERATOR_CANCELLED;
}
@@ -1613,16 +1911,16 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
const char *root = U.i18ndir;
const char *uilng = BLT_lang_get();
- uiStringInfo but_label = {BUT_GET_LABEL, NULL};
- uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL};
- uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
- uiStringInfo but_tip = {BUT_GET_TIP, NULL};
- uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL};
- uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
- uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
- uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
- uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL};
- uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL};
+ uiStringInfo but_label = {BUT_GET_LABEL, nullptr};
+ uiStringInfo rna_label = {BUT_GET_RNA_LABEL, nullptr};
+ uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, nullptr};
+ uiStringInfo but_tip = {BUT_GET_TIP, nullptr};
+ uiStringInfo rna_tip = {BUT_GET_RNA_TIP, nullptr};
+ uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, nullptr};
+ uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, nullptr};
+ uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, nullptr};
+ uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, nullptr};
+ uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, nullptr};
if (!BLI_is_dir(root)) {
BKE_report(op->reports,
@@ -1631,8 +1929,8 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
"Directory' path to a valid directory");
return OPERATOR_CANCELLED;
}
- ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
- if (ot == NULL) {
+ ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, false);
+ if (ot == nullptr) {
BKE_reportf(op->reports,
RPT_ERROR,
"Could not find operator '%s'! Please enable ui_translate add-on "
@@ -1661,7 +1959,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
&rna_prop,
&rna_enum,
&rna_ctxt,
- NULL);
+ nullptr);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "lang", uilng);
@@ -1676,7 +1974,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo);
RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo);
RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo);
- const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL);
+ const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr);
/* Clean up */
if (but_label.strinfo) {
@@ -1736,7 +2034,7 @@ static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
BLT_lang_init();
BLF_cache_clear();
- BLT_lang_set(NULL);
+ BLT_lang_set(nullptr);
UI_reinit_font();
return OPERATOR_FINISHED;
}
@@ -1763,13 +2061,13 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
ARegion *region_prev = CTX_wm_region(C);
- ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL;
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : nullptr;
- if (region == NULL) {
+ if (region == nullptr) {
region = region_prev;
}
- if (region == NULL) {
+ if (region == nullptr) {
return OPERATOR_PASS_THROUGH;
}
@@ -1777,7 +2075,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
uiBut *but = UI_context_active_but_get(C);
CTX_wm_region_set(C, region_prev);
- if (but == NULL) {
+ if (but == nullptr) {
return OPERATOR_PASS_THROUGH;
}
if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) {
@@ -1790,7 +2088,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
UI_but_execute(C, region, but);
- but->optype = but_optype;
+ but->optype = static_cast<wmOperatorType *>(but_optype);
WM_event_add_mousemove(CTX_wm_window(C));
@@ -1806,7 +2104,7 @@ static void UI_OT_button_execute(wmOperatorType *ot)
ot->invoke = ui_button_press_invoke;
ot->flag = OPTYPE_INTERNAL;
- RNA_def_boolean(ot->srna, "skip_depressed", 0, "Skip Depressed", "");
+ RNA_def_boolean(ot->srna, "skip_depressed", false, "Skip Depressed", "");
}
/** \} */
@@ -1852,21 +2150,21 @@ bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(
ARegion *region = CTX_wm_region(C);
if (UI_but_active_drop_color(C)) {
- return 1;
+ return true;
}
if (sima && (sima->mode == SI_MODE_PAINT) && sima->image &&
(region && region->regiontype == RGN_TYPE_WINDOW)) {
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
{
- uiDragColorHandle *drag_info = drag->poin;
+ uiDragColorHandle *drag_info = static_cast<uiDragColorHandle *>(drag->poin);
RNA_float_set_array(drop->ptr, "color", drag_info->color);
RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
@@ -1875,7 +2173,7 @@ void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
- uiBut *but = NULL;
+ uiBut *but = nullptr;
float color[4];
bool gamma;
@@ -1932,8 +2230,10 @@ static void UI_OT_drop_color(wmOperatorType *ot)
ot->invoke = drop_color_invoke;
ot->flag = OPTYPE_INTERNAL;
- RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
- RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected");
+ RNA_def_float_color(
+ ot->srna, "color", 3, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
+ RNA_def_boolean(
+ ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected");
}
/** \} */
@@ -1963,7 +2263,7 @@ static bool drop_name_poll(bContext *C)
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiBut *but = UI_but_active_drop_name_button(C);
- char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL);
+ char *str = RNA_string_get_alloc(op->ptr, "string", nullptr, 0, nullptr);
if (str) {
ui_but_set_string_interactive(C, but, str);
@@ -1984,7 +2284,7 @@ static void UI_OT_drop_name(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(
- ot->srna, "string", NULL, 0, "String", "The string value to drop into the button");
+ ot->srna, "string", nullptr, 0, "String", "The string value to drop into the button");
}
/** \} */
@@ -2002,7 +2302,7 @@ static bool ui_list_focused_poll(bContext *C)
const wmWindow *win = CTX_wm_window(C);
const uiList *list = UI_list_find_mouse_over(region, win->eventstate);
- return list != NULL;
+ return list != nullptr;
}
/**
@@ -2025,7 +2325,7 @@ static int ui_list_start_filter_invoke(bContext *C, wmOperator *UNUSED(op), cons
ARegion *region = CTX_wm_region(C);
uiList *list = UI_list_find_mouse_over(region, event);
/* Poll should check. */
- BLI_assert(list != NULL);
+ BLI_assert(list != nullptr);
if (ui_list_unhide_filter_options(list)) {
ui_region_redraw_immediately(C, region);
@@ -2054,40 +2354,43 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
/** \name UI Tree-View Drop Operator
* \{ */
-static bool ui_tree_view_drop_poll(bContext *C)
+static bool ui_view_drop_poll(bContext *C)
{
const wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
- const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
- region, win->eventstate->xy);
+ if (region == nullptr) {
+ return false;
+ }
+ const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, win->eventstate->xy);
- return hovered_tree_item != NULL;
+ return hovered_item != nullptr;
}
-static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int ui_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
if (event->custom != EVT_DATA_DRAGDROP) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
const ARegion *region = CTX_wm_region(C);
- uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, event->xy);
+ uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy);
- if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) {
+ if (!UI_view_item_drop_handle(
+ C, hovered_item, static_cast<const ListBase *>(event->customdata))) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
return OPERATOR_FINISHED;
}
-static void UI_OT_tree_view_drop(wmOperatorType *ot)
+static void UI_OT_view_drop(wmOperatorType *ot)
{
- ot->name = "Tree View drop";
- ot->idname = "UI_OT_tree_view_drop";
- ot->description = "Drag and drop items onto a tree item";
+ ot->name = "View drop";
+ ot->idname = "UI_OT_view_drop";
+ ot->description = "Drag and drop items onto a data-set item";
- ot->invoke = ui_tree_view_drop_invoke;
- ot->poll = ui_tree_view_drop_poll;
+ ot->invoke = ui_view_drop_invoke;
+ ot->poll = ui_view_drop_poll;
ot->flag = OPTYPE_INTERNAL;
}
@@ -2095,43 +2398,45 @@ static void UI_OT_tree_view_drop(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name UI Tree-View Item Rename Operator
+/** \name UI View Item Rename Operator
*
- * General purpose renaming operator for tree-views. Thanks to this, to add a rename button to
- * context menus for example, tree-view API users don't have to implement their own renaming
- * operators with the same logic as they already have for their #ui::AbstractTreeViewItem::rename()
- * override.
+ * General purpose renaming operator for views. Thanks to this, to add a rename button to context
+ * menus for example, view API users don't have to implement their own renaming operators with the
+ * same logic as they already have for their #ui::AbstractViewItem::rename() override.
*
* \{ */
-static bool ui_tree_view_item_rename_poll(bContext *C)
+static bool ui_view_item_rename_poll(bContext *C)
{
const ARegion *region = CTX_wm_region(C);
- const uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region);
- return active_item != NULL && UI_tree_view_item_can_rename(active_item);
+ if (region == nullptr) {
+ return false;
+ }
+ const uiViewItemHandle *active_item = UI_region_views_find_active_item(region);
+ return active_item != nullptr && UI_view_item_can_rename(active_item);
}
-static int ui_tree_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op))
+static int ui_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op))
{
ARegion *region = CTX_wm_region(C);
- uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region);
+ uiViewItemHandle *active_item = UI_region_views_find_active_item(region);
- UI_tree_view_item_begin_rename(active_item);
+ UI_view_item_begin_rename(active_item);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
}
-static void UI_OT_tree_view_item_rename(wmOperatorType *ot)
+static void UI_OT_view_item_rename(wmOperatorType *ot)
{
- ot->name = "Rename Tree-View Item";
- ot->idname = "UI_OT_tree_view_item_rename";
- ot->description = "Rename the active item in the tree";
+ ot->name = "Rename View Item";
+ ot->idname = "UI_OT_view_item_rename";
+ ot->description = "Rename the active item in the data-set view";
- ot->exec = ui_tree_view_item_rename_exec;
- ot->poll = ui_tree_view_item_rename_poll;
+ ot->exec = ui_view_item_rename_exec;
+ ot->poll = ui_view_item_rename_poll;
/* Could get a custom tooltip via the `get_description()` callback and another overridable
- * function of the tree-view. */
+ * function of the view. */
ot->flag = OPTYPE_INTERNAL;
}
@@ -2145,8 +2450,8 @@ static void UI_OT_tree_view_item_rename(wmOperatorType *ot)
static bool ui_drop_material_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
- Object *ob = ptr.data;
- if (ob == NULL) {
+ const Object *ob = static_cast<const Object *>(ptr.data);
+ if (ob == nullptr) {
return false;
}
@@ -2164,12 +2469,12 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op)
Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid(
bmain, op->ptr, ID_MA);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
- Object *ob = ptr.data;
+ Object *ob = static_cast<Object *>(ptr.data);
BLI_assert(ob);
PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
@@ -2177,14 +2482,14 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op)
const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1;
/* only drop grease pencil material on grease pencil objects */
- if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) {
+ if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
BKE_object_material_assign(bmain, ob, ma, target_slot, BKE_MAT_ASSIGN_USERPREF);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
@@ -2218,8 +2523,6 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_reset_default_button);
WM_operatortype_append(UI_OT_assign_default_button);
WM_operatortype_append(UI_OT_unset_property_button);
- WM_operatortype_append(UI_OT_override_type_set_button);
- WM_operatortype_append(UI_OT_override_remove_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_jump_to_target_button);
WM_operatortype_append(UI_OT_drop_color);
@@ -2235,8 +2538,15 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_list_start_filter);
- WM_operatortype_append(UI_OT_tree_view_drop);
- WM_operatortype_append(UI_OT_tree_view_item_rename);
+ WM_operatortype_append(UI_OT_view_drop);
+ WM_operatortype_append(UI_OT_view_item_rename);
+
+ WM_operatortype_append(UI_OT_override_type_set_button);
+ WM_operatortype_append(UI_OT_override_remove_button);
+ WM_operatortype_append(UI_OT_override_idtemplate_make);
+ WM_operatortype_append(UI_OT_override_idtemplate_reset);
+ WM_operatortype_append(UI_OT_override_idtemplate_clear);
+ override_idtemplate_menu();
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.cc
index 87bfb7ca0f7..745a2201dc1 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.cc
@@ -8,10 +8,10 @@
/* a full doc with API notes can be found in
* bf-blender/trunk/blender/doc/guides/interface_API.txt */
-#include <ctype.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cctype>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -57,7 +57,7 @@
#define ANIMATION_TIME 0.30
#define ANIMATION_INTERVAL 0.02
-typedef enum uiPanelRuntimeFlag {
+enum uiPanelRuntimeFlag {
PANEL_LAST_ADDED = (1 << 0),
PANEL_ACTIVE = (1 << 2),
PANEL_WAS_ACTIVE = (1 << 3),
@@ -78,22 +78,22 @@ typedef enum uiPanelRuntimeFlag {
PANEL_IS_DRAG_DROP = (1 << 10),
/** Draw a border with the active color around the panel. */
PANEL_ACTIVE_BORDER = (1 << 11),
-} uiPanelRuntimeFlag;
+};
/* The state of the mouse position relative to the panel. */
-typedef enum uiPanelMouseState {
+enum uiPanelMouseState {
PANEL_MOUSE_OUTSIDE, /** Mouse is not in the panel. */
PANEL_MOUSE_INSIDE_CONTENT, /** Mouse is in the actual panel content. */
PANEL_MOUSE_INSIDE_HEADER, /** Mouse is in the panel header. */
-} uiPanelMouseState;
+};
-typedef enum uiHandlePanelState {
+enum uiHandlePanelState {
PANEL_STATE_DRAG,
PANEL_STATE_ANIMATION,
PANEL_STATE_EXIT,
-} uiHandlePanelState;
+};
-typedef struct uiHandlePanelData {
+struct uiHandlePanelData {
uiHandlePanelState state;
/* Animation. */
@@ -104,17 +104,17 @@ typedef struct uiHandlePanelData {
int startx, starty;
int startofsx, startofsy;
float start_cur_xmin, start_cur_ymin;
-} uiHandlePanelData;
+};
-typedef struct PanelSort {
+struct PanelSort {
Panel *panel;
int new_offset_x;
int new_offset_y;
-} PanelSort;
+};
static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel);
static int get_panel_real_size_y(const Panel *panel);
-static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state);
+static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state);
static int compare_panel(const void *a, const void *b);
static bool panel_type_context_poll(ARegion *region,
const PanelType *panel_type,
@@ -155,7 +155,7 @@ static bool panel_active_animation_changed(ListBase *lb,
/* Detect animation. */
if (panel->activedata) {
- uiHandlePanelData *data = panel->activedata;
+ uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata);
if (data->state == PANEL_STATE_ANIMATION) {
*r_panel_animation = panel;
}
@@ -178,7 +178,7 @@ static bool panel_active_animation_changed(ListBase *lb,
static bool properties_space_needs_realign(const ScrArea *area, const ARegion *region)
{
if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
- SpaceProperties *sbuts = area->spacedata.first;
+ const SpaceProperties *sbuts = static_cast<SpaceProperties *>(area->spacedata.first);
if (sbuts->mainbo != sbuts->mainb) {
return true;
@@ -190,14 +190,14 @@ static bool properties_space_needs_realign(const ScrArea *area, const ARegion *r
static bool panels_need_realign(const ScrArea *area, ARegion *region, Panel **r_panel_animation)
{
- *r_panel_animation = NULL;
+ *r_panel_animation = nullptr;
if (properties_space_needs_realign(area, region)) {
return true;
}
/* Detect if a panel was added or removed. */
- Panel *panel_animation = NULL;
+ Panel *panel_animation = nullptr;
bool no_animation = false;
if (panel_active_animation_changed(&region->panels, &panel_animation, &no_animation)) {
return true;
@@ -225,7 +225,7 @@ static Panel *panel_add_instanced(ARegion *region,
PanelType *panel_type,
PointerRNA *custom_data)
{
- Panel *panel = MEM_callocN(sizeof(Panel), __func__);
+ Panel *panel = MEM_cnew<Panel>(__func__);
panel->type = panel_type;
BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
@@ -235,7 +235,7 @@ static Panel *panel_add_instanced(ARegion *region,
/* Add the panel's children too. Although they aren't instanced panels, we can still use this
* function to create them, as UI_panel_begin does other things we don't need to do. */
LISTBASE_FOREACH (LinkData *, child, &panel_type->children) {
- PanelType *child_type = child->data;
+ PanelType *child_type = static_cast<PanelType *>(child->data);
panel_add_instanced(region, &panel->children, child_type, custom_data);
}
@@ -265,12 +265,12 @@ Panel *UI_panel_add_instanced(const bContext *C,
{
ARegionType *region_type = region->type;
- PanelType *panel_type = BLI_findstring(
- &region_type->paneltypes, panel_idname, offsetof(PanelType, idname));
+ PanelType *panel_type = static_cast<PanelType *>(
+ BLI_findstring(&region_type->paneltypes, panel_idname, offsetof(PanelType, idname)));
- if (panel_type == NULL) {
+ if (panel_type == nullptr) {
printf("Panel type '%s' not found.\n", panel_idname);
- return NULL;
+ return nullptr;
}
Panel *new_panel = panel_add_instanced(region, panels, panel_type, custom_data);
@@ -314,14 +314,14 @@ void UI_panels_free_instanced(const bContext *C, ARegion *region)
{
/* Delete panels with the instanced flag. */
LISTBASE_FOREACH_MUTABLE (Panel *, panel, &region->panels) {
- if ((panel->type != NULL) && (panel->type->flag & PANEL_TYPE_INSTANCED)) {
+ if ((panel->type != nullptr) && (panel->type->flag & PANEL_TYPE_INSTANCED)) {
/* Make sure the panel's handler is removed before deleting it. */
- if (C != NULL && panel->activedata != NULL) {
+ if (C != nullptr && panel->activedata != nullptr) {
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
/* Free panel's custom data. */
- if (panel->runtime.custom_data_ptr != NULL) {
+ if (panel->runtime.custom_data_ptr != nullptr) {
MEM_freeN(panel->runtime.custom_data_ptr);
}
@@ -335,28 +335,28 @@ bool UI_panel_list_matches_data(ARegion *region,
ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func)
{
- /* Check for NULL data. */
+ /* Check for nullptr data. */
int data_len = 0;
- Link *data_link = NULL;
- if (data == NULL) {
+ Link *data_link = nullptr;
+ if (data == nullptr) {
data_len = 0;
- data_link = NULL;
+ data_link = nullptr;
}
else {
data_len = BLI_listbase_count(data);
- data_link = data->first;
+ data_link = static_cast<Link *>(data->first);
}
int i = 0;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
- if (panel->type != NULL && panel->type->flag & PANEL_TYPE_INSTANCED) {
+ if (panel->type != nullptr && panel->type->flag & PANEL_TYPE_INSTANCED) {
/* The panels were reordered by drag and drop. */
if (panel->flag & PNL_INSTANCED_LIST_ORDER_CHANGED) {
return false;
}
/* We reached the last data item before the last instanced panel. */
- if (data_link == NULL) {
+ if (data_link == nullptr) {
return false;
}
@@ -383,15 +383,15 @@ bool UI_panel_list_matches_data(ARegion *region,
static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel)
{
/* Without a type we cannot access the reorder callback. */
- if (drag_panel->type == NULL) {
+ if (drag_panel->type == nullptr) {
return;
}
/* Don't reorder if this instanced panel doesn't support drag and drop reordering. */
- if (drag_panel->type->reorder == NULL) {
+ if (drag_panel->type->reorder == nullptr) {
return;
}
- char *context = NULL;
+ char *context = nullptr;
if (!UI_panel_category_is_visible(region)) {
context = drag_panel->type->context;
}
@@ -415,7 +415,8 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
BLI_assert(start_index != -1); /* The drag panel should definitely be in the list. */
/* Sort the matching instanced panels by their display order. */
- PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__);
+ PanelSort *panel_sort = static_cast<PanelSort *>(
+ MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__));
PanelSort *sort_index = panel_sort;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->type) {
@@ -452,7 +453,7 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
/* Finally, move this panel's list item to the new index in its list. */
drag_panel->type->reorder(C, drag_panel, move_to_index);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
}
/**
@@ -480,9 +481,9 @@ static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag,
*/
static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel)
{
- BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type != nullptr);
BLI_assert(panel->type->flag & PANEL_TYPE_INSTANCED);
- if (panel->type->get_list_data_expand_flag == NULL) {
+ if (panel->type->get_list_data_expand_flag == nullptr) {
/* Instanced panel doesn't support loading expansion. */
return;
}
@@ -504,7 +505,7 @@ static void region_panels_set_expansion_from_list_data(const bContext *C, ARegio
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->runtime_flag & PANEL_ACTIVE) {
PanelType *panel_type = panel->type;
- if (panel_type != NULL && panel->type->flag & PANEL_TYPE_INSTANCED) {
+ if (panel_type != nullptr && panel->type->flag & PANEL_TYPE_INSTANCED) {
panel_set_expansion_from_list_data(C, panel);
}
}
@@ -537,7 +538,7 @@ static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *r
{
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
PanelType *panel_type = panel->type;
- if (panel_type == NULL) {
+ if (panel_type == nullptr) {
continue;
}
@@ -563,11 +564,11 @@ static bool panel_custom_data_active_get(const Panel *panel)
{
/* The caller should make sure the panel is active and has a type. */
BLI_assert(UI_panel_is_active(panel));
- BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type != nullptr);
if (panel->type->active_property[0] != '\0') {
PointerRNA *ptr = UI_panel_custom_data_get(panel);
- if (ptr != NULL && !RNA_pointer_is_null(ptr)) {
+ if (ptr != nullptr && !RNA_pointer_is_null(ptr)) {
return RNA_boolean_get(ptr, panel->type->active_property);
}
}
@@ -579,12 +580,12 @@ static void panel_custom_data_active_set(Panel *panel)
{
/* Since the panel is interacted with, it should be active and have a type. */
BLI_assert(UI_panel_is_active(panel));
- BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type != nullptr);
if (panel->type->active_property[0] != '\0') {
PointerRNA *ptr = UI_panel_custom_data_get(panel);
- BLI_assert(RNA_struct_find_property(ptr, panel->type->active_property) != NULL);
- if (ptr != NULL && !RNA_pointer_is_null(ptr)) {
+ BLI_assert(RNA_struct_find_property(ptr, panel->type->active_property) != nullptr);
+ if (ptr != nullptr && !RNA_pointer_is_null(ptr)) {
RNA_boolean_set(ptr, panel->type->active_property, true);
}
}
@@ -617,7 +618,7 @@ static void panel_set_runtime_flag_recursive(Panel *panel, short flag, bool valu
static void panels_collapse_all(ARegion *region, const Panel *from_panel)
{
const bool has_category_tabs = UI_panel_category_is_visible(region);
- const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL;
+ const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : nullptr;
const PanelType *from_pt = from_panel->type;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
@@ -659,7 +660,7 @@ Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt)
return panel;
}
}
- return NULL;
+ return nullptr;
}
Panel *UI_panel_begin(
@@ -668,10 +669,10 @@ Panel *UI_panel_begin(
Panel *panel_last;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
const char *idname = pt->idname;
- const bool newpanel = (panel == NULL);
+ const bool newpanel = (panel == nullptr);
if (newpanel) {
- panel = MEM_callocN(sizeof(Panel), __func__);
+ panel = MEM_cnew<Panel>(__func__);
panel->type = pt;
BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname));
@@ -701,7 +702,7 @@ Panel *UI_panel_begin(
/* If a new panel is added, we insert it right after the panel that was last added.
* This way new panels are inserted in the right place between versions. */
- for (panel_last = lb->first; panel_last; panel_last = panel_last->next) {
+ for (panel_last = static_cast<Panel *>(lb->first); panel_last; panel_last = panel_last->next) {
if (panel_last->runtime_flag & PANEL_LAST_ADDED) {
BLI_remlink(lb, panel);
BLI_insertlinkafter(lb, panel_last, panel);
@@ -755,7 +756,7 @@ void UI_panel_header_buttons_end(Panel *panel)
/* A button group should always be created in #UI_panel_header_buttons_begin. */
BLI_assert(!BLI_listbase_is_empty(&block->button_groups));
- uiButtonGroup *button_group = block->button_groups.last;
+ uiButtonGroup *button_group = static_cast<uiButtonGroup *>(block->button_groups.last);
button_group->flag &= ~UI_BUTTON_GROUP_LOCK;
@@ -770,7 +771,7 @@ void UI_panel_header_buttons_end(Panel *panel)
/* Always add a new button group. Although this may result in many empty groups, without it,
* new buttons in the panel body not protected with a #ui_block_new_button_group call would
* end up in the panel header group. */
- ui_block_new_button_group(block, 0);
+ ui_block_new_button_group(block, (uiButtonGroupFlag)0);
}
}
@@ -867,7 +868,7 @@ void ui_panel_tag_search_filter_match(Panel *panel)
static void panel_matches_search_filter_recursive(const Panel *panel, bool *filter_matches)
{
- *filter_matches |= panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH;
+ *filter_matches |= bool(panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH);
/* If the panel has no match we need to make sure that its children are too. */
if (!*filter_matches) {
@@ -893,7 +894,7 @@ static void panel_set_expansion_from_search_filter_recursive(const bContext *C,
{
/* This has to run on inactive panels that may not have a type,
* but we can prevent running on header-less panels in some cases. */
- if (panel->type == NULL || !(panel->type->flag & PANEL_TYPE_NO_HEADER)) {
+ if (panel->type == nullptr || !(panel->type->flag & PANEL_TYPE_NO_HEADER)) {
SET_FLAG_FROM_TEST(panel->runtime_flag, use_search_closed, PANEL_USE_CLOSED_FROM_SEARCH);
}
@@ -926,9 +927,9 @@ static void region_panels_set_expansion_from_search_filter(const bContext *C,
static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *parent_panel)
{
uiBlock *block = panel->runtime.block;
- BLI_assert(block != NULL);
+ BLI_assert(block != nullptr);
BLI_assert(block->active);
- if (parent_panel != NULL && UI_panel_is_closed(parent_panel)) {
+ if (parent_panel != nullptr && UI_panel_is_closed(parent_panel)) {
/* The parent panel is closed, so this panel can be completely removed. */
UI_block_set_search_only(block, true);
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
@@ -944,7 +945,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *
continue;
}
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
- uiBut *but = link->data;
+ uiBut *but = static_cast<uiBut *>(link->data);
but->flag |= UI_HIDDEN;
}
}
@@ -952,7 +953,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *
LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
if (child_panel->runtime_flag & PANEL_ACTIVE) {
- BLI_assert(child_panel->runtime.block != NULL);
+ BLI_assert(child_panel->runtime.block != nullptr);
panel_remove_invisible_layouts_recursive(child_panel, panel);
}
}
@@ -962,8 +963,8 @@ static void region_panels_remove_invisible_layouts(ARegion *region)
{
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->runtime_flag & PANEL_ACTIVE) {
- BLI_assert(panel->runtime.block != NULL);
- panel_remove_invisible_layouts_recursive(panel, NULL);
+ BLI_assert(panel->runtime.block != nullptr);
+ panel_remove_invisible_layouts_recursive(panel, nullptr);
}
}
}
@@ -1054,7 +1055,7 @@ static void panel_draw_highlight_border(const Panel *panel,
const rcti *rect,
const rcti *header_rect)
{
- const bool is_subpanel = panel->type->parent != NULL;
+ const bool is_subpanel = panel->type->parent != nullptr;
if (is_subpanel) {
return;
}
@@ -1064,18 +1065,15 @@ static void panel_draw_highlight_border(const Panel *panel,
const float radius = (btheme->tui.panel_roundness * U.widget_unit * 0.5f) / aspect;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ rctf box_rect;
+ box_rect.xmin = rect->xmin;
+ box_rect.xmax = rect->xmax;
+ box_rect.ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin;
+ box_rect.ymax = header_rect->ymax;
+
float color[4];
UI_GetThemeColor4fv(TH_SELECT_ACTIVE, color);
- UI_draw_roundbox_4fv(
- &(const rctf){
- .xmin = rect->xmin,
- .xmax = rect->xmax,
- .ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin,
- .ymax = header_rect->ymax,
- },
- false,
- radius,
- color);
+ UI_draw_roundbox_4fv(&box_rect, false, radius, color);
}
static void panel_draw_aligned_widgets(const uiStyle *style,
@@ -1086,19 +1084,18 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
const bool show_background,
const bool region_search_filter_active)
{
- const bool is_subpanel = panel->type->parent != NULL;
+ const bool is_subpanel = panel->type->parent != nullptr;
const uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
const int header_height = BLI_rcti_size_y(header_rect);
const int scaled_unit = round_fl_to_int(UI_UNIT_X / aspect);
- /* Offset triangle and text to the right for subpanels. */
- const rcti widget_rect = {
- .xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0),
- .xmax = header_rect->xmax,
- .ymin = header_rect->ymin,
- .ymax = header_rect->ymax,
- };
+ /* Offset triangle and text to the right for sub-panels. */
+ rcti widget_rect;
+ widget_rect.xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0);
+ widget_rect.xmax = header_rect->xmax;
+ widget_rect.ymin = header_rect->ymin;
+ widget_rect.ymax = header_rect->ymax;
uchar title_color[4];
panel_title_color_get(panel, show_background, region_search_filter_active, title_color);
@@ -1121,20 +1118,16 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
/* Draw text label. */
if (panel->drawname[0] != '\0') {
- const rcti title_rect = {
- .xmin = widget_rect.xmin + (panel->labelofs / aspect) + scaled_unit * 1.1f,
- .xmax = widget_rect.xmax,
- .ymin = widget_rect.ymin - 2.0f / aspect,
- .ymax = widget_rect.ymax,
- };
- UI_fontstyle_draw(fontstyle,
- &title_rect,
- panel->drawname,
- sizeof(panel->drawname),
- title_color,
- &(struct uiFontStyleDraw_Params){
- .align = UI_STYLE_TEXT_LEFT,
- });
+ rcti title_rect;
+ title_rect.xmin = widget_rect.xmin + (panel->labelofs / aspect) + scaled_unit * 1.1f;
+ title_rect.xmax = widget_rect.xmax;
+ title_rect.ymin = widget_rect.ymin - 2.0f / aspect;
+ title_rect.ymax = widget_rect.ymax;
+
+ uiFontStyleDraw_Params params{};
+ params.align = UI_STYLE_TEXT_LEFT;
+ UI_fontstyle_draw(
+ fontstyle, &title_rect, panel->drawname, sizeof(panel->drawname), title_color, &params);
}
/* Draw the pin icon. */
@@ -1167,7 +1160,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
GPUBatch *batch = GPU_batch_preset_panel_drag_widget(
U.pixelsize, color_high, color_dark, drag_widget_size);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR);
GPU_batch_draw(batch);
GPU_matrix_pop();
}
@@ -1177,7 +1170,7 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
const rcti *rect,
const rcti *header_rect)
{
- const bool is_subpanel = panel->type->parent != NULL;
+ const bool is_subpanel = panel->type->parent != nullptr;
const bool is_open = !UI_panel_is_closed(panel);
if (is_subpanel && !is_open) {
@@ -1188,7 +1181,7 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
const float aspect = panel->runtime.block->aspect;
const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f / aspect;
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
/* Panel backdrop. */
@@ -1197,16 +1190,12 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
UI_draw_roundbox_corner_set(is_open ? UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT : UI_CNR_ALL);
UI_GetThemeColor4fv((is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK), panel_backcolor);
- UI_draw_roundbox_4fv(
- &(const rctf){
- .xmin = rect->xmin,
- .xmax = rect->xmax,
- .ymin = rect->ymin,
- .ymax = rect->ymax,
- },
- true,
- radius,
- panel_backcolor);
+ rctf box_rect;
+ box_rect.xmin = rect->xmin;
+ box_rect.xmax = rect->xmax;
+ box_rect.ymin = rect->ymin;
+ box_rect.ymax = rect->ymax;
+ UI_draw_roundbox_4fv(&box_rect, true, radius, panel_backcolor);
}
/* Panel header backdrops for non sub-panels. */
@@ -1217,16 +1206,12 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
UI_draw_roundbox_corner_set(is_open ? UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT : UI_CNR_ALL);
/* Change the width a little bit to line up with the sides. */
- UI_draw_roundbox_4fv(
- &(const rctf){
- .xmin = rect->xmin,
- .xmax = rect->xmax,
- .ymin = header_rect->ymin,
- .ymax = header_rect->ymax,
- },
- true,
- radius,
- panel_headercolor);
+ rctf box_rect;
+ box_rect.xmin = rect->xmin;
+ box_rect.xmax = rect->xmax;
+ box_rect.ymin = header_rect->ymin;
+ box_rect.ymax = header_rect->ymax;
+ UI_draw_roundbox_4fv(&box_rect, true, radius, panel_headercolor);
}
GPU_blend(GPU_BLEND_NONE);
@@ -1247,7 +1232,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
rect->xmin,
rect->xmax,
rect->ymax,
- rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f),
+ rect->ymax + (int)floor(PNL_HEADER / block->aspect + 0.001f),
};
if (show_background) {
@@ -1300,7 +1285,7 @@ bool UI_panel_should_show_background(const ARegion *region, const PanelType *pan
void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
// #define USE_FLAT_INACTIVE
- const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT);
+ const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT;
View2D *v2d = &region->v2d;
const uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
@@ -1399,7 +1384,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw the background. */
if (is_alpha) {
@@ -1444,7 +1429,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
if (is_active == false && is_active_prev == false && pc_dyn->prev) {
pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fvAlpha(theme_col_tab_outline, 0.3f);
immRecti(pos,
is_left ? v2d->mask.xmin + (category_tabs_width / 5) :
@@ -1463,31 +1448,22 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
/* Draw filled rectangle and outline for tab. */
UI_draw_roundbox_corner_set(roundboxtype);
- UI_draw_roundbox_4fv(
- &(const rctf){
- .xmin = rct->xmin,
- .xmax = rct->xmax,
- .ymin = rct->ymin,
- .ymax = rct->ymax,
- },
- true,
- tab_curve_radius,
- is_active ? theme_col_tab_active : theme_col_tab_inactive);
- UI_draw_roundbox_4fv(
- &(const rctf){
- .xmin = rct->xmin,
- .xmax = rct->xmax,
- .ymin = rct->ymin,
- .ymax = rct->ymax,
- },
- false,
- tab_curve_radius,
- theme_col_tab_outline);
+ rctf box_rect;
+ box_rect.xmin = rct->xmin;
+ box_rect.xmax = rct->xmax;
+ box_rect.ymin = rct->ymin;
+ box_rect.ymax = rct->ymax;
+
+ UI_draw_roundbox_4fv(&box_rect,
+ true,
+ tab_curve_radius,
+ is_active ? theme_col_tab_active : theme_col_tab_inactive);
+ UI_draw_roundbox_4fv(&box_rect, false, tab_curve_radius, theme_col_tab_outline);
/* Disguise the outline on one side to join the tab to the panel. */
pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(is_active ? theme_col_tab_active : theme_col_tab_inactive);
immRecti(pos,
@@ -1502,7 +1478,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
if (do_scaletabs) {
category_draw_len = BLF_width_to_strlen(
- fontid, category_id_draw, category_draw_len, category_width, NULL);
+ fontid, category_id_draw, category_draw_len, category_width, nullptr);
}
BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f);
@@ -1660,7 +1636,7 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->runtime_flag & PANEL_ACTIVE) {
/* These panels should have types since they are currently displayed to the user. */
- BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type != nullptr);
active_panels_len++;
}
}
@@ -1669,7 +1645,8 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra
}
/* Sort panels. */
- PanelSort *panel_sort = MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__);
+ PanelSort *panel_sort = static_cast<PanelSort *>(
+ MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__));
{
PanelSort *ps = panel_sort;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
@@ -1791,7 +1768,7 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
static void ui_do_animate(bContext *C, Panel *panel)
{
- uiHandlePanelData *data = panel->activedata;
+ uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata);
ARegion *region = CTX_wm_region(C);
float fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME;
@@ -1856,7 +1833,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->runtime_flag & PANEL_ACTIVE) {
- BLI_assert(panel->runtime.block != NULL);
+ BLI_assert(panel->runtime.block != nullptr);
panel_calculate_size_recursive(region, panel);
}
}
@@ -1892,7 +1869,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
#define DRAG_REGION_PAD (PNL_HEADER * 0.5)
static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
{
- uiHandlePanelData *data = panel->activedata;
+ uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata);
ARegion *region = CTX_wm_region(C);
/* Keep the drag position in the region with a small pad to keep the panel visible. */
@@ -1942,14 +1919,14 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
return PANEL_MOUSE_OUTSIDE;
}
-typedef struct uiPanelDragCollapseHandle {
+struct uiPanelDragCollapseHandle {
bool was_first_open;
int xy_init[2];
-} uiPanelDragCollapseHandle;
+};
static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata)
{
- uiPanelDragCollapseHandle *dragcol_data = userdata;
+ uiPanelDragCollapseHandle *dragcol_data = static_cast<uiPanelDragCollapseHandle *>(userdata);
MEM_freeN(dragcol_data);
}
@@ -1960,11 +1937,11 @@ static void ui_panel_drag_collapse(const bContext *C,
ARegion *region = CTX_wm_region(C);
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
- float xy_b_block[2] = {UNPACK2(xy_dst)};
+ float xy_a_block[2] = {(float)dragcol_data->xy_init[0], (float)dragcol_data->xy_init[1]};
+ float xy_b_block[2] = {(float)xy_dst[0], (float)xy_dst[1]};
Panel *panel = block->panel;
- if (panel == NULL || (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER))) {
+ if (panel == nullptr || (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER))) {
continue;
}
const int oldflag = panel->flag;
@@ -2006,7 +1983,7 @@ static void ui_panel_drag_collapse(const bContext *C,
static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata)
{
wmWindow *win = CTX_wm_window(C);
- uiPanelDragCollapseHandle *dragcol_data = userdata;
+ uiPanelDragCollapseHandle *dragcol_data = static_cast<uiPanelDragCollapseHandle *>(userdata);
short retval = WM_UI_HANDLER_CONTINUE;
switch (event->type) {
@@ -2037,7 +2014,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
{
wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win->eventstate;
- uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
+ uiPanelDragCollapseHandle *dragcol_data = MEM_new<uiPanelDragCollapseHandle>(__func__);
dragcol_data->was_first_open = was_open;
copy_v2_v2_int(dragcol_data->xy_init, event->xy);
@@ -2066,10 +2043,10 @@ static void ui_handle_panel_header(const bContext *C,
Panel *panel = block->panel;
ARegion *region = CTX_wm_region(C);
- BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type != nullptr);
BLI_assert(!(panel->type->flag & PANEL_TYPE_NO_HEADER));
- const bool is_subpanel = (panel->type->parent != NULL);
+ const bool is_subpanel = (panel->type->parent != nullptr);
const bool use_pin = UI_panel_category_is_visible(region) && UI_panel_can_be_pinned(panel);
const bool show_pin = use_pin && (panel->flag & PNL_PIN);
const bool show_drag = !is_subpanel;
@@ -2102,8 +2079,8 @@ static void ui_handle_panel_header(const bContext *C,
else {
/* If a panel has sub-panels and it's open, toggle the expansion
* of the sub-panels (based on the expansion of the first sub-panel). */
- Panel *first_child = panel->children.first;
- BLI_assert(first_child != NULL);
+ Panel *first_child = static_cast<Panel *>(panel->children.first);
+ BLI_assert(first_child != nullptr);
panel_set_flag_recursive(panel, PNL_CLOSED, !UI_panel_is_closed(first_child));
panel->flag |= PNL_CLOSED;
}
@@ -2115,7 +2092,7 @@ static void ui_handle_panel_header(const bContext *C,
ui_panel_drag_collapse_handler_add(C, UI_panel_is_closed(panel));
}
- /* Set panel custom data (modifier) active when expanding subpanels, but not top-level
+ /* Set panel custom data (modifier) active when expanding sub-panels, but not top-level
* panels to allow collapsing and expanding without setting the active element. */
if (is_subpanel) {
panel_custom_data_active_set(panel);
@@ -2157,13 +2134,14 @@ bool UI_panel_category_is_visible(const ARegion *region)
PanelCategoryDyn *UI_panel_category_find(const ARegion *region, const char *idname)
{
- return BLI_findstring(&region->panels_category, idname, offsetof(PanelCategoryDyn, idname));
+ return static_cast<PanelCategoryDyn *>(
+ BLI_findstring(&region->panels_category, idname, offsetof(PanelCategoryDyn, idname)));
}
PanelCategoryStack *UI_panel_category_active_find(ARegion *region, const char *idname)
{
- return BLI_findstring(
- &region->panels_category_active, idname, offsetof(PanelCategoryStack, idname));
+ return static_cast<PanelCategoryStack *>(BLI_findstring(
+ &region->panels_category_active, idname, offsetof(PanelCategoryStack, idname)));
}
static void ui_panel_category_active_set(ARegion *region, const char *idname, bool fallback)
@@ -2175,7 +2153,7 @@ static void ui_panel_category_active_set(ARegion *region, const char *idname, bo
BLI_remlink(lb, pc_act);
}
else {
- pc_act = MEM_callocN(sizeof(PanelCategoryStack), __func__);
+ pc_act = MEM_cnew<PanelCategoryStack>(__func__);
BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname));
}
@@ -2226,14 +2204,14 @@ const char *UI_panel_category_active_get(ARegion *region, bool set_fallback)
}
if (set_fallback) {
- PanelCategoryDyn *pc_dyn = region->panels_category.first;
+ PanelCategoryDyn *pc_dyn = static_cast<PanelCategoryDyn *>(region->panels_category.first);
if (pc_dyn) {
ui_panel_category_active_set(region, pc_dyn->idname, true);
return pc_dyn->idname;
}
}
- return NULL;
+ return nullptr;
}
static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const wmEvent *event)
@@ -2244,12 +2222,12 @@ static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const
}
}
- return NULL;
+ return nullptr;
}
void UI_panel_category_add(ARegion *region, const char *name)
{
- PanelCategoryDyn *pc_dyn = MEM_callocN(sizeof(*pc_dyn), __func__);
+ PanelCategoryDyn *pc_dyn = MEM_cnew<PanelCategoryDyn>(__func__);
BLI_addtail(&region->panels_category, pc_dyn);
BLI_strncpy(pc_dyn->idname, name, sizeof(pc_dyn->idname));
@@ -2294,7 +2272,8 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next;
if (!pc_dyn) {
/* Proper cyclic behavior, back to first/last category (only used for ctrl+tab). */
- pc_dyn = backwards ? region->panels_category.last : region->panels_category.first;
+ pc_dyn = backwards ? static_cast<PanelCategoryDyn *>(region->panels_category.last) :
+ static_cast<PanelCategoryDyn *>(region->panels_category.first);
}
}
@@ -2318,7 +2297,7 @@ int ui_handler_panel_region(bContext *C,
const uiBut *active_but)
{
/* Mouse-move events are handled by separate handlers for dragging and drag collapsing. */
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (ISMOUSE_MOTION(event->type)) {
return WM_UI_HANDLER_CONTINUE;
}
@@ -2359,11 +2338,11 @@ int ui_handler_panel_region(bContext *C,
return retval;
}
- const bool region_has_active_button = (ui_region_find_active_but(region) != NULL);
+ const bool region_has_active_button = (ui_region_find_active_but(region) != nullptr);
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
Panel *panel = block->panel;
- if (panel == NULL || panel->type == NULL) {
+ if (panel == nullptr || panel->type == nullptr) {
continue;
}
/* We can't expand or collapse panels without headers, they would disappear. */
@@ -2434,10 +2413,10 @@ void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *pt
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
{
- BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type != nullptr);
/* Free the old custom data, which should be shared among all of the panel's sub-panels. */
- if (panel->runtime.custom_data_ptr != NULL) {
+ if (panel->runtime.custom_data_ptr != nullptr) {
MEM_freeN(panel->runtime.custom_data_ptr);
}
@@ -2455,7 +2434,7 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
Panel *panel = block->panel;
- if (panel == NULL) {
+ if (panel == nullptr) {
continue;
}
@@ -2468,12 +2447,12 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm
}
}
- return NULL;
+ return nullptr;
}
bool UI_panel_can_be_pinned(const Panel *panel)
{
- return (panel->type->parent == NULL) && !(panel->type->flag & PANEL_TYPE_INSTANCED);
+ return (panel->type->parent == nullptr) && !(panel->type->flag & PANEL_TYPE_INSTANCED);
}
/** \} */
@@ -2485,8 +2464,8 @@ bool UI_panel_can_be_pinned(const Panel *panel)
/* NOTE: this is modal handler and should not swallow events for animation. */
static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
{
- Panel *panel = userdata;
- uiHandlePanelData *data = panel->activedata;
+ Panel *panel = static_cast<Panel *>(userdata);
+ uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata);
/* Verify if we can stop. */
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
@@ -2506,7 +2485,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
}
}
- data = panel->activedata;
+ data = static_cast<uiHandlePanelData *>(panel->activedata);
if (data && data->state == PANEL_STATE_ANIMATION) {
return WM_UI_HANDLER_CONTINUE;
@@ -2516,7 +2495,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
static void ui_handler_remove_panel(bContext *C, void *userdata)
{
- Panel *panel = userdata;
+ Panel *panel = static_cast<Panel *>(userdata);
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
@@ -2527,13 +2506,13 @@ static void panel_handle_data_ensure(const bContext *C,
Panel *panel,
const uiHandlePanelState state)
{
- if (panel->activedata == NULL) {
+ if (panel->activedata == nullptr) {
panel->activedata = MEM_callocN(sizeof(uiHandlePanelData), __func__);
WM_event_add_ui_handler(
C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0);
}
- uiHandlePanelData *data = panel->activedata;
+ uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata);
data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL);
@@ -2554,11 +2533,11 @@ static void panel_handle_data_ensure(const bContext *C,
*/
static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state)
{
- uiHandlePanelData *data = panel->activedata;
+ uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata);
wmWindow *win = CTX_wm_window(C);
ARegion *region = CTX_wm_region(C);
- if (data != NULL && data->state == state) {
+ if (data != nullptr && data->state == state) {
return;
}
@@ -2582,15 +2561,15 @@ static void panel_activate_state(const bContext *C, Panel *panel, const uiHandle
else if (state == PANEL_STATE_EXIT) {
panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, false);
- BLI_assert(data != NULL);
+ BLI_assert(data != nullptr);
if (data->animtimer) {
WM_event_remove_timer(CTX_wm_manager(C), win, data->animtimer);
- data->animtimer = NULL;
+ data->animtimer = nullptr;
}
MEM_freeN(data);
- panel->activedata = NULL;
+ panel->activedata = nullptr;
WM_event_remove_ui_handler(
&win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false);
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index 71cf60985df..f084f3e06cb 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -54,13 +54,7 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_TOGGLE_N,
UI_BTYPE_CHECKBOX,
UI_BTYPE_CHECKBOX_N,
- UI_BTYPE_ROW,
- UI_BTYPE_TREEROW);
-}
-
-bool ui_but_is_view_item(const uiBut *but)
-{
- return ELEM(but->type, UI_BTYPE_TREEROW, UI_BTYPE_GRID_TILE);
+ UI_BTYPE_ROW);
}
bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip)
@@ -462,14 +456,9 @@ uiBut *ui_list_row_find_from_index(const ARegion *region, const int index, uiBut
return ui_but_find(region, ui_but_is_listrow_at_index, &data);
}
-static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
-{
- return but->type == UI_BTYPE_TREEROW;
-}
-
static bool ui_but_is_view_item_fn(const uiBut *but, const void *UNUSED(customdata))
{
- return ui_but_is_view_item(but);
+ return but->type == UI_BTYPE_VIEW_ITEM;
}
uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
@@ -477,24 +466,19 @@ uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_view_item_fn, nullptr);
}
-uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
-{
- return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr);
-}
-
-static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
+static bool ui_but_is_active_view_item(const uiBut *but, const void *UNUSED(customdata))
{
- if (!ui_but_is_treerow(but, customdata)) {
+ if (but->type != UI_BTYPE_VIEW_ITEM) {
return false;
}
- const uiButTreeRow *treerow_but = (const uiButTreeRow *)but;
- return UI_tree_view_item_is_active(treerow_but->tree_item);
+ const uiButViewItem *view_item_but = (const uiButViewItem *)but;
+ return UI_view_item_is_active(view_item_but->view_item);
}
-uiBut *ui_tree_row_find_active(const ARegion *region)
+uiBut *ui_view_item_find_active(const ARegion *region)
{
- return ui_but_find(region, ui_but_is_active_treerow, nullptr);
+ return ui_but_find(region, ui_but_is_active_view_item, nullptr);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_region_hud.cc b/source/blender/editors/interface/interface_region_hud.cc
index d6166694a4a..aca36686dea 100644
--- a/source/blender/editors/interface/interface_region_hud.cc
+++ b/source/blender/editors/interface/interface_region_hud.cc
@@ -143,6 +143,11 @@ static void hud_panels_register(ARegionType *art, int space_type, int region_typ
static void hud_region_init(wmWindowManager *wm, ARegion *region)
{
ED_region_panels_init(wm, region);
+
+ /* Reset zoom from panels init because we don't want zoom allowed for redo panel. */
+ region->v2d.maxzoom = 1.0f;
+ region->v2d.minzoom = 1.0f;
+
UI_region_handlers_add(&region->handlers);
region->flag |= RGN_FLAG_TEMP_REGIONDATA;
}
@@ -251,7 +256,7 @@ static ARegion *hud_region_add(ScrArea *area)
if (region_win) {
float x, y;
- UI_view2d_scroller_size_get(&region_win->v2d, &x, &y);
+ UI_view2d_scroller_size_get(&region_win->v2d, true, &x, &y);
region->runtime.offset_x = x;
region->runtime.offset_y = y;
}
diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc
index b11564f09c5..becdfaf4e25 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.cc
+++ b/source/blender/editors/interface/interface_region_menu_pie.cc
@@ -27,6 +27,7 @@
#include "WM_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "UI_interface.h"
@@ -36,7 +37,7 @@
#include "ED_screen.h"
#include "interface_intern.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Pie Menu
@@ -371,7 +372,7 @@ void ui_pie_menu_level_create(uiBlock *block,
EnumPropertyItem *remaining = static_cast<EnumPropertyItem *>(
MEM_mallocN(array_size + sizeof(EnumPropertyItem), "pie_level_item_array"));
memcpy(remaining, items + totitem_parent, array_size);
- /* A nullptr terminating sentinel element is required. */
+ /* A null terminating sentinel element is required. */
memset(&remaining[totitem_remain], 0, sizeof(EnumPropertyItem));
/* yuk, static... issue is we can't reliably free this without doing dangerous changes */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc
index a22f7218203..0647e1a4a70 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.cc
+++ b/source/blender/editors/interface/interface_region_menu_popup.cc
@@ -39,7 +39,7 @@
#include "ED_screen.h"
#include "interface_intern.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Utility Functions
diff --git a/source/blender/editors/interface/interface_region_popover.cc b/source/blender/editors/interface/interface_region_popover.cc
index 2e10261a4f7..17c8d890755 100644
--- a/source/blender/editors/interface/interface_region_popover.cc
+++ b/source/blender/editors/interface/interface_region_popover.cc
@@ -46,7 +46,7 @@
#include "UI_interface.h"
#include "interface_intern.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Popup Menu with Callback or String
@@ -397,7 +397,7 @@ void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap)
pup->window = window;
- /* TODO(campbell): we may want to make this configurable.
+ /* TODO(@campbellbarton): we may want to make this configurable.
* The begin/end stype of calling popups doesn't allow 'can_refresh' to be set.
* For now close this style of popovers when accessed. */
UI_block_flag_disable(pup->block, UI_BLOCK_KEEP_OPEN);
diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc
index 74c228e3338..daa46b150a3 100644
--- a/source/blender/editors/interface/interface_region_popup.cc
+++ b/source/blender/editors/interface/interface_region_popup.cc
@@ -31,7 +31,7 @@
#include "ED_screen.h"
#include "interface_intern.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Utility Functions
@@ -397,7 +397,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *region)
static void ui_block_region_popup_window_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
switch (wmn->category) {
case NC_WINDOW: {
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index 64de31dfe6a..6bb47666afd 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -41,7 +41,7 @@
#include "GPU_state.h"
#include "interface_intern.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
#define MENU_BORDER (int)(0.3f * U.widget_unit)
@@ -451,15 +451,16 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
/* reset vars */
data->items.totitem = 0;
data->items.more = 0;
- if (reset == false) {
+ if (!reset) {
data->items.offset_i = data->items.offset;
}
else {
data->items.offset_i = data->items.offset = 0;
data->active = -1;
- /* handle active */
- if (search_but->items_update_fn && search_but->item_active) {
+ /* On init, find and center active item. */
+ const bool is_first_search = !search_but->but.changed;
+ if (is_first_search && search_but->items_update_fn && search_but->item_active) {
data->items.active = search_but->item_active;
ui_searchbox_update_fn(C, search_but, but->editstr, &data->items);
data->items.active = nullptr;
@@ -709,18 +710,18 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
type.regionid = RGN_TYPE_TEMPORARY;
region->type = &type;
- /* create searchbox data */
+ /* Create search-box data. */
uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__);
- /* set font, get bb */
+ /* Set font, get the bounding-box. */
data->fstyle = style->widget; /* copy struct */
ui_fontscale(&data->fstyle.points, aspect);
UI_fontstyle_set(&data->fstyle);
region->regiondata = data;
- /* special case, hardcoded feature, not draw backdrop when called from menus,
- * assume for design that popup already added it */
+ /* Special case, hard-coded feature, not draw backdrop when called from menus,
+ * assume for design that popup already added it. */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
data->noback = true;
}
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.cc
index 82d4405e1b5..a6e37d3f36f 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.cc
@@ -7,7 +7,7 @@
* ToolTip Region and Construction
*/
-/* TODO(campbell):
+/* TODO(@campbellbarton):
* We may want to have a higher level API that initializes a timer,
* checks for mouse motion and clears the tool-tip afterwards.
* We never want multiple tool-tips at once
@@ -16,9 +16,9 @@
* For now it's not a priority, so leave as-is.
*/
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -39,6 +39,7 @@
#include "WM_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "UI_interface.h"
@@ -52,7 +53,7 @@
#include "ED_screen.h"
#include "interface_intern.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
#define UI_TIP_PAD_FAC 1.3f
#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y)
@@ -60,59 +61,82 @@
#define UI_TIP_STR_MAX 1024
-typedef struct uiTooltipFormat {
- enum {
- UI_TIP_STYLE_NORMAL = 0,
- UI_TIP_STYLE_HEADER,
- UI_TIP_STYLE_MONO,
- } style : 3;
- enum {
- UI_TIP_LC_MAIN = 0, /* primary text */
- UI_TIP_LC_VALUE, /* the value of buttons (also shortcuts) */
- UI_TIP_LC_ACTIVE, /* titles of active enum values */
- UI_TIP_LC_NORMAL, /* regular text */
- UI_TIP_LC_PYTHON, /* Python snippet */
- UI_TIP_LC_ALERT, /* description of why operator can't run */
- } color_id : 4;
- int is_pad : 1;
-} uiTooltipFormat;
-
-typedef struct uiTooltipField {
+struct uiTooltipFormat {
+ enum class Style : int8_t {
+ Normal,
+ Header,
+ Mono,
+ };
+ enum class ColorID : int8_t {
+ /** Primary Text. */
+ Main = 0,
+ /** The value of buttons (also shortcuts). */
+ Value = 1,
+ /** Titles of active enum values. */
+ Active = 2,
+ /** Regular text. */
+ Normal = 3,
+ /** Python snippet. */
+ Python = 4,
+ /** Description of why an operator can't run. */
+ Alert = 5,
+ };
+ Style style;
+ ColorID color_id;
+ bool is_pad;
+};
+
+struct uiTooltipField {
char *text;
char *text_suffix;
struct {
- uint x_pos; /* x cursor position at the end of the last line */
- uint lines; /* number of lines, 1 or more with word-wrap */
+ /** X cursor position at the end of the last line. */
+ uint x_pos;
+ /** Number of lines, 1 or more with word-wrap. */
+ uint lines;
} geom;
uiTooltipFormat format;
+};
-} uiTooltipField;
-
-typedef struct uiTooltipData {
+struct uiTooltipData {
rcti bbox;
uiTooltipField *fields;
uint fields_len;
uiFontStyle fstyle;
int wrap_width;
int toth, lineh;
-} uiTooltipData;
+};
#define UI_TIP_LC_MAX 6
-BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max");
+BLI_STATIC_ASSERT(UI_TIP_LC_MAX == static_cast<int>(uiTooltipFormat::ColorID::Alert) + 1,
+ "invalid lc-max");
BLI_STATIC_ASSERT(sizeof(uiTooltipFormat) <= sizeof(int), "oversize");
static uiTooltipField *text_field_add_only(uiTooltipData *data)
{
data->fields_len += 1;
- data->fields = MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len);
+ data->fields = static_cast<uiTooltipField *>(
+ MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len));
return &data->fields[data->fields_len - 1];
}
-static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format)
+// static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format)
+// {
+// uiTooltipField *field = text_field_add_only(data);
+// field->format = *format;
+// return field;
+// }
+
+static uiTooltipField *text_field_add(uiTooltipData *data,
+ const uiTooltipFormat::Style style,
+ const uiTooltipFormat::ColorID color,
+ const bool is_pad = false)
{
uiTooltipField *field = text_field_add_only(data);
- field->format = *format;
+ field->format = {};
+ field->format.style = style;
+ field->format.color_id = color, field->format.is_pad = is_pad;
return field;
}
@@ -137,30 +161,31 @@ static void rgb_tint(float col[3], float h, float h_strength, float v, float v_s
static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region)
{
const float pad_px = UI_TIP_PADDING;
- uiTooltipData *data = region->regiondata;
+ uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata);
const uiWidgetColors *theme = ui_tooltip_get_theme();
rcti bbox = data->bbox;
float tip_colors[UI_TIP_LC_MAX][3];
uchar drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */
- float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */
- float *value_color = tip_colors[UI_TIP_LC_VALUE];
- float *active_color = tip_colors[UI_TIP_LC_ACTIVE];
- float *normal_color = tip_colors[UI_TIP_LC_NORMAL];
- float *python_color = tip_colors[UI_TIP_LC_PYTHON];
- float *alert_color = tip_colors[UI_TIP_LC_ALERT];
+ /* The color from the theme. */
+ float *main_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Main)];
+ float *value_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Value)];
+ float *active_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Active)];
+ float *normal_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Normal)];
+ float *python_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Python)];
+ float *alert_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Alert)];
float background_color[3];
wmOrtho2_region_pixelspace(region);
- /* draw background */
- ui_draw_tooltip_background(UI_style_get(), NULL, &bbox);
+ /* Draw background. */
+ ui_draw_tooltip_background(UI_style_get(), nullptr, &bbox);
/* set background_color */
rgb_uchar_to_float(background_color, theme->inner);
- /* calculate normal_color */
+ /* Calculate `normal_color`. */
rgb_uchar_to_float(main_color, theme->text);
copy_v3_v3(active_color, main_color);
copy_v3_v3(normal_color, main_color);
@@ -168,19 +193,19 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
copy_v3_v3(alert_color, main_color);
copy_v3_v3(value_color, main_color);
- /* find the brightness difference between background and text colors */
+ /* Find the brightness difference between background and text colors. */
const float tone_bg = rgb_to_grayscale(background_color);
- /* tone_fg = rgb_to_grayscale(main_color); */
+ // tone_fg = rgb_to_grayscale(main_color);
- /* mix the colors */
+ /* Mix the colors. */
rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* Light gray. */
rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* Light blue. */
rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* Gray. */
rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* Dark gray. */
rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* Red. */
- /* draw text */
+ /* Draw text. */
BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width);
BLF_wordwrap(blf_mono_font, data->wrap_width);
@@ -189,58 +214,58 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
for (int i = 0; i < data->fields_len; i++) {
const uiTooltipField *field = &data->fields[i];
- const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL;
+ const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] :
+ nullptr;
bbox.ymin = bbox.ymax - (data->lineh * field->geom.lines);
- if (field->format.style == UI_TIP_STYLE_HEADER) {
- const struct uiFontStyleDraw_Params fs_params = {
- .align = UI_STYLE_TEXT_LEFT,
- .word_wrap = true,
- };
- /* draw header and active data (is done here to be able to change color) */
- rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
+ if (field->format.style == uiTooltipFormat::Style::Header) {
+ uiFontStyleDraw_Params fs_params{};
+ fs_params.align = UI_STYLE_TEXT_LEFT;
+ fs_params.word_wrap = true;
+
+ /* Draw header and active data (is done here to be able to change color). */
+ rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Main)]);
UI_fontstyle_set(&data->fstyle);
UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
- /* offset to the end of the last line */
+ /* Offset to the end of the last line. */
if (field->text_suffix) {
const float xofs = field->geom.x_pos;
const float yofs = data->lineh * (field->geom.lines - 1);
bbox.xmin += xofs;
bbox.ymax -= yofs;
- rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
+ rgb_float_to_uchar(drawcol,
+ tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Active)]);
UI_fontstyle_draw(
&data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params);
- /* undo offset */
+ /* Undo offset. */
bbox.xmin -= xofs;
bbox.ymax += yofs;
}
}
- else if (field->format.style == UI_TIP_STYLE_MONO) {
- const struct uiFontStyleDraw_Params fs_params = {
- .align = UI_STYLE_TEXT_LEFT,
- .word_wrap = true,
- };
+ else if (field->format.style == uiTooltipFormat::Style::Mono) {
+ uiFontStyleDraw_Params fs_params{};
+ fs_params.align = UI_STYLE_TEXT_LEFT;
+ fs_params.word_wrap = true;
uiFontStyle fstyle_mono = data->fstyle;
fstyle_mono.uifont_id = blf_mono_font;
UI_fontstyle_set(&fstyle_mono);
- /* XXX, needed because we don't have mono in 'U.uifonts' */
+ /* XXX: needed because we don't have mono in 'U.uifonts'. */
BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
- rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
+ rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(field->format.color_id)]);
UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
else {
- BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL);
- const struct uiFontStyleDraw_Params fs_params = {
- .align = UI_STYLE_TEXT_LEFT,
- .word_wrap = true,
- };
-
- /* draw remaining data */
- rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
+ BLI_assert(field->format.style == uiTooltipFormat::Style::Normal);
+ uiFontStyleDraw_Params fs_params{};
+ fs_params.align = UI_STYLE_TEXT_LEFT;
+ fs_params.word_wrap = true;
+
+ /* Draw remaining data. */
+ rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(field->format.color_id)]);
UI_fontstyle_set(&data->fstyle);
UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
@@ -258,7 +283,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
static void ui_tooltip_region_free_cb(ARegion *region)
{
- uiTooltipData *data = region->regiondata;
+ uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata);
for (int i = 0; i < data->fields_len; i++) {
const uiTooltipField *field = &data->fields[i];
@@ -269,7 +294,7 @@ static void ui_tooltip_region_free_cb(ARegion *region)
}
MEM_freeN(data->fields);
MEM_freeN(data);
- region->regiondata = NULL;
+ region->regiondata = nullptr;
}
/** \} */
@@ -280,7 +305,7 @@ static void ui_tooltip_region_free_cb(ARegion *region)
static char *ui_tooltip_text_python_from_op(bContext *C, wmOperatorType *ot, PointerRNA *opptr)
{
- char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, opptr);
+ char *str = WM_operator_pystring_ex(C, nullptr, false, false, ot, opptr);
/* Avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary. */
WM_operator_pystring_abbreviate(str, 32);
@@ -303,24 +328,17 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
- if (ot != NULL) {
- /* Tip */
+ if (ot != nullptr) {
+ /* Tip. */
{
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_MAIN,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true);
field->text = BLI_strdup(ot->description ? ot->description : ot->name);
}
- /* Shortcut */
+ /* Shortcut. */
{
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_NORMAL,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal);
bool found = false;
if (WM_keymap_item_to_string(kmi, false, buf, sizeof(buf))) {
found = true;
@@ -328,13 +346,10 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None");
}
- /* Python */
+ /* Python. */
if (U.flag & USER_TOOLTIPS_PYTHON) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_PYTHON,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Python);
char *str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr);
field->text = BLI_sprintfN(TIP_("Python: %s"), str);
MEM_freeN(str);
@@ -352,17 +367,17 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
*/
static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is_label)
{
- if (but->optype == NULL) {
- return NULL;
+ if (but->optype == nullptr) {
+ return nullptr;
}
if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_id")) {
- return NULL;
+ return nullptr;
}
/* Needed to get the space-data's type (below). */
- if (CTX_wm_space_data(C) == NULL) {
- return NULL;
+ if (CTX_wm_space_data(C) == nullptr) {
+ return nullptr;
}
char tool_id[MAX_NAME];
@@ -377,7 +392,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
const char *has_valid_context_error = IFACE_("Unsupported context");
{
ScrArea *area = CTX_wm_area(C);
- if (area == NULL) {
+ if (area == nullptr) {
has_valid_context = false;
}
else {
@@ -392,16 +407,15 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
/* We have a tool, now extract the info. */
- uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+ uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__);
#ifdef WITH_PYTHON
- /* it turns out to be most simple to do this via Python since C
- * doesn't have access to information about non-active tools.
- */
+ /* It turns out to be most simple to do this via Python since C
+ * doesn't have access to information about non-active tools. */
/* Title (when icon-only). */
if (but->drawstr[0] == '\0') {
- const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
char expr[256];
SNPRINTF(expr,
"bl_ui.space_toolsystem_common.item_from_id("
@@ -409,16 +423,16 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
"bpy.context.space_data.type, "
"'%s').label",
tool_id);
- char *expr_result = NULL;
+ char *expr_result = nullptr;
bool is_error = false;
if (has_valid_context == false) {
expr_result = BLI_strdup(has_valid_context_error);
}
- else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) {
+ else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) {
if (STREQ(expr_result, "")) {
MEM_freeN(expr_result);
- expr_result = NULL;
+ expr_result = nullptr;
}
}
else {
@@ -428,7 +442,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
is_error = true;
}
- if (expr_result != NULL) {
+ if (expr_result != nullptr) {
/* NOTE: This is a very weak hack to get a valid translation most of the time...
* Proper way to do would be to get i18n context from the item, somehow. */
const char *label_str = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, expr_result);
@@ -441,23 +455,19 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
expr_result = BLI_strdup(label_str);
}
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_MAIN,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true);
field->text = expr_result;
if (UNLIKELY(is_error)) {
- field->format.color_id = UI_TIP_LC_ALERT;
+ field->format.color_id = uiTooltipFormat::ColorID::Alert;
}
}
}
/* Tip. */
if (is_label == false) {
- const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
char expr[256];
SNPRINTF(expr,
"bl_ui.space_toolsystem_common.description_from_id("
@@ -466,16 +476,16 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
"'%s') + '.'",
tool_id);
- char *expr_result = NULL;
+ char *expr_result = nullptr;
bool is_error = false;
if (has_valid_context == false) {
expr_result = BLI_strdup(has_valid_context_error);
}
- else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) {
+ else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) {
if (STREQ(expr_result, ".")) {
MEM_freeN(expr_result);
- expr_result = NULL;
+ expr_result = nullptr;
}
}
else {
@@ -485,17 +495,13 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
is_error = true;
}
- if (expr_result != NULL) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_MAIN,
- .is_pad = true,
- });
+ if (expr_result != nullptr) {
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true);
field->text = expr_result;
if (UNLIKELY(is_error)) {
- field->format.color_id = UI_TIP_LC_ALERT;
+ field->format.color_id = uiTooltipFormat::ColorID::Alert;
}
}
}
@@ -514,18 +520,18 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
*
* Either way case it's useful to show the shortcut.
*/
- char *shortcut = NULL;
+ char *shortcut = nullptr;
{
- uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL};
- UI_but_string_info_get(C, but, &op_keymap, NULL);
+ uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, nullptr};
+ UI_but_string_info_get(C, but, &op_keymap, nullptr);
shortcut = op_keymap.strinfo;
}
- if (shortcut == NULL) {
+ if (shortcut == nullptr) {
const ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
- if (tool_attr != NULL) {
+ if (tool_attr != nullptr) {
const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
const char *tool_id_lstrip = strrchr(tool_id, '.');
const int tool_id_offset = tool_id_lstrip ? ((tool_id_lstrip - tool_id) + 1) : 0;
@@ -542,7 +548,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (WM_key_event_operator_string(C,
ot->idname,
WM_OP_INVOKE_REGION_WIN,
- op_props.data,
+ static_cast<IDProperty *>(op_props.data),
true,
shortcut_brush,
ARRAY_SIZE(shortcut_brush))) {
@@ -553,20 +559,20 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
}
- if (shortcut == NULL) {
+ if (shortcut == nullptr) {
/* Check for direct access to the tool. */
char shortcut_toolbar[128] = "";
if (WM_key_event_operator_string(C,
"WM_OT_toolbar",
WM_OP_INVOKE_REGION_WIN,
- NULL,
+ nullptr,
true,
shortcut_toolbar,
ARRAY_SIZE(shortcut_toolbar))) {
/* Generate keymap in order to inspect it.
* NOTE: we could make a utility to avoid the keymap generation part of this. */
const char *expr_imports[] = {
- "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", NULL};
+ "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", nullptr};
const char *expr =
("getattr("
"bl_keymap_utils.keymap_from_toolbar.generate("
@@ -579,7 +585,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
shortcut = BLI_strdup(has_valid_context_error);
}
- else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) {
+ else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) {
if (expr_result != 0) {
wmKeyMap *keymap = (wmKeyMap *)expr_result;
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
@@ -602,13 +608,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
}
- if (shortcut != NULL) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ if (shortcut != nullptr) {
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_sprintfN(TIP_("Shortcut: %s"), shortcut);
MEM_freeN(shortcut);
}
@@ -626,11 +628,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
* This is a little involved since the shortcut may be bound to another tool in this group,
* instead of the current tool on display. */
- char *expr_result = NULL;
+ char *expr_result = nullptr;
size_t expr_result_len;
{
- const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
char expr[256];
SNPRINTF(expr,
"'\\x00'.join("
@@ -644,12 +646,12 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
/* pass */
}
else if (BPY_run_string_as_string_and_size(
- C, expr_imports, expr, NULL, &expr_result, &expr_result_len)) {
+ C, expr_imports, expr, nullptr, &expr_result, &expr_result_len)) {
/* pass. */
}
}
- if (expr_result != NULL) {
+ if (expr_result != nullptr) {
PointerRNA op_props;
WM_operator_properties_create_ptr(&op_props, but->optype);
RNA_boolean_set(&op_props, "cycle", true);
@@ -664,7 +666,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (WM_key_event_operator_string(C,
but->optype->idname,
WM_OP_INVOKE_REGION_WIN,
- op_props.data,
+ static_cast<IDProperty *>(op_props.data),
true,
shortcut,
ARRAY_SIZE(shortcut))) {
@@ -677,12 +679,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
MEM_freeN(expr_result);
if (shortcut[0] != '\0') {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_sprintfN(TIP_("Shortcut Cycle: %s"), shortcut);
}
}
@@ -690,12 +688,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
/* Python */
if ((is_label == false) && (U.flag & USER_TOOLTIPS_PYTHON)) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_PYTHON,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Python, true);
char *str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr);
field->text = BLI_sprintfN(TIP_("Python: %s"), str);
MEM_freeN(str);
@@ -705,7 +699,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
/* This is too handy not to expose somehow, let's be sneaky for now. */
if ((is_label == false) && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
- const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
char expr[256];
SNPRINTF(expr,
"getattr("
@@ -721,15 +715,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
/* pass */
}
- else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) {
+ else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) {
if (expr_result != 0) {
{
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_NORMAL,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal, true);
field->text = BLI_strdup("Tool Keymap:");
}
wmKeyMap *keymap = (wmKeyMap *)expr_result;
@@ -746,7 +736,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (data->fields_len == 0) {
MEM_freeN(data);
- return NULL;
+ return nullptr;
}
return data;
}
@@ -755,26 +745,26 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
uiBut *but,
uiButExtraOpIcon *extra_icon)
{
- uiStringInfo but_label = {BUT_GET_LABEL, NULL};
- uiStringInfo but_tip = {BUT_GET_TIP, NULL};
- uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
- uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
- uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL};
- uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, NULL};
- uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
- uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
+ uiStringInfo but_label = {BUT_GET_LABEL, nullptr};
+ uiStringInfo but_tip = {BUT_GET_TIP, nullptr};
+ uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, nullptr};
+ uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, nullptr};
+ uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, nullptr};
+ uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, nullptr};
+ uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, nullptr};
+ uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, nullptr};
char buf[512];
wmOperatorType *optype = extra_icon ? UI_but_extra_operator_icon_optype_get(extra_icon) :
but->optype;
- PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop;
+ PropertyRNA *rnaprop = extra_icon ? nullptr : but->rnaprop;
/* create tooltip data */
- uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+ uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__);
if (extra_icon) {
- UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, NULL);
+ UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, nullptr);
}
else {
UI_but_string_info_get(C,
@@ -787,30 +777,25 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
&prop_keymap,
&rna_struct,
&rna_prop,
- NULL);
+ nullptr);
}
/* Tip Label (only for buttons not already showing the label).
* Check prefix instead of comparing because the button may include the shortcut.
- * Buttons with dynamic tooltips also don't get their default label here since they
- * can already provide more accurate and specific tooltip content. */
+ * Buttons with dynamic tool-tips also don't get their default label here since they
+ * can already provide more accurate and specific tool-tip content. */
if (but_label.strinfo && !STRPREFIX(but->drawstr, but_label.strinfo) && !but->tip_func) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_HEADER,
- .color_id = UI_TIP_LC_NORMAL,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal);
+
field->text = BLI_strdup(but_label.strinfo);
}
/* Tip */
if (but_tip.strinfo) {
{
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_HEADER,
- .color_id = UI_TIP_LC_NORMAL,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal);
if (enum_label.strinfo) {
field->text = BLI_sprintfN("%s: ", but_tip.strinfo);
field->text_suffix = BLI_strdup(enum_label.strinfo);
@@ -822,59 +807,40 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
/* special case enum rna buttons */
if ((but->type & UI_BTYPE_ROW) && rnaprop && RNA_property_flag(rnaprop) & PROP_ENUM_FLAG) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_NORMAL,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal);
field->text = BLI_strdup(TIP_("(Shift-Click/Drag to select multiple)"));
}
}
- /* Enum field label & tip */
+ /* Enum field label & tip. */
if (enum_tip.strinfo) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value);
field->text = BLI_strdup(enum_tip.strinfo);
}
- /* Op shortcut */
+ /* Operator shortcut. */
if (op_keymap.strinfo) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_sprintfN(TIP_("Shortcut: %s"), op_keymap.strinfo);
}
- /* Property context-toggle shortcut */
+ /* Property context-toggle shortcut. */
if (prop_keymap.strinfo) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_sprintfN(TIP_("Shortcut: %s"), prop_keymap.strinfo);
}
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- /* better not show the value of a password */
+ /* Better not show the value of a password. */
if ((rnaprop && (RNA_property_subtype(rnaprop) == PROP_PASSWORD)) == 0) {
- /* full string */
+ /* Full string. */
ui_but_string_get(but, buf, sizeof(buf));
if (buf[0]) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_sprintfN(TIP_("Value: %s"), buf);
}
}
@@ -889,22 +855,16 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
RNA_property_float_get_index(&but->rnapoin, rnaprop, but->rnaindex) :
RNA_property_float_get(&but->rnapoin, rnaprop);
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value);
field->text = BLI_sprintfN(TIP_("Radians: %f"), value);
}
}
if (but->flag & UI_BUT_DRIVEN) {
if (ui_but_anim_expression_get(but, buf, sizeof(buf))) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_NORMAL,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal);
field->text = BLI_sprintfN(TIP_("Expression: %s"), buf);
}
}
@@ -912,64 +872,56 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
if (but->rnapoin.owner_id) {
const ID *id = but->rnapoin.owner_id;
if (ID_IS_LINKED(id)) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_NORMAL,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal);
field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->filepath);
}
}
}
else if (optype) {
PointerRNA *opptr = extra_icon ? UI_but_extra_operator_icon_opptr_get(extra_icon) :
- /* allocated when needed, the button owns it */
+ /* Allocated when needed, the button owns it. */
UI_but_operator_ptr_get(but);
- /* so the context is passed to fieldf functions (some py fieldf functions use it) */
+ /* So the context is passed to field functions (some Python field functions use it). */
WM_operator_properties_sanitize(opptr, false);
char *str = ui_tooltip_text_python_from_op(C, optype, opptr);
- /* operator info */
+ /* Operator info. */
if (U.flag & USER_TOOLTIPS_PYTHON) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_MONO,
- .color_id = UI_TIP_LC_PYTHON,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python, true);
field->text = BLI_sprintfN(TIP_("Python: %s"), str);
}
MEM_freeN(str);
}
- /* button is disabled, we may be able to tell user why */
+ /* Button is disabled, we may be able to tell user why. */
if ((but->flag & UI_BUT_DISABLED) || extra_icon) {
- const char *disabled_msg = NULL;
+ const char *disabled_msg = nullptr;
bool disabled_msg_free = false;
- /* if operator poll check failed, it can give pretty precise info why */
+ /* If operator poll check failed, it can give pretty precise info why. */
if (optype) {
const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext :
but->opcontext;
+ wmOperatorCallParams call_params{};
+ call_params.optype = optype;
+ call_params.opcontext = opcontext;
CTX_wm_operator_poll_msg_clear(C);
- ui_but_context_poll_operator_ex(
- C, but, &(wmOperatorCallParams){.optype = optype, .opcontext = opcontext});
+ ui_but_context_poll_operator_ex(C, but, &call_params);
disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free);
}
- /* alternatively, buttons can store some reasoning too */
+ /* Alternatively, buttons can store some reasoning too. */
else if (!extra_icon && but->disabled_info) {
disabled_msg = TIP_(but->disabled_info);
}
if (disabled_msg && disabled_msg[0]) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_ALERT,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Alert);
field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg);
}
if (disabled_msg_free) {
@@ -979,39 +931,31 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
if ((U.flag & USER_TOOLTIPS_PYTHON) && !optype && rna_struct.strinfo) {
{
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_MONO,
- .color_id = UI_TIP_LC_PYTHON,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python, true);
if (rna_prop.strinfo) {
/* Struct and prop */
field->text = BLI_sprintfN(TIP_("Python: %s.%s"), rna_struct.strinfo, rna_prop.strinfo);
}
else {
- /* Only struct (e.g. menus) */
+ /* Only struct (e.g. menus). */
field->text = BLI_sprintfN(TIP_("Python: %s"), rna_struct.strinfo);
}
}
if (but->rnapoin.owner_id) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_MONO,
- .color_id = UI_TIP_LC_PYTHON,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python);
- /* this could get its own 'BUT_GET_...' type */
+ /* This could get its own `BUT_GET_...` type. */
/* never fails */
- /* move ownership (no need for re-alloc) */
+ /* Move ownership (no need for re-allocation). */
if (rnaprop) {
- field->text = RNA_path_full_property_py_ex(
- CTX_data_main(C), &but->rnapoin, rnaprop, but->rnaindex, true);
+ field->text = RNA_path_full_property_py_ex(&but->rnapoin, rnaprop, but->rnaindex, true);
}
else {
- field->text = RNA_path_full_struct_py(CTX_data_main(C), &but->rnapoin);
+ field->text = RNA_path_full_struct_py(&but->rnapoin);
}
}
}
@@ -1044,73 +988,66 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
if (data->fields_len == 0) {
MEM_freeN(data);
- return NULL;
+ return nullptr;
}
return data;
}
static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
{
- uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+ uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__);
- /* TODO(campbell): a way for gizmos to have their own descriptions (low priority). */
+ /* TODO(@campbellbarton): a way for gizmos to have their own descriptions (low priority). */
/* Operator Actions */
{
const bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part;
- const struct {
+ struct GizmoOpActions {
int part;
const char *prefix;
- } gzop_actions[] = {
+ };
+ GizmoOpActions gzop_actions[] = {
{
- .part = gz->highlight_part,
- .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : NULL,
+ gz->highlight_part,
+ use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : nullptr,
},
{
- .part = use_drag ? gz->drag_part : -1,
- .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : NULL,
+ use_drag ? gz->drag_part : -1,
+ use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : nullptr,
},
};
for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) {
wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ?
WM_gizmo_operator_get(gz, gzop_actions[i].part) :
- NULL;
- if (gzop != NULL) {
+ nullptr;
+ if (gzop != nullptr) {
/* Description */
char *info = WM_operatortype_description_or_name(C, gzop->type, &gzop->ptr);
- if (info != NULL) {
+ if (info != nullptr) {
char *text = info;
- if (gzop_actions[i].prefix != NULL) {
+ if (gzop_actions[i].prefix != nullptr) {
text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info);
MEM_freeN(info);
}
- if (text != NULL) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_HEADER,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ if (text != nullptr) {
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Value, true);
field->text = text;
}
}
/* Shortcut */
{
- IDProperty *prop = gzop->ptr.data;
+ IDProperty *prop = static_cast<IDProperty *>(gzop->ptr.data);
char buf[128];
if (WM_key_event_operator_string(
C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, buf, ARRAY_SIZE(buf))) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_sprintfN(TIP_("Shortcut: %s"), buf);
}
}
@@ -1122,17 +1059,13 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
if (gz->type->target_property_defs_len) {
wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
for (int i = 0; i < gz->type->target_property_defs_len; i++) {
- /* TODO(campbell): function callback descriptions. */
+ /* TODO(@campbellbarton): function callback descriptions. */
wmGizmoProperty *gz_prop = &gz_prop_array[i];
- if (gz_prop->prop != NULL) {
+ if (gz_prop->prop != nullptr) {
const char *info = RNA_property_ui_description(gz_prop->prop);
if (info && info[0]) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_strdup(info);
}
}
@@ -1141,7 +1074,7 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
if (data->fields_len == 0) {
MEM_freeN(data);
- return NULL;
+ return nullptr;
}
return data;
}
@@ -1160,7 +1093,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
rcti rect_i;
int font_flag = 0;
- /* create area region */
+ /* Create area region. */
ARegion *region = ui_region_temp_add(CTX_wm_screen(C));
static ARegionType type;
@@ -1170,7 +1103,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
type.regionid = RGN_TYPE_TEMPORARY;
region->type = &type;
- /* set font, get bb */
+ /* Set font, get bounding-box. */
data->fstyle = style->widget; /* copy struct */
ui_fontscale(&data->fstyle.points, aspect);
@@ -1184,7 +1117,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width);
BLF_wordwrap(blf_mono_font, data->wrap_width);
- /* these defines tweaked depending on font */
+ /* These defines tweaked depending on font. */
#define TIP_BORDER_X (16.0f / aspect)
#define TIP_BORDER_Y (6.0f / aspect)
@@ -1193,18 +1126,19 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
int i, fonth, fontw;
for (i = 0, fontw = 0, fonth = 0; i < data->fields_len; i++) {
uiTooltipField *field = &data->fields[i];
- uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL;
+ uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : nullptr;
struct ResultBLF info;
int w, x_pos = 0;
int font_id;
- if (field->format.style == UI_TIP_STYLE_MONO) {
+ if (field->format.style == uiTooltipFormat::Style::Mono) {
BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi);
font_id = blf_mono_font;
}
else {
- BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER));
+ BLI_assert(ELEM(
+ field->format.style, uiTooltipFormat::Style::Normal, uiTooltipFormat::Style::Header));
font_id = data->fstyle.uifont_id;
}
w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info);
@@ -1252,22 +1186,20 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
/* Clamp to window bounds. */
{
- /* Ensure at least 5 px above screen bounds
- * UI_UNIT_Y is just a guess to be above the menu item */
- if (init_rect_overlap != NULL) {
+ /* Ensure at least 5 px above screen bounds.
+ * #UI_UNIT_Y is just a guess to be above the menu item. */
+ if (init_rect_overlap != nullptr) {
const int pad = max_ff(1.0f, U.pixelsize) * 5;
- const rcti init_rect = {
- .xmin = init_rect_overlap->xmin - pad,
- .xmax = init_rect_overlap->xmax + pad,
- .ymin = init_rect_overlap->ymin - pad,
- .ymax = init_rect_overlap->ymax + pad,
- };
- const rcti rect_clamp = {
- .xmin = 0,
- .xmax = winx,
- .ymin = 0,
- .ymax = winy,
- };
+ rcti init_rect;
+ init_rect.xmin = init_rect_overlap->xmin - pad;
+ init_rect.xmax = init_rect_overlap->xmax + pad;
+ init_rect.ymin = init_rect_overlap->ymin - pad;
+ init_rect.ymax = init_rect_overlap->ymax + pad;
+ rcti rect_clamp;
+ rect_clamp.xmin = 0;
+ rect_clamp.xmax = winx;
+ rect_clamp.ymin = 0;
+ rect_clamp.ymax = winy;
/* try right. */
const int size_x = BLI_rcti_size_x(&rect_i);
const int size_y = BLI_rcti_size_y(&rect_i);
@@ -1347,12 +1279,11 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
}
else {
const int pad = max_ff(1.0f, U.pixelsize) * 5;
- const rcti rect_clamp = {
- .xmin = pad,
- .xmax = winx - pad,
- .ymin = pad + (UI_UNIT_Y * 2),
- .ymax = winy - pad,
- };
+ rcti rect_clamp;
+ rect_clamp.xmin = pad;
+ rect_clamp.xmax = winx - pad;
+ rect_clamp.ymin = pad + (UI_UNIT_Y * 2);
+ rect_clamp.ymax = winy - pad;
int offset_dummy[2];
BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy);
}
@@ -1367,7 +1298,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
{
/* Compensate for margin offset, visually this corrects the position. */
const int margin = UI_POPUP_MARGIN;
- if (init_rect_overlap != NULL) {
+ if (init_rect_overlap != nullptr) {
BLI_rcti_translate(&rect_i, margin, margin / 2);
}
@@ -1402,29 +1333,29 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label)
{
wmWindow *win = CTX_wm_window(C);
- /* aspect values that shrink text are likely unreadable */
+ /* Aspect values that shrink text are likely unreadable. */
const float aspect = min_ff(1.0f, but->block->aspect);
float init_position[2];
if (but->drawflag & UI_BUT_NO_TOOLTIP) {
- return NULL;
+ return nullptr;
}
- uiTooltipData *data = NULL;
+ uiTooltipData *data = nullptr;
- if (data == NULL) {
+ if (data == nullptr) {
data = ui_tooltip_data_from_tool(C, but, is_label);
}
- if (data == NULL) {
+ if (data == nullptr) {
data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon);
}
- if (data == NULL) {
- data = ui_tooltip_data_from_button_or_extra_icon(C, but, NULL);
+ if (data == nullptr) {
+ data = ui_tooltip_data_from_button_or_extra_icon(C, but, nullptr);
}
- if (data == NULL) {
- return NULL;
+ if (data == nullptr) {
+ return nullptr;
}
const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(but);
@@ -1453,31 +1384,30 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
}
ARegion *region = ui_tooltip_create_with_data(
- C, data, init_position, is_no_overlap ? &init_rect : NULL, aspect);
+ C, data, init_position, is_no_overlap ? &init_rect : nullptr, aspect);
return region;
}
ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
{
- return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label);
+ return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, nullptr, is_label);
}
ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
{
wmWindow *win = CTX_wm_window(C);
const float aspect = 1.0f;
- float init_position[2] = {win->eventstate->xy[0], win->eventstate->xy[1]};
+ float init_position[2] = {static_cast<float>(win->eventstate->xy[0]),
+ static_cast<float>(win->eventstate->xy[1])};
uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz);
- if (data == NULL) {
- return NULL;
+ if (data == nullptr) {
+ return nullptr;
}
- /* TODO(harley):
- * Julian preferred that the gizmo callback return the 3D bounding box
- * which we then project to 2D here. Would make a nice improvement.
- */
+ /* TODO(@harley): Julian preferred that the gizmo callback return the 3D bounding box
+ * which we then project to 2D here. Would make a nice improvement. */
if (gz->type->screen_bounds_get) {
rcti bounds;
if (gz->type->screen_bounds_get(C, gz, &bounds)) {
@@ -1486,46 +1416,34 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
}
}
- return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
+ return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect);
}
static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
const uiSearchItemTooltipData *item_tooltip_data)
{
- uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+ uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__);
if (item_tooltip_data->description[0]) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_HEADER,
- .color_id = UI_TIP_LC_NORMAL,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal, true);
field->text = BLI_strdup(item_tooltip_data->description);
}
if (item_tooltip_data->name && item_tooltip_data->name[0]) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_VALUE,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true);
field->text = BLI_strdup(item_tooltip_data->name);
}
if (item_tooltip_data->hint[0]) {
- uiTooltipField *field = text_field_add(data,
- &(uiTooltipFormat){
- .style = UI_TIP_STYLE_NORMAL,
- .color_id = UI_TIP_LC_NORMAL,
- .is_pad = true,
- });
+ uiTooltipField *field = text_field_add(
+ data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal, true);
field->text = BLI_strdup(item_tooltip_data->hint);
}
if (data->fields_len == 0) {
MEM_freeN(data);
- return NULL;
+ return nullptr;
}
return data;
}
@@ -1537,8 +1455,8 @@ ARegion *UI_tooltip_create_from_search_item_generic(
const uiSearchItemTooltipData *item_tooltip_data)
{
uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(item_tooltip_data);
- if (data == NULL) {
- return NULL;
+ if (data == nullptr) {
+ return nullptr;
}
const float aspect = 1.0f;
@@ -1547,7 +1465,7 @@ ARegion *UI_tooltip_create_from_search_item_generic(
init_position[0] = win->eventstate->xy[0];
init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2);
- return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
+ return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect);
}
void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region)
diff --git a/source/blender/editors/interface/interface_regions.cc b/source/blender/editors/interface/interface_regions.cc
index 1a2c1f7919c..1770805cf59 100644
--- a/source/blender/editors/interface/interface_regions.cc
+++ b/source/blender/editors/interface/interface_regions.cc
@@ -21,7 +21,7 @@
#include "ED_screen.h"
-#include "interface_regions_intern.h"
+#include "interface_regions_intern.hh"
ARegion *ui_region_temp_add(bScreen *screen)
{
diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.hh
index 2ed2cb3d68b..6287a031f5c 100644
--- a/source/blender/editors/interface/interface_regions_intern.h
+++ b/source/blender/editors/interface/interface_regions_intern.hh
@@ -3,23 +3,16 @@
/** \file
* \ingroup edinterface
*
- * Share between interface_region_*.c files.
+ * Share between interface_region_*.cc files.
*/
#pragma once
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* interface_region_menu_popup.c */
+/* interface_region_menu_popup.cc */
uint ui_popup_menu_hash(const char *str);
-/* interface_regions_intern.h */
+/* interface_regions.cc */
+
ARegion *ui_region_temp_add(bScreen *screen);
void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/interface/interface_style.cc b/source/blender/editors/interface/interface_style.cc
index 291ede05730..904765f6dc4 100644
--- a/source/blender/editors/interface/interface_style.cc
+++ b/source/blender/editors/interface/interface_style.cc
@@ -382,19 +382,8 @@ void uiStyleInit(void)
}
CLAMP(U.dpi, 48, 144);
- LISTBASE_FOREACH (uiFont *, font, &U.uifonts) {
- BLF_unload_id(font->blf_id);
- }
-
- if (blf_mono_font != -1) {
- BLF_unload_id(blf_mono_font);
- blf_mono_font = -1;
- }
-
- if (blf_mono_font_render != -1) {
- BLF_unload_id(blf_mono_font_render);
- blf_mono_font_render = -1;
- }
+ /* Needed so that custom fonts are always first. */
+ BLF_unload_all();
uiFont *font_first = static_cast<uiFont *>(U.uifonts.first);
@@ -498,6 +487,9 @@ void uiStyleInit(void)
const bool unique = true;
blf_mono_font_render = BLF_load_mono_default(unique);
}
+
+ /* Load the fallback fonts last. */
+ BLF_load_font_stack();
}
void UI_fontstyle_set(const uiFontStyle *fs)
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 8588c7cabc0..3147deb5ad1 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -66,7 +66,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
}
static void asset_view_draw_item(uiList *ui_list,
- bContext *UNUSED(C),
+ const bContext *UNUSED(C),
uiLayout *layout,
PointerRNA *UNUSED(dataptr),
PointerRNA *itemptr,
@@ -183,7 +183,7 @@ static void asset_view_template_refresh_asset_collection(
}
void uiTemplateAssetView(uiLayout *layout,
- bContext *C,
+ const bContext *C,
const char *list_id,
PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 4e587bd5338..0a684903f0f 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -50,7 +50,7 @@ static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttrib
}
void attribute_search_add_items(StringRefNull str,
- const bool is_output,
+ const bool can_create_attribute,
Span<const GeometryAttributeInfo *> infos,
uiSearchItems *seach_items,
const bool is_first)
@@ -68,8 +68,12 @@ void attribute_search_add_items(StringRefNull str,
}
if (!contained) {
dummy_info.name = str;
- UI_search_item_add(
- seach_items, str.c_str(), &dummy_info, is_output ? ICON_ADD : ICON_NONE, 0, 0);
+ UI_search_item_add(seach_items,
+ str.c_str(),
+ &dummy_info,
+ can_create_attribute ? ICON_ADD : ICON_NONE,
+ 0,
+ 0);
}
}
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index e0b6bbb34c4..f0c91588f98 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -83,7 +83,7 @@ struct TemplateListVisualInfo {
};
static void uilist_draw_item_default(struct uiList *ui_list,
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct uiLayout *layout,
struct PointerRNA *UNUSED(dataptr),
struct PointerRNA *itemptr,
@@ -114,7 +114,7 @@ static void uilist_draw_item_default(struct uiList *ui_list,
}
static void uilist_draw_filter_default(struct uiList *ui_list,
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct uiLayout *layout)
{
PointerRNA listptr;
@@ -160,7 +160,7 @@ static int cmpstringp(const void *p1, const void *p2)
}
static void uilist_filter_items_default(struct uiList *ui_list,
- struct bContext *UNUSED(C),
+ const struct bContext *UNUSED(C),
struct PointerRNA *dataptr,
const char *propname)
{
@@ -434,7 +434,7 @@ static void ui_template_list_collect_items(PointerRNA *list_ptr,
/**
* Create the UI-list representation of the list items, sorted and filtered if needed.
*/
-static void ui_template_list_collect_display_items(bContext *C,
+static void ui_template_list_collect_display_items(const bContext *C,
uiList *ui_list,
TemplateListInputData *input_data,
const uiListFilterItemsFunc filter_items_fn,
@@ -601,7 +601,7 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha
/**
* \note that \a layout_type may be null.
*/
-static uiList *ui_list_ensure(bContext *C,
+static uiList *ui_list_ensure(const bContext *C,
uiListType *ui_list_type,
const char *list_id,
int layout_type,
@@ -656,7 +656,7 @@ static uiList *ui_list_ensure(bContext *C,
return ui_list;
}
-static void ui_template_list_layout_draw(bContext *C,
+static void ui_template_list_layout_draw(const bContext *C,
uiList *ui_list,
uiLayout *layout,
TemplateListInputData *input_data,
@@ -1156,7 +1156,7 @@ static void ui_template_list_layout_draw(bContext *C,
}
uiList *uiTemplateList_ex(uiLayout *layout,
- bContext *C,
+ const bContext *C,
const char *listtype_name,
const char *list_id,
PointerRNA *dataptr,
@@ -1227,7 +1227,7 @@ uiList *uiTemplateList_ex(uiLayout *layout,
}
void uiTemplateList(uiLayout *layout,
- bContext *C,
+ const bContext *C,
const char *listtype_name,
const char *list_id,
PointerRNA *dataptr,
diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc
index c3021028b97..c777b7834f2 100644
--- a/source/blender/editors/interface/interface_template_search_menu.cc
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -918,6 +918,7 @@ static void menu_search_arg_free_fn(void *data_v)
WM_operator_properties_free(item->op.opptr);
MEM_freeN(item->op.opptr);
}
+ break;
}
case MenuSearch_Item::Type::RNA: {
break;
diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.cc
index 41de2ab197d..0d0a5f01744 100644
--- a/source/blender/editors/interface/interface_template_search_operator.c
+++ b/source/blender/editors/interface/interface_template_search_operator.cc
@@ -7,14 +7,15 @@
* accessed via the #WM_OT_search_operator operator.
*/
-#include <string.h>
+#include <cstring>
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_ghash.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -35,10 +36,10 @@
static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
{
- wmOperatorType *ot = arg2;
+ wmOperatorType *ot = static_cast<wmOperatorType *>(arg2);
if (ot) {
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
}
}
@@ -53,19 +54,20 @@ static void operator_search_update_fn(const bContext *C,
/* Prepare BLI_string_all_words_matched. */
const size_t str_len = strlen(str);
const int words_max = BLI_string_max_possible_word_count(str_len);
- int(*words)[2] = BLI_array_alloca(words, words_max);
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+ blender::Array<blender::int2> words(words_max);
+ const int words_len = BLI_string_find_split_words(
+ str, str_len, ' ', (int(*)[2])words.data(), words_max);
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
BLI_ghashIterator_step(&iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ wmOperatorType *ot = static_cast<wmOperatorType *>(BLI_ghashIterator_getValue(&iter));
const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
continue;
}
- if (BLI_string_all_words_matched(ot_ui_name, str, words, words_len)) {
+ if (BLI_string_all_words_matched(ot_ui_name, str, (int(*)[2])words.data(), words_len)) {
if (WM_operator_poll((bContext *)C, ot)) {
char name[256];
const int len = strlen(ot_ui_name);
@@ -78,7 +80,7 @@ static void operator_search_update_fn(const bContext *C,
if (WM_key_event_operator_string(C,
ot->idname,
WM_OP_EXEC_DEFAULT,
- NULL,
+ nullptr,
true,
&name[len + 1],
sizeof(name) - len - 1)) {
@@ -105,11 +107,11 @@ void UI_but_func_operator_search(uiBut *but)
UI_but_func_search_set(but,
ui_searchbox_create_operator,
operator_search_update_fn,
- NULL,
+ nullptr,
false,
- NULL,
+ nullptr,
operator_search_exec_fn,
- NULL);
+ nullptr);
}
void uiTemplateOperatorSearch(uiLayout *layout)
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 4b3937dabce..4d0f3026772 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -571,8 +571,11 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
/** \name ID Template
* \{ */
-/* This is for browsing and editing the ID-blocks used */
+static void template_id_cb(bContext *C, void *arg_litem, void *arg_event);
+/**
+ * This is for browsing and editing the ID-blocks used.
+ */
void UI_context_active_but_prop_get_templateID(bContext *C,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
@@ -582,7 +585,7 @@ void UI_context_active_but_prop_get_templateID(bContext *C,
memset(r_ptr, 0, sizeof(*r_ptr));
*r_prop = NULL;
- if (but && but->func_argN) {
+ if (but && (but->funcN == template_id_cb) && but->func_argN) {
TemplateID *template_ui = but->func_argN;
*r_ptr = template_ui->ptr;
*r_prop = template_ui->prop;
@@ -650,20 +653,41 @@ static void template_id_liboverride_hierarchy_collections_tag_recursive(
}
}
-static void template_id_liboverride_hierarchy_create(bContext *C,
- Main *bmain,
- TemplateID *template_ui,
- PointerRNA *idptr,
- const char **r_undo_push_label)
+ID *ui_template_id_liboverride_hierarchy_make(
+ bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
{
- ID *id = idptr->data;
- ID *owner_id = template_ui->ptr.owner_id;
+ const char *undo_push_label;
+ if (r_undo_push_label == NULL) {
+ r_undo_push_label = &undo_push_label;
+ }
+
+ /* If this is called on an already local override, 'toggle' between user-editable state, and
+ * system override with reset. */
+ if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY(id)) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ BKE_lib_override_library_get(bmain, id, NULL, &id);
+ }
+ if (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) {
+ id->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ *r_undo_push_label = "Make Library Override Hierarchy Editable";
+ }
+ else {
+ BKE_lib_override_library_id_reset(bmain, id, true);
+ *r_undo_push_label = "Clear Library Override Hierarchy";
+ }
+
+ WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ return id;
+ }
/* Attempt to perform a hierarchy override, based on contextual data available.
* NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough
* context, better to abort than create random overrides all over the place. */
if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id)) {
- return;
+ RNA_warning("The data-block %s is not overridable", id->name);
+ return NULL;
}
Object *object_active = CTX_data_active_object(C);
@@ -768,6 +792,15 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
BKE_lib_override_library_create(
bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
}
+ else {
+ if (object_active != NULL) {
+ object_active->id.tag |= LIB_TAG_DOIT;
+ }
+ BKE_lib_override_library_create(
+ bmain, scene, view_layer, NULL, id, NULL, NULL, &id_override, false);
+ BKE_scene_collections_object_remove(bmain, scene, (Object *)id, true);
+ WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL);
+ }
break;
case ID_ME:
case ID_CU_LEGACY:
@@ -781,7 +814,8 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
case ID_CV:
case ID_PT:
case ID_VO:
- if (object_active != NULL && object_active->data == id) {
+ case ID_NT: /* Essentially geometry nodes from modifier currently. */
+ if (object_active != NULL) {
if (collection_active != NULL &&
BKE_collection_has_object_recursive(collection_active, object_active)) {
template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, id, true);
@@ -808,23 +842,62 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
case ID_MA:
case ID_TE:
case ID_IM:
+ RNA_warning("The type of data-block %s could not yet implemented", id->name);
break;
case ID_WO:
+ RNA_warning("The type of data-block %s could not yet implemented", id->name);
break;
case ID_PA:
+ RNA_warning("The type of data-block %s could not yet implemented", id->name);
break;
default:
+ RNA_warning("The type of data-block %s could not yet implemented", id->name);
break;
}
if (id_override != NULL) {
id_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
*r_undo_push_label = "Make Library Override Hierarchy";
- /* Given `idptr` is re-assigned to owner property by caller to ensure proper updates etc. Here
- * we also use it to ensure remapping of the owner property from the linked data to the newly
- * created liboverride (note that in theory this remapping has already been done by code
- * above). */
- RNA_id_pointer_create(id_override, idptr);
+ /* In theory we could rely on setting/updating the RNA ID pointer property (as done by calling
+ * code) to be enough.
+ *
+ * However, some rare ID pointers properties (like the 'active object in viewlayer' one used
+ * for the Object templateID in the Object properties) use notifiers that do not enforce a
+ * rebuild of outliner trees, leading to crashes.
+ *
+ * So for now, add some extra notifiers here. */
+ WM_event_add_notifier(C, NC_ID | NA_ADDED, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ }
+ return id_override;
+}
+
+static void template_id_liboverride_hierarchy_make(bContext *C,
+ Main *bmain,
+ TemplateID *template_ui,
+ PointerRNA *idptr,
+ const char **r_undo_push_label)
+{
+ ID *id = idptr->data;
+ ID *owner_id = template_ui->ptr.owner_id;
+
+ ID *id_override = ui_template_id_liboverride_hierarchy_make(
+ C, bmain, owner_id, id, r_undo_push_label);
+
+ if (id_override != NULL) {
+ /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
+ * to ensure remapping of the owner property from the linked data to the newly created
+ * liboverride (note that in theory this remapping has already been done by code above), but
+ * only in case owner ID was already local ID (override or pure local data).
+ *
+ * Otherwise, owner ID will also have been overridden, and remapped already to use it's
+ * override of the data too. */
+ if (!ID_IS_LINKED(owner_id)) {
+ RNA_id_pointer_create(id_override, idptr);
+ }
+ }
+ else {
+ RNA_warning("The data-block %s could not be overridden", id->name);
}
}
@@ -877,8 +950,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id) {
Main *bmain = CTX_data_main(C);
if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
- template_id_liboverride_hierarchy_create(
- C, bmain, template_ui, &idptr, &undo_push_label);
+ template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
}
else {
if (BKE_lib_id_make_local(bmain, id, 0)) {
@@ -897,12 +969,18 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_OVERRIDE:
if (id && ID_IS_OVERRIDE_LIBRARY(id)) {
- BKE_lib_override_library_make_local(id);
- /* Reassign to get proper updates/notifiers. */
- idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
- RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL);
- RNA_property_update(C, &template_ui->ptr, template_ui->prop);
- undo_push_label = "Make Local";
+ Main *bmain = CTX_data_main(C);
+ if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
+ template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
+ }
+ else {
+ BKE_lib_override_library_make_local(id);
+ /* Reassign to get proper updates/notifiers. */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
+ undo_push_label = "Make Local";
+ }
}
break;
case UI_ID_ALONE:
@@ -1024,6 +1102,26 @@ static const char *template_id_browse_tip(const StructRNA *type)
}
/**
+ * Add a superimposed extra icon to \a but, for workspace pinning.
+ * Rather ugly special handling, but this is really a special case at this point, nothing worth
+ * generalizing.
+ */
+static void template_id_workspace_pin_extra_icon(const TemplateID *template_ui, uiBut *but)
+{
+ if ((template_ui->idcode != ID_SCE) || (template_ui->ptr.type != &RNA_Window)) {
+ return;
+ }
+
+ const wmWindow *win = template_ui->ptr.data;
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ UI_but_extra_operator_icon_add(but,
+ "WORKSPACE_OT_scene_pin_toggle",
+ WM_OP_INVOKE_DEFAULT,
+ (workspace->flags & WORKSPACE_USE_PIN_SCENE) ? ICON_PINNED :
+ ICON_UNPINNED);
+}
+
+/**
* \return a type-based i18n context, needed e.g. by "New" button.
* In most languages, this adjective takes different form based on gender of type name...
*/
@@ -1220,6 +1318,8 @@ static void template_ID(const bContext *C,
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
+ template_id_workspace_pin_extra_icon(template_ui, but);
+
if (ID_IS_LINKED(id)) {
const bool disabled = !BKE_idtype_idcode_is_localizable(GS(id->name));
if (id->tag & LIB_TAG_INDIRECT) {
@@ -1265,20 +1365,22 @@ static void template_ID(const bContext *C,
}
}
else if (ID_IS_OVERRIDE_LIBRARY(id)) {
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_LIBRARY_DATA_OVERRIDE,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0,
- 0,
- 0,
- 0,
- TIP_("Library override of linked data-block, click to make fully local"));
+ but = uiDefIconBut(
+ block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_LIBRARY_DATA_OVERRIDE,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0,
+ TIP_("Library override of linked data-block, click to make fully local, "
+ "Shift + Click to clear the library override and toggle if it can be edited"));
UI_but_funcN_set(
but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OVERRIDE));
}
@@ -5104,7 +5206,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
0.0,
- "Reapply and update the preset, removing changes");
+ TIP_("Reapply and update the preset, removing changes"));
UI_but_funcN_set(bt, CurveProfile_buttons_reset, MEM_dupallocN(cb), profile);
}
}
@@ -6229,7 +6331,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
0,
width + UI_UNIT_X,
UI_UNIT_Y,
- "Show in Info Log");
+ TIP_("Show in Info Log"));
UI_block_emboss_set(block, previous_emboss);
}
@@ -6256,8 +6358,10 @@ void uiTemplateInputStatus(uiLayout *layout, struct bContext *C)
uiLayout *row = uiLayoutRow(col, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
- const char *msg = TIP_(WM_window_cursor_keymap_status_get(win, i, 0));
- const char *msg_drag = TIP_(WM_window_cursor_keymap_status_get(win, i, 1));
+ const char *msg = CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT,
+ WM_window_cursor_keymap_status_get(win, i, 0));
+ const char *msg_drag = CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT,
+ WM_window_cursor_keymap_status_get(win, i, 1));
if (msg || (msg_drag == NULL)) {
uiItemL(row, msg ? msg : "", (ICON_MOUSE_LMB + i));
@@ -6425,13 +6529,13 @@ bool uiTemplateEventFromKeymapItem(struct uiLayout *layout,
for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) {
uiItemL(layout, "", icon_mod[j]);
}
- uiItemL(layout, text, icon);
+ uiItemL(layout, CTX_TIP_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, text), icon);
ok = true;
}
else if (text_fallback) {
const char *event_text = WM_key_event_string(kmi->type, true);
uiItemL(layout, event_text, ICON_NONE);
- uiItemL(layout, text, ICON_NONE);
+ uiItemL(layout, CTX_TIP_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, text), ICON_NONE);
ok = true;
}
return ok;
@@ -6669,7 +6773,7 @@ void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
}
static void cache_file_layer_item(uiList *UNUSED(ui_list),
- bContext *UNUSED(C),
+ const bContext *UNUSED(C),
uiLayout *layout,
PointerRNA *UNUSED(dataptr),
PointerRNA *itemptr,
diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.cc
index e998eb6dbed..ec54b695cf7 100644
--- a/source/blender/editors/interface/interface_undo.c
+++ b/source/blender/editors/interface/interface_undo.cc
@@ -7,7 +7,7 @@
* Undo stack to use for UI widgets that manage their own editing state.
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
@@ -21,39 +21,39 @@
/** \name Text Field Undo Stack
* \{ */
-typedef struct uiUndoStack_Text_State {
+struct uiUndoStack_Text_State {
struct uiUndoStack_Text_State *next, *prev;
int cursor_index;
char text[0];
-} uiUndoStack_Text_State;
+};
-typedef struct uiUndoStack_Text {
+struct uiUndoStack_Text {
ListBase states;
uiUndoStack_Text_State *current;
-} uiUndoStack_Text;
+};
static const char *ui_textedit_undo_impl(uiUndoStack_Text *stack, int *r_cursor_index)
{
/* Don't undo if no data has been pushed yet. */
- if (stack->current == NULL) {
- return NULL;
+ if (stack->current == nullptr) {
+ return nullptr;
}
/* Travel backwards in the stack and copy information to the caller. */
- if (stack->current->prev != NULL) {
+ if (stack->current->prev != nullptr) {
stack->current = stack->current->prev;
*r_cursor_index = stack->current->cursor_index;
return stack->current->text;
}
- return NULL;
+ return nullptr;
}
static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_index)
{
/* Don't redo if no data has been pushed yet. */
- if (stack->current == NULL) {
- return NULL;
+ if (stack->current == nullptr) {
+ return nullptr;
}
/* Only redo if new data has not been entered since the last undo. */
@@ -63,7 +63,7 @@ static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_
*r_cursor_index = stack->current->cursor_index;
return stack->current->text;
}
- return NULL;
+ return nullptr;
}
const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_cursor_index)
@@ -78,7 +78,7 @@ const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_curs
void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index)
{
/* Clear all redo actions from the current state. */
- if (stack->current != NULL) {
+ if (stack->current != nullptr) {
while (stack->current->next) {
uiUndoStack_Text_State *state = stack->current->next;
BLI_remlink(&stack->states, state);
@@ -88,7 +88,8 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor
/* Create the new state. */
const int text_size = strlen(text) + 1;
- stack->current = MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__);
+ stack->current = static_cast<uiUndoStack_Text_State *>(
+ MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__));
stack->current->cursor_index = cursor_index;
memcpy(stack->current->text, text, text_size);
BLI_addtail(&stack->states, stack->current);
@@ -96,8 +97,8 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor
uiUndoStack_Text *ui_textedit_undo_stack_create(void)
{
- uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__);
- stack->current = NULL;
+ uiUndoStack_Text *stack = MEM_new<uiUndoStack_Text>(__func__);
+ stack->current = nullptr;
BLI_listbase_clear(&stack->states);
return stack;
diff --git a/source/blender/editors/interface/interface_utils.cc b/source/blender/editors/interface/interface_utils.cc
index b7ca2d9aa11..4b94834ce97 100644
--- a/source/blender/editors/interface/interface_utils.cc
+++ b/source/blender/editors/interface/interface_utils.cc
@@ -787,7 +787,7 @@ int UI_calc_float_precision(int prec, double value)
*/
value = fabs(value);
if ((value < pow10_neg[prec]) && (value > (1.0 / max_pow))) {
- int value_i = (int)((value * max_pow) + 0.5);
+ int value_i = (int)lround(value * max_pow);
if (value_i != 0) {
const int prec_span = 3; /* show: 0.01001, 5 would allow 0.0100001 for eg. */
int test_prec;
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
deleted file mode 100644
index 699ac0c2b53..00000000000
--- a/source/blender/editors/interface/interface_view.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edinterface
- *
- * This part of the UI-View API is mostly needed to support persistent state of items within the
- * view. Views are stored in #uiBlock's, and kept alive with it until after the next redraw. So we
- * can compare the old view items with the new view items and keep state persistent for matching
- * ones.
- */
-
-#include <memory>
-#include <type_traits>
-#include <variant>
-
-#include "DNA_screen_types.h"
-
-#include "BKE_screen.h"
-
-#include "BLI_listbase.h"
-
-#include "ED_screen.h"
-
-#include "interface_intern.h"
-
-#include "UI_interface.hh"
-
-#include "UI_grid_view.hh"
-#include "UI_tree_view.hh"
-
-using namespace blender;
-using namespace blender::ui;
-
-/**
- * Wrapper to store views in a #ListBase. There's no `uiView` base class, we just store views as a
- * #std::variant.
- */
-struct ViewLink : public Link {
- using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
- using GridViewPtr = std::unique_ptr<AbstractGridView>;
-
- std::string idname;
- /* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
- std::variant<TreeViewPtr, GridViewPtr> view;
-};
-
-template<class T> constexpr void check_if_valid_view_type()
-{
- static_assert(std::is_same_v<T, AbstractTreeView> || std::is_same_v<T, AbstractGridView>,
- "Unsupported view type");
-}
-
-template<class T> T *get_view_from_link(ViewLink &link)
-{
- auto *t_uptr = std::get_if<std::unique_ptr<T>>(&link.view);
- return t_uptr ? t_uptr->get() : nullptr;
-}
-
-template<class T>
-static T *ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr<T> view)
-{
- check_if_valid_view_type<T>();
-
- ViewLink *view_link = MEM_new<ViewLink>(__func__);
- BLI_addtail(&block.views, view_link);
-
- view_link->view = std::move(view);
- view_link->idname = idname;
-
- return get_view_from_link<T>(*view_link);
-}
-
-AbstractGridView *UI_block_add_view(uiBlock &block,
- StringRef idname,
- std::unique_ptr<AbstractGridView> tree_view)
-{
- return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(tree_view));
-}
-
-AbstractTreeView *UI_block_add_view(uiBlock &block,
- StringRef idname,
- std::unique_ptr<AbstractTreeView> tree_view)
-{
- return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
-}
-
-void ui_block_free_views(uiBlock *block)
-{
- LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
- MEM_delete(link);
- }
-}
-
-void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
-{
- ARegion *region = listener_params->region;
-
- LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
- if (AbstractGridView *grid_view = get_view_from_link<AbstractGridView>(*view_link)) {
- if (UI_grid_view_listen_should_redraw(reinterpret_cast<uiGridViewHandle *>(grid_view),
- listener_params->notifier)) {
- ED_region_tag_redraw(region);
- }
- }
- else if (AbstractTreeView *tree_view = get_view_from_link<AbstractTreeView>(*view_link)) {
- if (UI_tree_view_listen_should_redraw(reinterpret_cast<uiTreeViewHandle *>(tree_view),
- listener_params->notifier)) {
- ED_region_tag_redraw(region);
- }
- }
- }
-}
-
-uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
-{
- uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
- if (!tree_row_but) {
- return nullptr;
- }
-
- return tree_row_but->tree_item;
-}
-
-uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region)
-{
- uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_active(region);
- if (!tree_row_but) {
- return nullptr;
- }
-
- return tree_row_but->tree_item;
-}
-
-template<class T> static StringRef ui_block_view_find_idname(const uiBlock &block, const T &view)
-{
- check_if_valid_view_type<T>();
-
- /* First get the idname the of the view we're looking for. */
- LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
- if (get_view_from_link<T>(*view_link) == &view) {
- return view_link->idname;
- }
- }
-
- return {};
-}
-
-template<class T>
-static T *ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const T &new_view)
-{
- check_if_valid_view_type<T>();
-
- uiBlock *old_block = new_block.oldblock;
- if (!old_block) {
- return nullptr;
- }
-
- StringRef idname = ui_block_view_find_idname(new_block, new_view);
- if (idname.is_empty()) {
- return nullptr;
- }
-
- LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
- if (old_view_link->idname == idname) {
- return get_view_from_link<T>(*old_view_link);
- }
- }
-
- return nullptr;
-}
-
-uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(
- const uiBlock *new_block, const uiTreeViewHandle *new_view_handle)
-{
- BLI_assert(new_block && new_view_handle);
- const AbstractTreeView &new_view = reinterpret_cast<const AbstractTreeView &>(*new_view_handle);
-
- AbstractTreeView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
- return reinterpret_cast<uiTreeViewHandle *>(old_view);
-}
-
-uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
- const uiBlock *new_block, const uiGridViewHandle *new_view_handle)
-{
- BLI_assert(new_block && new_view_handle);
- const AbstractGridView &new_view = reinterpret_cast<const AbstractGridView &>(*new_view_handle);
-
- AbstractGridView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
- return reinterpret_cast<uiGridViewHandle *>(old_view);
-}
-
-uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
- const uiTreeViewItemHandle *new_item_handle)
-{
- uiBlock *old_block = new_block->oldblock;
- if (!old_block) {
- return nullptr;
- }
-
- const AbstractTreeViewItem &new_item = *reinterpret_cast<const AbstractTreeViewItem *>(
- new_item_handle);
- const AbstractTreeView *old_tree_view = ui_block_view_find_matching_in_old_block(
- *new_block, new_item.get_tree_view());
- if (!old_tree_view) {
- return nullptr;
- }
-
- LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
- if (old_but->type != UI_BTYPE_TREEROW) {
- continue;
- }
- uiButTreeRow *old_treerow_but = (uiButTreeRow *)old_but;
- if (!old_treerow_but->tree_item) {
- continue;
- }
- AbstractTreeViewItem &old_item = *reinterpret_cast<AbstractTreeViewItem *>(
- old_treerow_but->tree_item);
- /* Check if the row is from the expected tree-view. */
- if (&old_item.get_tree_view() != old_tree_view) {
- continue;
- }
-
- if (UI_tree_view_item_matches(new_item_handle, old_treerow_but->tree_item)) {
- return old_treerow_but;
- }
- }
-
- return nullptr;
-}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index e2df2d77817..53b1967d668 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -104,8 +104,7 @@ typedef enum {
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
- UI_WTYPE_TREEROW,
- UI_WTYPE_GRID_TILE,
+ UI_WTYPE_VIEW_ITEM,
} uiWidgetTypeEnum;
/**
@@ -534,7 +533,7 @@ static void draw_anti_tria(
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(draw_color);
immBegin(GPU_PRIM_TRIS, 3 * WIDGET_AA_JITTER);
@@ -1525,11 +1524,6 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
const size_t max_len,
const char rpart_sep)
{
- /* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits!
- * Better to have a small piece of the last char cut out,
- * than two remaining chars replaced by an ellipsis... */
- okwidth += 1.0f + UI_DPI_FAC;
-
BLI_assert(str[0]);
/* need to set this first */
@@ -1628,7 +1622,7 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
}
- BLI_assert(strwidth <= okwidth);
+ BLI_assert((strwidth <= okwidth) || (okwidth <= 0.0f));
return strwidth;
}
@@ -1985,7 +1979,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
rcti selection_shape;
selection_shape.xmin = rect->xmin + selsta_draw;
@@ -2037,7 +2031,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_WIDGET_TEXT_CURSOR);
@@ -2780,7 +2774,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
for (int step = 1; step <= (int)radout; step++) {
const float expfac = sqrtf(step / radout);
@@ -2836,7 +2830,7 @@ static void ui_hsv_cursor(const float x, const float y, const float zoom)
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
imm_draw_circle_fill_2d(pos, x, y, radius, 8);
@@ -2936,7 +2930,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
immBegin(GPU_PRIM_TRI_FAN, tot + 2);
immAttr3fv(color, rgb_center);
@@ -2970,7 +2964,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
@@ -3067,7 +3061,7 @@ void ui_draw_gradient(const rcti *rect,
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
immBegin(GPU_PRIM_TRIS, steps * 3 * 6);
@@ -3232,7 +3226,7 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
/* outline */
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3ub(0, 0, 0);
imm_draw_box_wire_2d(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
immUnbindProgram();
@@ -3308,7 +3302,7 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
immUniformColor4ubv(col);
@@ -3672,12 +3666,11 @@ static void widget_progressbar(uiBut *but,
widgetbase_draw(&wtb_bar, wcol);
}
-static void widget_treerow_exec(uiWidgetColors *wcol,
- rcti *rect,
- const uiWidgetStateInfo *state,
- int UNUSED(roundboxalign),
- int indentation,
- const float zoom)
+static void widget_view_item(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3690,31 +3683,6 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
if ((state->but_flag & UI_ACTIVE) || (state->but_flag & UI_SELECT)) {
widgetbase_draw(&wtb, wcol);
}
-
- BLI_rcti_resize(rect, BLI_rcti_size_x(rect) - UI_UNIT_X * indentation, BLI_rcti_size_y(rect));
- BLI_rcti_translate(rect, 0.5f * UI_UNIT_X * indentation, 0);
-}
-
-static void widget_treerow(uiBut *but,
- uiWidgetColors *wcol,
- rcti *rect,
- const uiWidgetStateInfo *state,
- int roundboxalign,
- const float zoom)
-{
- uiButTreeRow *tree_row = (uiButTreeRow *)but;
- BLI_assert(but->type == UI_BTYPE_TREEROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
-}
-
-static void widget_gridtile(uiWidgetColors *wcol,
- rcti *rect,
- const uiWidgetStateInfo *state,
- int roundboxalign,
- const float zoom)
-{
- /* TODO Reuse tree-row drawing. */
- widget_treerow_exec(wcol, rect, state, roundboxalign, 0, zoom);
}
static void widget_nodesocket(uiBut *but,
@@ -3949,7 +3917,7 @@ static void widget_swatch(uiBut *but,
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3f(bw, bw, bw);
immBegin(GPU_PRIM_TRIS, 3);
@@ -4415,7 +4383,7 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* make mask to draw over image */
uchar col[4];
@@ -4608,14 +4576,9 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_progressbar;
break;
- case UI_WTYPE_TREEROW:
- wt.wcol_theme = &btheme->tui.wcol_view_item;
- wt.custom = widget_treerow;
- break;
-
- case UI_WTYPE_GRID_TILE:
+ case UI_WTYPE_VIEW_ITEM:
wt.wcol_theme = &btheme->tui.wcol_view_item;
- wt.draw = widget_gridtile;
+ wt.draw = widget_view_item;
break;
case UI_WTYPE_NODESOCKET:
@@ -4949,13 +4912,8 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
- case UI_BTYPE_TREEROW:
- wt = widget_type(UI_WTYPE_TREEROW);
- fstyle = &style->widgetlabel;
- break;
-
- case UI_BTYPE_GRID_TILE:
- wt = widget_type(UI_WTYPE_GRID_TILE);
+ case UI_BTYPE_VIEW_ITEM:
+ wt = widget_type(UI_WTYPE_VIEW_ITEM);
fstyle = &style->widgetlabel;
break;
@@ -5121,7 +5079,7 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
if (ELEM(direction, UI_DIR_UP, UI_DIR_DOWN)) {
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
const bool is_down = (direction == UI_DIR_DOWN);
const int sign = is_down ? 1 : -1;
@@ -5197,10 +5155,10 @@ static void draw_disk_shaded(float start,
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (shaded) {
col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ubv(col1);
}
@@ -5311,7 +5269,7 @@ void ui_draw_pie_center(uiBlock *block)
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ubv(btheme->tui.wcol_pie_menu.outline);
imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_internal, subd);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index cfdcd08df4a..93b94d42d39 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -895,6 +895,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_WIDGET_TEXT_CURSOR:
cp = btheme->tui.widget_text_cursor;
break;
+ case TH_WIDGET_TEXT_SELECTION:
+ cp = btheme->tui.wcol_text.item;
+ break;
+ case TH_WIDGET_TEXT_HIGHLIGHT:
+ cp = btheme->tui.wcol_text.text_sel;
+ break;
case TH_TRANSPARENT_CHECKER_PRIMARY:
cp = btheme->tui.transparent_checker_primary;
diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc
index 6ece7eb4ffa..bb459f227f9 100644
--- a/source/blender/editors/interface/view2d.cc
+++ b/source/blender/editors/interface/view2d.cc
@@ -149,7 +149,9 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
}
}
- scroll = view2d_scroll_mapped(v2d->scroll);
+ /* Do not use mapped scroll here because we want to update scroller rects
+ * even if they are not displayed. For initialization purposes. See T75003. */
+ scroll = v2d->scroll;
/* Scrollers are based off region-size:
* - they can only be on one to two edges of the region they define
@@ -158,7 +160,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
if (scroll) {
float scroll_width, scroll_height;
- UI_view2d_scroller_size_get(v2d, &scroll_width, &scroll_height);
+ UI_view2d_scroller_size_get(v2d, false, &scroll_width, &scroll_height);
/* vertical scroller */
if (scroll & V2D_SCROLL_LEFT) {
@@ -191,18 +193,6 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
v2d->hor = *mask_scroll;
v2d->hor.ymin = v2d->hor.ymax - scroll_height;
}
-
- /* adjust vertical scroller if there's a horizontal scroller, to leave corner free */
- if (scroll & V2D_SCROLL_VERTICAL) {
- if (scroll & V2D_SCROLL_BOTTOM) {
- /* on bottom edge of region */
- v2d->vert.ymin = v2d->hor.ymax;
- }
- else if (scroll & V2D_SCROLL_TOP) {
- /* on upper edge of region */
- v2d->vert.ymax = v2d->hor.ymin;
- }
- }
}
}
@@ -260,6 +250,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
/* tot rect has strictly regulated placement, and must only occur in +/- quadrant */
v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
v2d->keeptot = V2D_KEEPTOT_STRICT;
+ v2d->keepofs = (V2D_KEEPOFS_X | V2D_KEEPOFS_Y);
tot_changed = do_init;
/* scroller settings are currently not set here... that is left for regions... */
@@ -276,6 +267,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
v2d->keeptot = V2D_KEEPTOT_STRICT;
+ v2d->keepofs = (V2D_KEEPOFS_X | V2D_KEEPOFS_Y);
tot_changed = do_init;
/* scroller settings are currently not set here... that is left for regions... */
@@ -493,8 +485,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
}
/* check if we should restore aspect ratio (if view size changed) */
- if (v2d->keepzoom & V2D_KEEPASPECT) {
- bool do_x = false, do_y = false, do_cur /* , do_win */ /* UNUSED */;
+ if (v2d->keepzoom & V2D_KEEPASPECT && !(v2d->keeptot == V2D_KEEPTOT_STRICT)) {
+ bool do_x = false, do_y = false, do_cur;
float curRatio, winRatio;
/* when a window edge changes, the aspect ratio can't be used to
@@ -532,53 +524,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
/* do_win = do_y; */ /* UNUSED */
if (do_cur) {
- if ((v2d->keeptot == V2D_KEEPTOT_STRICT) && (winx != v2d->oldwinx)) {
- /* Special exception for Outliner (and later channel-lists):
- * - The view may be moved left to avoid contents
- * being pushed out of view when view shrinks.
- * - The keeptot code will make sure cur->xmin will not be less than tot->xmin
- * (which cannot be allowed).
- * - width is not adjusted for changed ratios here.
- */
- if (winx < v2d->oldwinx) {
- const float temp = v2d->oldwinx - winx;
-
- cur->xmin -= temp;
- cur->xmax -= temp;
-
- /* width does not get modified, as keepaspect here is just set to make
- * sure visible area adjusts to changing view shape!
- */
- }
- }
- else {
- /* portrait window: correct for x */
- width = height / winRatio;
- }
+ /* portrait window: correct for x */
+ width = height / winRatio;
}
else {
- if ((v2d->keeptot == V2D_KEEPTOT_STRICT) && (winy != v2d->oldwiny)) {
- /* special exception for Outliner (and later channel-lists):
- * - Currently, no actions need to be taken here...
- */
-
- if (winy < v2d->oldwiny) {
- const float temp = v2d->oldwiny - winy;
-
- if (v2d->align & V2D_ALIGN_NO_NEG_Y) {
- cur->ymin -= temp;
- cur->ymax -= temp;
- }
- else { /* Assume V2D_ALIGN_NO_POS_Y or combination */
- cur->ymin += temp;
- cur->ymax += temp;
- }
- }
- }
- else {
- /* landscape window: correct for y */
- height = width * winRatio;
- }
+ /* landscape window: correct for y */
+ height = width * winRatio;
}
/* store region size for next time */
@@ -1185,7 +1136,7 @@ void UI_view2d_multi_grid_draw(
GPU_line_width(1.0f);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
immBeginAtMost(GPU_PRIM_LINES, vertex_count);
for (int level = 0; level < totlevels; level++) {
@@ -1283,7 +1234,7 @@ void UI_view2d_dot_grid_draw(const View2D *v2d,
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
/* Scaling the dots fully with the zoom looks too busy, but a bit of size variation is nice. */
const float min_point_size = 2.0f * UI_DPI_FAC;
@@ -1510,7 +1461,7 @@ void UI_view2d_scrollers_calc(View2D *v2d,
}
}
-void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
+void UI_view2d_scrollers_draw_ex(View2D *v2d, const rcti *mask_custom, bool use_full_hide)
{
View2DScrollers scrollers;
UI_view2d_scrollers_calc(v2d, mask_custom, &scrollers);
@@ -1518,6 +1469,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
rcti vert, hor;
const int scroll = view2d_scroll_mapped(v2d->scroll);
const char emboss_alpha = btheme->tui.widget_emboss[3];
+ const float alpha_min = use_full_hide ? 0.0f : V2D_SCROLL_MIN_ALPHA;
+
uchar scrollers_back_color[4];
/* Color for scrollbar backs */
@@ -1530,7 +1483,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
/* horizontal scrollbar */
if (scroll & V2D_SCROLL_HORIZONTAL) {
uiWidgetColors wcol = btheme->tui.wcol_scroll;
- const float alpha_fac = v2d->alpha_hor / 255.0f;
+ /* 0..255 -> min...1 */
+ const float alpha_fac = ((v2d->alpha_hor / 255.0f) * (1.0f - alpha_min)) + alpha_min;
rcti slider;
int state;
@@ -1543,8 +1497,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
wcol.inner[3] *= alpha_fac;
wcol.item[3] *= alpha_fac;
- wcol.outline[3] *= alpha_fac;
- btheme->tui.widget_emboss[3] *= alpha_fac; /* will be reset later */
+ wcol.outline[3] = 0;
+ btheme->tui.widget_emboss[3] = 0; /* will be reset later */
/* show zoom handles if:
* - zooming on x-axis is allowed (no scroll otherwise)
@@ -1565,7 +1519,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
if (scroll & V2D_SCROLL_VERTICAL) {
uiWidgetColors wcol = btheme->tui.wcol_scroll;
rcti slider;
- const float alpha_fac = v2d->alpha_vert / 255.0f;
+ /* 0..255 -> min...1 */
+ const float alpha_fac = ((v2d->alpha_vert / 255.0f) * (1.0f - alpha_min)) + alpha_min;
int state;
slider.xmin = vert.xmin;
@@ -1577,8 +1532,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
wcol.inner[3] *= alpha_fac;
wcol.item[3] *= alpha_fac;
- wcol.outline[3] *= alpha_fac;
- btheme->tui.widget_emboss[3] *= alpha_fac; /* will be reset later */
+ wcol.outline[3] = 0;
+ btheme->tui.widget_emboss[3] = 0; /* will be reset later */
/* show zoom handles if:
* - zooming on y-axis is allowed (no scroll otherwise)
@@ -1599,6 +1554,11 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
btheme->tui.widget_emboss[3] = emboss_alpha;
}
+void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
+{
+ UI_view2d_scrollers_draw_ex(v2d, mask_custom, false);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1735,6 +1695,41 @@ void UI_view2d_view_to_region_fl(
*r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask));
}
+bool UI_view2d_view_to_region_segment_clip(const View2D *v2d,
+ const float xy_a[2],
+ const float xy_b[2],
+ int r_region_a[2],
+ int r_region_b[2])
+{
+ rctf rect_unit;
+ rect_unit.xmin = rect_unit.ymin = 0.0f;
+ rect_unit.xmax = rect_unit.ymax = 1.0f;
+
+ /* Express given coordinates as proportional values. */
+ const float s_a[2] = {
+ (xy_a[0] - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur),
+ (xy_a[1] - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur),
+ };
+ const float s_b[2] = {
+ (xy_b[0] - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur),
+ (xy_b[1] - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur),
+ };
+
+ /* Set initial value in case coordinates lie outside bounds. */
+ r_region_a[0] = r_region_b[0] = r_region_a[1] = r_region_b[1] = V2D_IS_CLIPPED;
+
+ if (BLI_rctf_isect_segment(&rect_unit, s_a, s_b)) {
+ r_region_a[0] = (int)(v2d->mask.xmin + (s_a[0] * BLI_rcti_size_x(&v2d->mask)));
+ r_region_a[1] = (int)(v2d->mask.ymin + (s_a[1] * BLI_rcti_size_y(&v2d->mask)));
+ r_region_b[0] = (int)(v2d->mask.xmin + (s_b[0] * BLI_rcti_size_x(&v2d->mask)));
+ r_region_b[1] = (int)(v2d->mask.ymin + (s_b[1] * BLI_rcti_size_y(&v2d->mask)));
+
+ return true;
+ }
+
+ return false;
+}
+
void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
@@ -1835,13 +1830,14 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
return &(region->v2d);
}
-void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_scroller_size_get(const View2D *v2d, bool mapped, float *r_x, float *r_y)
{
- const int scroll = view2d_scroll_mapped(v2d->scroll);
+ const int scroll = (mapped) ? view2d_scroll_mapped(v2d->scroll) : v2d->scroll;
if (r_x) {
if (scroll & V2D_SCROLL_VERTICAL) {
*r_x = (scroll & V2D_SCROLL_VERTICAL_HANDLES) ? V2D_SCROLL_HANDLE_WIDTH : V2D_SCROLL_WIDTH;
+ *r_x = ((*r_x - V2D_SCROLL_MIN_WIDTH) * (v2d->alpha_vert / 255.0f)) + V2D_SCROLL_MIN_WIDTH;
}
else {
*r_x = 0;
@@ -1851,6 +1847,7 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
if (scroll & V2D_SCROLL_HORIZONTAL) {
*r_y = (scroll & V2D_SCROLL_HORIZONTAL_HANDLES) ? V2D_SCROLL_HANDLE_HEIGHT :
V2D_SCROLL_HEIGHT;
+ *r_y = ((*r_y - V2D_SCROLL_MIN_WIDTH) * (v2d->alpha_hor / 255.0f)) + V2D_SCROLL_MIN_WIDTH;
}
else {
*r_y = 0;
diff --git a/source/blender/editors/interface/view2d_draw.cc b/source/blender/editors/interface/view2d_draw.cc
index d76230ba99c..ea4cf399a57 100644
--- a/source/blender/editors/interface/view2d_draw.cc
+++ b/source/blender/editors/interface/view2d_draw.cc
@@ -202,7 +202,7 @@ static void draw_parallel_lines(const ParallelLinesSet *lines,
immUniform1f("lineWidth", U.pixelsize - 1.0f);
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
immUniformColor3ubv(color);
immBegin(GPU_PRIM_LINES, steps * 2);
diff --git a/source/blender/editors/interface/view2d_ops.cc b/source/blender/editors/interface/view2d_ops.cc
index a4477c5271c..ec15c4ffc9f 100644
--- a/source/blender/editors/interface/view2d_ops.cc
+++ b/source/blender/editors/interface/view2d_ops.cc
@@ -960,8 +960,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
const double time = PIL_check_seconds_timer();
const float time_step = (float)(time - vzd->timer_lastdraw);
- dx *= time_step * 0.5f;
- dy *= time_step * 0.5f;
+ dx *= time_step * 5.0f;
+ dy *= time_step * 5.0f;
vzd->timer_lastdraw = time;
}
diff --git a/source/blender/editors/interface/views/abstract_view.cc b/source/blender/editors/interface/views/abstract_view.cc
new file mode 100644
index 00000000000..077c76a08f1
--- /dev/null
+++ b/source/blender/editors/interface/views/abstract_view.cc
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "interface_intern.h"
+
+#include "UI_abstract_view.hh"
+
+namespace blender::ui {
+
+void AbstractView::register_item(AbstractViewItem &item)
+{
+ /* Actually modifies the item, not the view. But for the public API it "feels" a bit nicer to
+ * have the view base class register the items, rather than setting the view on the item. */
+ item.view_ = this;
+}
+
+/* ---------------------------------------------------------------------- */
+/** \name View Reconstruction
+ * \{ */
+
+bool AbstractView::is_reconstructed() const
+{
+ return is_reconstructed_;
+}
+
+void AbstractView::update_from_old(uiBlock &new_block)
+{
+ uiBlock *old_block = new_block.oldblock;
+ if (!old_block) {
+ is_reconstructed_ = true;
+ return;
+ }
+
+ uiViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
+ &new_block, reinterpret_cast<uiViewHandle *>(this));
+ if (old_view_handle == nullptr) {
+ /* Initial construction, nothing to update. */
+ is_reconstructed_ = true;
+ return;
+ }
+
+ AbstractView &old_view = reinterpret_cast<AbstractView &>(*old_view_handle);
+
+ /* Update own persistent data. */
+ /* Keep the rename buffer persistent while renaming! The rename button uses the buffer's
+ * pointer to identify itself over redraws. */
+ rename_buffer_ = std::move(old_view.rename_buffer_);
+ old_view.rename_buffer_ = nullptr;
+
+ update_children_from_old(old_view);
+
+ /* Finished (re-)constructing the tree. */
+ is_reconstructed_ = true;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Default implementations of virtual functions
+ * \{ */
+
+bool AbstractView::listen(const wmNotifier & /*notifier*/) const
+{
+ /* Nothing by default. */
+ return false;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Renaming
+ * \{ */
+
+bool AbstractView::is_renaming() const
+{
+ return rename_buffer_ != nullptr;
+}
+
+bool AbstractView::begin_renaming()
+{
+ if (is_renaming()) {
+ return false;
+ }
+
+ rename_buffer_ = std::make_unique<decltype(rename_buffer_)::element_type>();
+ return true;
+}
+
+void AbstractView::end_renaming()
+{
+ BLI_assert(is_renaming());
+ rename_buffer_ = nullptr;
+}
+
+Span<char> AbstractView::get_rename_buffer() const
+{
+ return *rename_buffer_;
+}
+MutableSpan<char> AbstractView::get_rename_buffer()
+{
+ return *rename_buffer_;
+}
+
+/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/views/abstract_view_item.cc b/source/blender/editors/interface/views/abstract_view_item.cc
new file mode 100644
index 00000000000..f73183d07e9
--- /dev/null
+++ b/source/blender/editors/interface/views/abstract_view_item.cc
@@ -0,0 +1,373 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+#include "UI_abstract_view.hh"
+
+namespace blender::ui {
+
+/* ---------------------------------------------------------------------- */
+/** \name View Reconstruction
+ * \{ */
+
+void AbstractViewItem::update_from_old(const AbstractViewItem &old)
+{
+ is_active_ = old.is_active_;
+ is_renaming_ = old.is_renaming_;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Renaming
+ * \{ */
+
+bool AbstractViewItem::supports_renaming() const
+{
+ /* No renaming by default. */
+ return false;
+}
+bool AbstractViewItem::rename(StringRefNull /*new_name*/)
+{
+ /* No renaming by default. */
+ return false;
+}
+
+StringRef AbstractViewItem::get_rename_string() const
+{
+ /* No rename string by default. */
+ return {};
+}
+
+bool AbstractViewItem::is_renaming() const
+{
+ return is_renaming_;
+}
+
+void AbstractViewItem::begin_renaming()
+{
+ AbstractView &view = get_view();
+ if (view.is_renaming() || !supports_renaming()) {
+ return;
+ }
+
+ if (view.begin_renaming()) {
+ is_renaming_ = true;
+ }
+
+ StringRef initial_str = get_rename_string();
+ std::copy(std::begin(initial_str), std::end(initial_str), std::begin(view.get_rename_buffer()));
+}
+
+void AbstractViewItem::rename_apply()
+{
+ const AbstractView &view = get_view();
+ rename(view.get_rename_buffer().data());
+ end_renaming();
+}
+
+void AbstractViewItem::end_renaming()
+{
+ if (!is_renaming()) {
+ return;
+ }
+
+ is_renaming_ = false;
+
+ AbstractView &view = get_view();
+ view.end_renaming();
+}
+
+static AbstractViewItem *find_item_from_rename_button(const uiBut &rename_but)
+{
+ /* A minimal sanity check, can't do much more here. */
+ BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
+
+ LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
+ if (but->type != UI_BTYPE_VIEW_ITEM) {
+ continue;
+ }
+
+ uiButViewItem *view_item_but = (uiButViewItem *)but;
+ AbstractViewItem *item = reinterpret_cast<AbstractViewItem *>(view_item_but->view_item);
+ const AbstractView &view = item->get_view();
+
+ if (item->is_renaming() && (view.get_rename_buffer().data() == rename_but.poin)) {
+ return item;
+ }
+ }
+
+ return nullptr;
+}
+
+static void rename_button_fn(bContext *UNUSED(C), void *arg, char *UNUSED(origstr))
+{
+ const uiBut *rename_but = static_cast<uiBut *>(arg);
+ AbstractViewItem *item = find_item_from_rename_button(*rename_but);
+ BLI_assert(item);
+ item->rename_apply();
+}
+
+void AbstractViewItem::add_rename_button(uiBlock &block)
+{
+ AbstractView &view = get_view();
+ uiBut *rename_but = uiDefBut(&block,
+ UI_BTYPE_TEXT,
+ 1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ view.get_rename_buffer().data(),
+ 1.0f,
+ view.get_rename_buffer().size(),
+ 0,
+ 0,
+ "");
+
+ /* Gotta be careful with what's passed to the `arg1` here. Any view data will be freed once the
+ * callback is executed. */
+ UI_but_func_rename_set(rename_but, rename_button_fn, rename_but);
+ UI_but_flag_disable(rename_but, UI_BUT_UNDO);
+
+ const bContext *evil_C = reinterpret_cast<bContext *>(block.evil_C);
+ ARegion *region = CTX_wm_region(evil_C);
+ /* Returns false if the button was removed. */
+ if (UI_but_active_only(evil_C, region, &block, rename_but) == false) {
+ end_renaming();
+ }
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Context Menu
+ * \{ */
+
+void AbstractViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
+{
+ /* No context menu by default. */
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+std::unique_ptr<AbstractViewItemDragController> AbstractViewItem::create_drag_controller() const
+{
+ /* There's no drag controller (and hence no drag support) by default. */
+ return nullptr;
+}
+
+std::unique_ptr<AbstractViewItemDropController> AbstractViewItem::create_drop_controller() const
+{
+ /* There's no drop controller (and hence no drop support) by default. */
+ return nullptr;
+}
+
+AbstractViewItemDragController::AbstractViewItemDragController(AbstractView &view) : view_(view)
+{
+}
+
+void AbstractViewItemDragController::on_drag_start()
+{
+ /* Do nothing by default. */
+}
+
+AbstractViewItemDropController::AbstractViewItemDropController(AbstractView &view) : view_(view)
+{
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name General Getters & Setters
+ * \{ */
+
+AbstractView &AbstractViewItem::get_view() const
+{
+ if (UNLIKELY(!view_)) {
+ throw std::runtime_error(
+ "Invalid state, item must be registered through AbstractView::register_item()");
+ }
+ return *view_;
+}
+
+bool AbstractViewItem::is_active() const
+{
+ BLI_assert_msg(get_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
+ return is_active_;
+}
+
+/** \} */
+
+} // namespace blender::ui
+
+/* ---------------------------------------------------------------------- */
+/** \name C-API
+ * \{ */
+
+namespace blender::ui {
+
+/**
+ * Helper class to provide a higher level public (C-)API. Has access to private/protected view item
+ * members and ensures some invariants that way.
+ */
+class ViewItemAPIWrapper {
+ public:
+ static bool matches(const AbstractViewItem &a, const AbstractViewItem &b)
+ {
+ if (typeid(a) != typeid(b)) {
+ return false;
+ }
+ /* TODO should match the view as well. */
+ return a.matches(b);
+ }
+
+ static bool can_rename(const AbstractViewItem &item)
+ {
+ const AbstractView &view = item.get_view();
+ return !view.is_renaming() && item.supports_renaming();
+ }
+
+ static bool drag_start(bContext &C, const AbstractViewItem &item)
+ {
+ const std::unique_ptr<AbstractViewItemDragController> drag_controller =
+ item.create_drag_controller();
+ if (!drag_controller) {
+ return false;
+ }
+
+ WM_event_start_drag(&C,
+ ICON_NONE,
+ drag_controller->get_drag_type(),
+ drag_controller->create_drag_data(),
+ 0,
+ WM_DRAG_FREE_DATA);
+ drag_controller->on_drag_start();
+
+ return true;
+ }
+
+ static bool can_drop(const AbstractViewItem &item,
+ const wmDrag &drag,
+ const char **r_disabled_hint)
+ {
+ const std::unique_ptr<AbstractViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return false;
+ }
+
+ return drop_controller->can_drop(drag, r_disabled_hint);
+ }
+
+ static std::string drop_tooltip(const AbstractViewItem &item, const wmDrag &drag)
+ {
+ const std::unique_ptr<AbstractViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return {};
+ }
+
+ return drop_controller->drop_tooltip(drag);
+ }
+
+ static bool drop_handle(bContext &C, const AbstractViewItem &item, const ListBase &drags)
+ {
+ std::unique_ptr<AbstractViewItemDropController> drop_controller =
+ item.create_drop_controller();
+
+ const char *disabled_hint_dummy = nullptr;
+ LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
+ if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
+ return drop_controller->on_drop(&C, *drag);
+ }
+ }
+
+ return false;
+ }
+};
+
+} // namespace blender::ui
+
+using namespace blender::ui;
+
+bool UI_view_item_is_active(const uiViewItemHandle *item_handle)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
+ return item.is_active();
+}
+
+bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle)
+{
+ const AbstractViewItem &a = reinterpret_cast<const AbstractViewItem &>(*a_handle);
+ const AbstractViewItem &b = reinterpret_cast<const AbstractViewItem &>(*b_handle);
+ return ViewItemAPIWrapper::matches(a, b);
+}
+
+bool UI_view_item_can_rename(const uiViewItemHandle *item_handle)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
+ return ViewItemAPIWrapper::can_rename(item);
+}
+
+void UI_view_item_begin_rename(uiViewItemHandle *item_handle)
+{
+ AbstractViewItem &item = reinterpret_cast<AbstractViewItem &>(*item_handle);
+ item.begin_renaming();
+}
+
+void UI_view_item_context_menu_build(bContext *C,
+ const uiViewItemHandle *item_handle,
+ uiLayout *column)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
+ item.build_context_menu(*C, *column);
+}
+
+bool UI_view_item_drag_start(bContext *C, const uiViewItemHandle *item_)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+ return ViewItemAPIWrapper::drag_start(*C, item);
+}
+
+bool UI_view_item_can_drop(const uiViewItemHandle *item_,
+ const wmDrag *drag,
+ const char **r_disabled_hint)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+ return ViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
+}
+
+char *UI_view_item_drop_tooltip(const uiViewItemHandle *item_, const wmDrag *drag)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+
+ const std::string tooltip = ViewItemAPIWrapper::drop_tooltip(item, *drag);
+ return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
+}
+
+bool UI_view_item_drop_handle(bContext *C, const uiViewItemHandle *item_, const ListBase *drags)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+ return ViewItemAPIWrapper::drop_handle(*C, item, *drags);
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/grid_view.cc b/source/blender/editors/interface/views/grid_view.cc
index a82cb7798fe..52ff1460cbd 100644
--- a/source/blender/editors/interface/grid_view.cc
+++ b/source/blender/editors/interface/views/grid_view.cc
@@ -29,26 +29,19 @@ AbstractGridViewItem &AbstractGridView::add_item(std::unique_ptr<AbstractGridVie
items_.append(std::move(item));
AbstractGridViewItem &added_item = *items_.last();
- added_item.view_ = this;
-
item_map_.add(added_item.identifier_, &added_item);
+ register_item(added_item);
return added_item;
}
void AbstractGridView::foreach_item(ItemIterFn iter_fn) const
{
- for (auto &item_ptr : items_) {
+ for (const auto &item_ptr : items_) {
iter_fn(*item_ptr);
}
}
-bool AbstractGridView::listen(const wmNotifier &) const
-{
- /* Nothing by default. */
- return false;
-}
-
AbstractGridViewItem *AbstractGridView::find_matching_item(
const AbstractGridViewItem &item_to_match, const AbstractGridView &view_to_search_in) const
{
@@ -67,34 +60,18 @@ void AbstractGridView::change_state_delayed()
foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); });
}
-void AbstractGridView::update_from_old(uiBlock &new_block)
+void AbstractGridView::update_children_from_old(const AbstractView &old_view)
{
- uiGridViewHandle *old_view_handle = ui_block_grid_view_find_matching_in_old_block(
- &new_block, reinterpret_cast<uiGridViewHandle *>(this));
- if (!old_view_handle) {
- /* Initial construction, nothing to update. */
- is_reconstructed_ = true;
- return;
- }
+ const AbstractGridView &old_grid_view = dynamic_cast<const AbstractGridView &>(old_view);
- AbstractGridView &old_view = reinterpret_cast<AbstractGridView &>(*old_view_handle);
-
- foreach_item([this, &old_view](AbstractGridViewItem &new_item) {
- const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_view);
+ foreach_item([this, &old_grid_view](AbstractGridViewItem &new_item) {
+ const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_grid_view);
if (!matching_old_item) {
return;
}
new_item.update_from_old(*matching_old_item);
});
-
- /* Finished (re-)constructing the tree. */
- is_reconstructed_ = true;
-}
-
-bool AbstractGridView::is_reconstructed() const
-{
- return is_reconstructed_;
}
const GridViewStyle &AbstractGridView::get_style() const
@@ -117,18 +94,19 @@ AbstractGridViewItem::AbstractGridViewItem(StringRef identifier) : identifier_(i
{
}
-bool AbstractGridViewItem::matches(const AbstractGridViewItem &other) const
+bool AbstractGridViewItem::matches(const AbstractViewItem &other) const
{
- return identifier_ == other.identifier_;
+ const AbstractGridViewItem &other_grid_item = dynamic_cast<const AbstractGridViewItem &>(other);
+ return identifier_ == other_grid_item.identifier_;
}
void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
void *but_arg1,
void * /*arg2*/)
{
- uiButGridTile *grid_tile_but = (uiButGridTile *)but_arg1;
+ uiButViewItem *view_item_but = (uiButViewItem *)but_arg1;
AbstractGridViewItem &grid_item = reinterpret_cast<AbstractGridViewItem &>(
- *grid_tile_but->view_item);
+ *view_item_but->view_item);
grid_item.activate();
}
@@ -136,8 +114,8 @@ void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
{
const GridViewStyle &style = get_view().get_style();
- grid_tile_but_ = (uiButGridTile *)uiDefBut(&block,
- UI_BTYPE_GRID_TILE,
+ view_item_but_ = (uiButViewItem *)uiDefBut(&block,
+ UI_BTYPE_VIEW_ITEM,
0,
"",
0,
@@ -151,15 +129,8 @@ void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
0,
"");
- grid_tile_but_->view_item = reinterpret_cast<uiGridViewItemHandle *>(this);
- UI_but_func_set(&grid_tile_but_->but, grid_tile_click_fn, grid_tile_but_, nullptr);
-}
-
-bool AbstractGridViewItem::is_active() const
-{
- BLI_assert_msg(get_view().is_reconstructed(),
- "State can't be queried until reconstruction is completed");
- return is_active_;
+ view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
+ UI_but_func_set(&view_item_but_->but, grid_tile_click_fn, view_item_but_, nullptr);
}
void AbstractGridViewItem::on_activate()
@@ -180,11 +151,6 @@ void AbstractGridViewItem::change_state_delayed()
}
}
-void AbstractGridViewItem::update_from_old(const AbstractGridViewItem &old)
-{
- is_active_ = old.is_active_;
-}
-
void AbstractGridViewItem::activate()
{
BLI_assert_msg(get_view().is_reconstructed(),
@@ -213,7 +179,7 @@ const AbstractGridView &AbstractGridViewItem::get_view() const
throw std::runtime_error(
"Invalid state, item must be added through AbstractGridView::add_item()");
}
- return *view_;
+ return dynamic_cast<AbstractGridView &>(*view_);
}
/* ---------------------------------------------------------------------- */
@@ -243,17 +209,17 @@ class BuildOnlyVisibleButtonsHelper {
IndexRange visible_items_range_{};
public:
- BuildOnlyVisibleButtonsHelper(const View2D &,
+ BuildOnlyVisibleButtonsHelper(const View2D &v2d,
const AbstractGridView &grid_view,
int cols_per_row);
bool is_item_visible(int item_idx) const;
- void fill_layout_before_visible(uiBlock &) const;
- void fill_layout_after_visible(uiBlock &) const;
+ void fill_layout_before_visible(uiBlock &block) const;
+ void fill_layout_after_visible(uiBlock &block) const;
private:
IndexRange get_visible_range() const;
- void add_spacer_button(uiBlock &, int row_count) const;
+ void add_spacer_button(uiBlock &block, int row_count) const;
};
BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d,
@@ -495,31 +461,3 @@ std::optional<bool> PreviewGridItem::should_be_active() const
}
} // namespace blender::ui
-
-using namespace blender::ui;
-
-/* ---------------------------------------------------------------------- */
-/* C-API */
-
-using namespace blender::ui;
-
-bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle)
-{
- const AbstractGridViewItem &item = reinterpret_cast<const AbstractGridViewItem &>(*item_handle);
- return item.is_active();
-}
-
-bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view_handle,
- const wmNotifier *notifier)
-{
- const AbstractGridView &view = *reinterpret_cast<const AbstractGridView *>(view_handle);
- return view.listen(*notifier);
-}
-
-bool UI_grid_view_item_matches(const uiGridViewItemHandle *a_handle,
- const uiGridViewItemHandle *b_handle)
-{
- const AbstractGridViewItem &a = reinterpret_cast<const AbstractGridViewItem &>(*a_handle);
- const AbstractGridViewItem &b = reinterpret_cast<const AbstractGridViewItem &>(*b_handle);
- return a.matches(b);
-}
diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc
new file mode 100644
index 00000000000..c568a8cab74
--- /dev/null
+++ b/source/blender/editors/interface/views/interface_view.cc
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Code to manage views as part of the regular screen hierarchy. E.g. managing ownership of views
+ * inside blocks (#uiBlock.views), looking up items in the region, passing WM notifiers to views,
+ * etc.
+ *
+ * Blocks and their contained views are reconstructed on every redraw. This file also contains
+ * functions related to this recreation of views inside blocks. For example to query state
+ * information before the view is done reconstructing (#AbstractView.is_reconstructed() returns
+ * false), it may be enough to query the previous version of the block/view/view-item. Since such
+ * queries rely on the details of the UI reconstruction process, they should remain internal to
+ * `interface/` code.
+ */
+
+#include <memory>
+#include <type_traits>
+#include <variant>
+
+#include "DNA_screen_types.h"
+
+#include "BKE_screen.h"
+
+#include "BLI_listbase.h"
+
+#include "ED_screen.h"
+
+#include "interface_intern.h"
+
+#include "UI_interface.hh"
+
+#include "UI_abstract_view.hh"
+#include "UI_grid_view.hh"
+#include "UI_tree_view.hh"
+
+using namespace blender;
+using namespace blender::ui;
+
+/**
+ * Wrapper to store views in a #ListBase, addressable via an identifier.
+ */
+struct ViewLink : public Link {
+ std::string idname;
+ std::unique_ptr<AbstractView> view;
+};
+
+template<class T>
+static T *ui_block_add_view_impl(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractView> view)
+{
+ ViewLink *view_link = MEM_new<ViewLink>(__func__);
+ BLI_addtail(&block.views, view_link);
+
+ view_link->view = std::move(view);
+ view_link->idname = idname;
+
+ return dynamic_cast<T *>(view_link->view.get());
+}
+
+AbstractGridView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractGridView> grid_view)
+{
+ return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(grid_view));
+}
+
+AbstractTreeView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractTreeView> tree_view)
+{
+ return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
+}
+
+void ui_block_free_views(uiBlock *block)
+{
+ LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
+ MEM_delete(link);
+ }
+}
+
+void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
+{
+ ARegion *region = listener_params->region;
+
+ LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
+ if (view_link->view->listen(*listener_params->notifier)) {
+ ED_region_tag_redraw(region);
+ }
+ }
+}
+
+uiViewItemHandle *UI_region_views_find_item_at(const ARegion *region, const int xy[2])
+{
+ uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region, xy);
+ if (!item_but) {
+ return nullptr;
+ }
+
+ return item_but->view_item;
+}
+
+uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region)
+{
+ uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_active(region);
+ if (!item_but) {
+ return nullptr;
+ }
+
+ return item_but->view_item;
+}
+
+static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractView &view)
+{
+ /* First get the idname the of the view we're looking for. */
+ LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
+ if (view_link->view.get() == &view) {
+ return view_link->idname;
+ }
+ }
+
+ return {};
+}
+
+template<class T>
+static T *ui_block_view_find_matching_in_old_block_impl(const uiBlock &new_block,
+ const T &new_view)
+{
+ uiBlock *old_block = new_block.oldblock;
+ if (!old_block) {
+ return nullptr;
+ }
+
+ StringRef idname = ui_block_view_find_idname(new_block, new_view);
+ if (idname.is_empty()) {
+ return nullptr;
+ }
+
+ LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
+ if (old_view_link->idname == idname) {
+ return dynamic_cast<T *>(old_view_link->view.get());
+ }
+ }
+
+ return nullptr;
+}
+
+uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiViewHandle *new_view_handle)
+{
+ BLI_assert(new_block && new_view_handle);
+ const AbstractView &new_view = reinterpret_cast<const AbstractView &>(*new_view_handle);
+
+ AbstractView *old_view = ui_block_view_find_matching_in_old_block_impl(*new_block, new_view);
+ return reinterpret_cast<uiViewHandle *>(old_view);
+}
+
+uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
+ const uiBlock *new_block, const uiViewItemHandle *new_item_handle)
+{
+ uiBlock *old_block = new_block->oldblock;
+ if (!old_block) {
+ return nullptr;
+ }
+
+ const AbstractViewItem &new_item = *reinterpret_cast<const AbstractViewItem *>(new_item_handle);
+ const AbstractView *old_view = ui_block_view_find_matching_in_old_block_impl(
+ *new_block, new_item.get_view());
+ if (!old_view) {
+ return nullptr;
+ }
+
+ LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
+ if (old_but->type != UI_BTYPE_VIEW_ITEM) {
+ continue;
+ }
+ uiButViewItem *old_item_but = (uiButViewItem *)old_but;
+ if (!old_item_but->view_item) {
+ continue;
+ }
+ AbstractViewItem &old_item = *reinterpret_cast<AbstractViewItem *>(old_item_but->view_item);
+ /* Check if the item is from the expected view. */
+ if (&old_item.get_view() != old_view) {
+ continue;
+ }
+
+ if (UI_view_item_matches(reinterpret_cast<const uiViewItemHandle *>(&new_item),
+ reinterpret_cast<const uiViewItemHandle *>(&old_item))) {
+ return old_item_but;
+ }
+ }
+
+ return nullptr;
+}
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc
index f86d1c4d8bc..43fdf741ac5 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/views/tree_view.cc
@@ -37,9 +37,11 @@ AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
if (root_ == nullptr) {
root_ = this;
}
-
+ AbstractTreeView &tree_view = static_cast<AbstractTreeView &>(*root_);
AbstractTreeViewItem &added_item = *children_.last();
added_item.root_ = root_;
+ tree_view.register_item(added_item);
+
if (root_ != this) {
/* Any item that isn't the root can be assumed to the a #AbstractTreeViewItem. Not entirely
* nice to static_cast this, but well... */
@@ -68,45 +70,11 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
foreach_item_recursive(iter_fn, options);
}
-bool AbstractTreeView::listen(const wmNotifier &) const
+void AbstractTreeView::update_children_from_old(const AbstractView &old_view)
{
- /* Nothing by default. */
- return false;
-}
+ const AbstractTreeView &old_tree_view = dynamic_cast<const AbstractTreeView &>(old_view);
-bool AbstractTreeView::is_renaming() const
-{
- return rename_buffer_ != nullptr;
-}
-
-void AbstractTreeView::update_from_old(uiBlock &new_block)
-{
- uiBlock *old_block = new_block.oldblock;
- if (!old_block) {
- /* Initial construction, nothing to update. */
- is_reconstructed_ = true;
- return;
- }
-
- uiTreeViewHandle *old_view_handle = ui_block_tree_view_find_matching_in_old_block(
- &new_block, reinterpret_cast<uiTreeViewHandle *>(this));
- if (old_view_handle == nullptr) {
- is_reconstructed_ = true;
- return;
- }
-
- AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle);
-
- /* Update own persistent data. */
- /* Keep the rename buffer persistent while renaming! The rename button uses the buffer's
- * pointer to identify itself over redraws. */
- rename_buffer_ = std::move(old_view.rename_buffer_);
- old_view.rename_buffer_ = nullptr;
-
- update_children_from_old_recursive(*this, old_view);
-
- /* Finished (re-)constructing the tree. */
- is_reconstructed_ = true;
+ update_children_from_old_recursive(*this, old_tree_view);
}
void AbstractTreeView::update_children_from_old_recursive(const TreeViewOrItem &new_items,
@@ -129,7 +97,7 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{
for (const auto &iter_item : items.children_) {
- if (lookup_item.matches(*iter_item)) {
+ if (lookup_item.matches_single(*iter_item)) {
/* We have a matching item! */
return iter_item.get();
}
@@ -138,11 +106,6 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
return nullptr;
}
-bool AbstractTreeView::is_reconstructed() const
-{
- return is_reconstructed_;
-}
-
void AbstractTreeView::change_state_delayed()
{
BLI_assert_msg(
@@ -157,9 +120,8 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
void *but_arg1,
void * /*arg2*/)
{
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but_arg1;
- AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(
- *tree_row_but->tree_item);
+ uiButViewItem *item_but = (uiButViewItem *)but_arg1;
+ AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(*item_but->view_item);
tree_item.activate();
/* Not only activate the item, also show its children. Maybe this should be optional, or
@@ -170,11 +132,11 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
{
/* For some reason a width > (UI_UNIT_X * 2) make the layout system use all available width. */
- tree_row_but_ = (uiButTreeRow *)uiDefBut(
- &block, UI_BTYPE_TREEROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
+ view_item_but_ = (uiButViewItem *)uiDefBut(
+ &block, UI_BTYPE_VIEW_ITEM, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
- tree_row_but_->tree_item = reinterpret_cast<uiTreeViewItemHandle *>(this);
- UI_but_func_set(&tree_row_but_->but, tree_row_click_fn, tree_row_but_, nullptr);
+ view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
+ UI_but_func_set(&view_item_but_->but, tree_row_click_fn, view_item_but_, nullptr);
}
void AbstractTreeViewItem::add_indent(uiLayout &row) const
@@ -206,10 +168,10 @@ void AbstractTreeViewItem::collapse_chevron_click_fn(struct bContext *C,
const wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
- uiTreeViewItemHandle *hovered_item_handle = UI_block_tree_view_find_item_at(region,
- win->eventstate->xy);
- AbstractTreeViewItem *hovered_item = reinterpret_cast<AbstractTreeViewItem *>(
- hovered_item_handle);
+ uiViewItemHandle *hovered_item_handle = UI_region_views_find_item_at(region,
+ win->eventstate->xy);
+
+ AbstractTreeViewItem *hovered_item = from_item_handle<AbstractTreeViewItem>(hovered_item_handle);
BLI_assert(hovered_item != nullptr);
hovered_item->toggle_collapsed();
@@ -243,40 +205,6 @@ void AbstractTreeViewItem::add_collapse_chevron(uiBlock &block) const
BLI_assert(is_collapse_chevron_but(but));
}
-AbstractTreeViewItem *AbstractTreeViewItem::find_tree_item_from_rename_button(
- const uiBut &rename_but)
-{
- /* A minimal sanity check, can't do much more here. */
- BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
-
- LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
- if (but->type != UI_BTYPE_TREEROW) {
- continue;
- }
-
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
- AbstractTreeViewItem *item = reinterpret_cast<AbstractTreeViewItem *>(tree_row_but->tree_item);
- const AbstractTreeView &tree_view = item->get_tree_view();
-
- if (item->is_renaming() && (tree_view.rename_buffer_->data() == rename_but.poin)) {
- return item;
- }
- }
-
- return nullptr;
-}
-
-void AbstractTreeViewItem::rename_button_fn(bContext *UNUSED(C), void *arg, char *UNUSED(origstr))
-{
- const uiBut *rename_but = static_cast<uiBut *>(arg);
- AbstractTreeViewItem *item = find_tree_item_from_rename_button(*rename_but);
- BLI_assert(item);
-
- const AbstractTreeView &tree_view = item->get_tree_view();
- item->rename(tree_view.rename_buffer_->data());
- item->end_renaming();
-}
-
void AbstractTreeViewItem::add_rename_button(uiLayout &row)
{
uiBlock *block = uiLayoutGetBlock(&row);
@@ -286,33 +214,7 @@ void AbstractTreeViewItem::add_rename_button(uiLayout &row)
/* Enable emboss for the text button. */
UI_block_emboss_set(block, UI_EMBOSS);
- AbstractTreeView &tree_view = get_tree_view();
- uiBut *rename_but = uiDefBut(block,
- UI_BTYPE_TEXT,
- 1,
- "",
- 0,
- 0,
- UI_UNIT_X * 10,
- UI_UNIT_Y,
- tree_view.rename_buffer_->data(),
- 1.0f,
- tree_view.rename_buffer_->max_size(),
- 0,
- 0,
- "");
-
- /* Gotta be careful with what's passed to the `arg1` here. Any tree data will be freed once the
- * callback is executed. */
- UI_but_func_rename_set(rename_but, AbstractTreeViewItem::rename_button_fn, rename_but);
- UI_but_flag_disable(rename_but, UI_BUT_UNDO);
-
- const bContext *evil_C = static_cast<bContext *>(block->evil_C);
- ARegion *region = CTX_wm_region(evil_C);
- /* Returns false if the button was removed. */
- if (UI_but_active_only(evil_C, region, block, rename_but) == false) {
- end_renaming();
- }
+ AbstractViewItem::add_rename_button(*block);
UI_block_emboss_set(block, previous_emboss);
UI_block_layout_set_current(block, &row);
@@ -345,79 +247,35 @@ bool AbstractTreeViewItem::supports_collapsing() const
return true;
}
-std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
- const
+StringRef AbstractTreeViewItem::get_rename_string() const
{
- /* There's no drag controller (and hence no drag support) by default. */
- return nullptr;
-}
-
-std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create_drop_controller()
- const
-{
- /* There's no drop controller (and hence no drop support) by default. */
- return nullptr;
-}
-
-bool AbstractTreeViewItem::supports_renaming() const
-{
- /* No renaming by default. */
- return false;
+ return label_;
}
bool AbstractTreeViewItem::rename(StringRefNull new_name)
{
- /* It is important to update the label after renaming, so #AbstractTreeViewItem::matches()
+ /* It is important to update the label after renaming, so #AbstractTreeViewItem::matches_single()
* recognizes the item. (It only compares labels by default.) */
label_ = new_name;
return true;
}
-void AbstractTreeViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
+void AbstractTreeViewItem::update_from_old(const AbstractViewItem &old)
{
- /* No context menu by default. */
-}
+ AbstractViewItem::update_from_old(old);
-void AbstractTreeViewItem::update_from_old(const AbstractTreeViewItem &old)
-{
- is_open_ = old.is_open_;
- is_active_ = old.is_active_;
- is_renaming_ = old.is_renaming_;
+ const AbstractTreeViewItem &old_tree_item = dynamic_cast<const AbstractTreeViewItem &>(old);
+ is_open_ = old_tree_item.is_open_;
}
-bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
+bool AbstractTreeViewItem::matches_single(const AbstractTreeViewItem &other) const
{
return label_ == other.label_;
}
-void AbstractTreeViewItem::begin_renaming()
-{
- AbstractTreeView &tree_view = get_tree_view();
- if (tree_view.is_renaming() || !supports_renaming()) {
- return;
- }
-
- is_renaming_ = true;
-
- tree_view.rename_buffer_ = std::make_unique<decltype(tree_view.rename_buffer_)::element_type>();
- std::copy(std::begin(label_), std::end(label_), std::begin(*tree_view.rename_buffer_));
-}
-
-void AbstractTreeViewItem::end_renaming()
-{
- if (!is_renaming()) {
- return;
- }
-
- is_renaming_ = false;
-
- AbstractTreeView &tree_view = get_tree_view();
- tree_view.rename_buffer_ = nullptr;
-}
-
AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
{
- return static_cast<AbstractTreeView &>(*root_);
+ return dynamic_cast<AbstractTreeView &>(get_view());
}
int AbstractTreeViewItem::count_parents() const
@@ -453,26 +311,19 @@ void AbstractTreeViewItem::deactivate()
is_active_ = false;
}
-bool AbstractTreeViewItem::is_active() const
-{
- BLI_assert_msg(get_tree_view().is_reconstructed(),
- "State can't be queried until reconstruction is completed");
- return is_active_;
-}
-
bool AbstractTreeViewItem::is_hovered() const
{
BLI_assert_msg(get_tree_view().is_reconstructed(),
"State can't be queried until reconstruction is completed");
- BLI_assert_msg(tree_row_but_ != nullptr,
+ BLI_assert_msg(view_item_but_ != nullptr,
"Hovered state can't be queried before the tree row is being built");
- const uiTreeViewItemHandle *this_handle = reinterpret_cast<const uiTreeViewItemHandle *>(this);
+ const uiViewItemHandle *this_item_handle = reinterpret_cast<const uiViewItemHandle *>(this);
/* The new layout hasn't finished construction yet, so the final state of the button is unknown.
* Get the matching button from the previous redraw instead. */
- uiButTreeRow *old_treerow_but = ui_block_view_find_treerow_in_old_block(tree_row_but_->but.block,
- this_handle);
- return old_treerow_but && (old_treerow_but->but.flag & UI_ACTIVE);
+ uiButViewItem *old_item_but = ui_block_view_find_matching_view_item_but_in_old_block(
+ view_item_but_->but.block, this_item_handle);
+ return old_item_but && (old_item_but->but.flag & UI_ACTIVE);
}
bool AbstractTreeViewItem::is_collapsed() const
@@ -500,11 +351,6 @@ bool AbstractTreeViewItem::is_collapsible() const
return this->supports_collapsing();
}
-bool AbstractTreeViewItem::is_renaming() const
-{
- return is_renaming_;
-}
-
void AbstractTreeViewItem::ensure_parents_uncollapsed()
{
for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {
@@ -512,19 +358,21 @@ void AbstractTreeViewItem::ensure_parents_uncollapsed()
}
}
-bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem &other) const
+bool AbstractTreeViewItem::matches(const AbstractViewItem &other) const
{
- if (!matches(other)) {
+ const AbstractTreeViewItem &other_tree_item = dynamic_cast<const AbstractTreeViewItem &>(other);
+
+ if (!matches_single(other_tree_item)) {
return false;
}
- if (count_parents() != other.count_parents()) {
+ if (count_parents() != other_tree_item.count_parents()) {
return false;
}
- for (AbstractTreeViewItem *parent = parent_, *other_parent = other.parent_;
+ for (AbstractTreeViewItem *parent = parent_, *other_parent = other_tree_item.parent_;
parent && other_parent;
parent = parent->parent_, other_parent = other_parent->parent_) {
- if (!parent->matches(*other_parent)) {
+ if (!parent->matches_single(*other_parent)) {
return false;
}
}
@@ -532,9 +380,9 @@ bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem
return true;
}
-uiButTreeRow *AbstractTreeViewItem::tree_row_button()
+uiButViewItem *AbstractTreeViewItem::view_item_button()
{
- return tree_row_but_;
+ return view_item_but_;
}
void AbstractTreeViewItem::change_state_delayed()
@@ -547,25 +395,6 @@ void AbstractTreeViewItem::change_state_delayed()
/* ---------------------------------------------------------------------- */
-AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view)
- : tree_view_(tree_view)
-{
-}
-
-void AbstractTreeViewItemDragController::on_drag_start()
-{
- /* Do nothing by default. */
-}
-
-/* ---------------------------------------------------------------------- */
-
-AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
- : tree_view_(tree_view)
-{
-}
-
-/* ---------------------------------------------------------------------- */
-
class TreeViewLayoutBuilder {
uiBlock &block_;
@@ -611,7 +440,7 @@ void TreeViewLayoutBuilder::polish_layout(const uiBlock &block)
UI_but_drawflag_enable(static_cast<uiBut *>(but->next), UI_BUT_NO_TEXT_PADDING);
}
- if (but->type == UI_BTYPE_TREEROW) {
+ if (but->type == UI_BTYPE_VIEW_ITEM) {
break;
}
}
@@ -723,161 +552,4 @@ std::optional<bool> BasicTreeViewItem::should_be_active() const
return std::nullopt;
}
-/* ---------------------------------------------------------------------- */
-
-/**
- * Helper for a public (C-)API, presenting higher level functionality. Has access to internal
- * data/functionality (friend of #AbstractTreeViewItem), which is sometimes needed when
- * functionality of the API needs to be constructed from multiple internal conditions and/or
- * functions that on their own shouldn't be part of the API.
- */
-class TreeViewItemAPIWrapper {
- public:
- static bool matches(const AbstractTreeViewItem &a, const AbstractTreeViewItem &b)
- {
- /* TODO should match the tree-view as well. */
- return a.matches_including_parents(b);
- }
-
- static bool drag_start(bContext &C, const AbstractTreeViewItem &item)
- {
- const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
- item.create_drag_controller();
- if (!drag_controller) {
- return false;
- }
-
- WM_event_start_drag(&C,
- ICON_NONE,
- drag_controller->get_drag_type(),
- drag_controller->create_drag_data(),
- 0,
- WM_DRAG_FREE_DATA);
- drag_controller->on_drag_start();
-
- return true;
- }
-
- static bool can_drop(const AbstractTreeViewItem &item,
- const wmDrag &drag,
- const char **r_disabled_hint)
- {
- const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
- if (!drop_controller) {
- return false;
- }
-
- return drop_controller->can_drop(drag, r_disabled_hint);
- }
-
- static std::string drop_tooltip(const AbstractTreeViewItem &item, const wmDrag &drag)
- {
- const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
- if (!drop_controller) {
- return {};
- }
-
- return drop_controller->drop_tooltip(drag);
- }
-
- static bool drop_handle(bContext &C, const AbstractTreeViewItem &item, const ListBase &drags)
- {
- std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
-
- const char *disabled_hint_dummy = nullptr;
- LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
- if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
- return drop_controller->on_drop(&C, *drag);
- }
- }
-
- return false;
- }
-
- static bool can_rename(const AbstractTreeViewItem &item)
- {
- const AbstractTreeView &tree_view = item.get_tree_view();
- return !tree_view.is_renaming() && item.supports_renaming();
- }
-};
-
} // namespace blender::ui
-
-/* ---------------------------------------------------------------------- */
-/* C-API */
-
-using namespace blender::ui;
-
-bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view_handle,
- const wmNotifier *notifier)
-{
- const AbstractTreeView &view = *reinterpret_cast<const AbstractTreeView *>(view_handle);
- return view.listen(*notifier);
-}
-
-bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
- return item.is_active();
-}
-
-bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
- const uiTreeViewItemHandle *b_handle)
-{
- const AbstractTreeViewItem &a = reinterpret_cast<const AbstractTreeViewItem &>(*a_handle);
- const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
- return TreeViewItemAPIWrapper::matches(a, b);
-}
-
-bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- return TreeViewItemAPIWrapper::drag_start(*C, item);
-}
-
-bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
- const wmDrag *drag,
- const char **r_disabled_hint)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- return TreeViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
-}
-
-char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
-
- const std::string tooltip = TreeViewItemAPIWrapper::drop_tooltip(item, *drag);
- return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
-}
-
-bool UI_tree_view_item_drop_handle(bContext *C,
- const uiTreeViewItemHandle *item_,
- const ListBase *drags)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- return TreeViewItemAPIWrapper::drop_handle(*C, item, *drags);
-}
-
-bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
- return TreeViewItemAPIWrapper::can_rename(item);
-}
-
-void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle)
-{
- AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_handle);
- item.begin_renaming();
-}
-
-void UI_tree_view_item_context_menu_build(bContext *C,
- const uiTreeViewItemHandle *item_handle,
- uiLayout *column)
-{
- const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
- item.build_context_menu(*C, *column);
-}
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index a716c00d5d9..568ece00c4c 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -11,9 +11,9 @@ set(INC
../../io/collada
../../io/common
../../io/gpencil
+ ../../io/stl
../../io/usd
../../io/wavefront_obj
- ../../io/stl
../../makesdna
../../makesrna
../../windowmanager
@@ -33,8 +33,8 @@ set(SRC
io_gpencil_utils.c
io_obj.c
io_ops.c
- io_usd.c
io_stl_ops.c
+ io_usd.c
io_alembic.h
io_cache.h
@@ -42,8 +42,8 @@ set(SRC
io_gpencil.h
io_obj.h
io_ops.h
- io_usd.h
io_stl_ops.h
+ io_usd.h
)
set(LIB
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 0e8e0f83597..d4855f470ff 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -39,6 +39,7 @@
# include "RNA_define.h"
# include "RNA_enum_types.h"
+# include "ED_fileselect.h"
# include "ED_object.h"
# include "UI_interface.h"
@@ -75,20 +76,7 @@ static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *
RNA_boolean_set(op->ptr, "init_scene_frame_range", true);
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- Main *bmain = CTX_data_main(C);
- char filepath[FILE_MAX];
-
- if (BKE_main_blendfile_path(bmain)[0] == '\0') {
- BLI_strncpy(filepath, "untitled", sizeof(filepath));
- }
- else {
- BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
- }
-
- BLI_path_extension_replace(filepath, sizeof(filepath), ".abc");
- RNA_string_set(op->ptr, "filepath", filepath);
- }
+ ED_fileselect_ensure_default_filepath(C, op, ".abc");
WM_event_add_fileselect(C, op);
@@ -99,7 +87,7 @@ static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *
static int wm_alembic_export_exec(bContext *C, wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -144,10 +132,10 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
/* Take some defaults from the scene, if not specified explicitly. */
Scene *scene = CTX_data_scene(C);
if (params.frame_start == INT_MIN) {
- params.frame_start = SFRA;
+ params.frame_start = scene->r.sfra;
}
if (params.frame_end == INT_MIN) {
- params.frame_end = EFRA;
+ params.frame_end = scene->r.efra;
}
const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
@@ -248,8 +236,8 @@ static void wm_alembic_export_draw(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
if (scene != NULL && RNA_boolean_get(op->ptr, "init_scene_frame_range")) {
- RNA_int_set(op->ptr, "start", SFRA);
- RNA_int_set(op->ptr, "end", EFRA);
+ RNA_int_set(op->ptr, "start", scene->r.sfra);
+ RNA_int_set(op->ptr, "end", scene->r.efra);
RNA_boolean_set(op->ptr, "init_scene_frame_range", false);
}
@@ -619,7 +607,7 @@ static int wm_alembic_import_invoke(bContext *C, wmOperator *op, const wmEvent *
static int wm_alembic_import_exec(bContext *C, wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -651,16 +639,16 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
ED_object_mode_set(C, OB_MODE_OBJECT);
}
- bool ok = ABC_import(C,
- filename,
- scale,
- is_sequence,
- set_frame_range,
- sequence_len,
- offset,
- validate_meshes,
- always_add_cache_reader,
- as_background_job);
+ struct AlembicImportParams params = {0};
+ params.global_scale = scale;
+ params.sequence_len = sequence_len;
+ params.sequence_offset = offset;
+ params.is_sequence = is_sequence;
+ params.set_frame_range = set_frame_range;
+ params.validate_meshes = validate_meshes;
+ params.always_add_cache_reader = always_add_cache_reader;
+
+ bool ok = ABC_import(C, filename, &params, as_background_job);
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index c491e7a5815..3da7c00d5e2 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -19,6 +19,7 @@
# include "DEG_depsgraph.h"
+# include "ED_fileselect.h"
# include "ED_object.h"
# include "RNA_access.h"
@@ -36,22 +37,7 @@
static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Main *bmain = CTX_data_main(C);
-
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- char filepath[FILE_MAX];
- const char *blendfile_path = BKE_main_blendfile_path(bmain);
-
- if (blendfile_path[0] == '\0') {
- BLI_strncpy(filepath, "untitled", sizeof(filepath));
- }
- else {
- BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
- }
-
- BLI_path_extension_replace(filepath, sizeof(filepath), ".dae");
- RNA_string_set(op->ptr, "filepath", filepath);
- }
+ ED_fileselect_ensure_default_filepath(C, op, ".dae");
WM_event_add_fileselect(C, op);
@@ -98,7 +84,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int export_count;
int sample_animations;
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -709,7 +695,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
int keep_bind_info;
ImportSettings import_settings;
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index 6e5ae9f3cba..12d87113a66 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -20,6 +20,8 @@
# include "BLT_translation.h"
+# include "ED_fileselect.h"
+
# include "RNA_access.h"
# include "RNA_define.h"
@@ -71,24 +73,6 @@ static void gpencil_export_common_props_definition(wmOperatorType *ot)
"Normalize",
"Export strokes with constant thickness");
}
-
-static void set_export_filepath(bContext *C, wmOperator *op, const char *extension)
-{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- Main *bmain = CTX_data_main(C);
- char filepath[FILE_MAX];
-
- if (BKE_main_blendfile_path(bmain)[0] == '\0') {
- BLI_strncpy(filepath, "untitled", sizeof(filepath));
- }
- else {
- BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
- }
-
- BLI_path_extension_replace(filepath, sizeof(filepath), extension);
- RNA_string_set(op->ptr, "filepath", filepath);
- }
-}
# endif
/* <-------- SVG single frame export. --------> */
@@ -109,7 +93,7 @@ static bool wm_gpencil_export_svg_common_check(bContext *UNUSED(C), wmOperator *
static int wm_gpencil_export_svg_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- set_export_filepath(C, op, ".svg");
+ ED_fileselect_ensure_default_filepath(C, op, ".svg");
WM_event_add_fileselect(C, op);
@@ -121,7 +105,7 @@ static int wm_gpencil_export_svg_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -153,9 +137,9 @@ static int wm_gpencil_export_svg_exec(bContext *C, wmOperator *op)
.v3d = v3d,
.ob = ob,
.mode = GP_EXPORT_TO_SVG,
- .frame_start = CFRA,
- .frame_end = CFRA,
- .frame_cur = CFRA,
+ .frame_start = scene->r.cfra,
+ .frame_end = scene->r.cfra,
+ .frame_cur = scene->r.cfra,
.flag = flag,
.scale = 1.0f,
.select_mode = select_mode,
@@ -264,7 +248,7 @@ static bool wm_gpencil_export_pdf_common_check(bContext *UNUSED(C), wmOperator *
static int wm_gpencil_export_pdf_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- set_export_filepath(C, op, ".pdf");
+ ED_fileselect_ensure_default_filepath(C, op, ".pdf");
WM_event_add_fileselect(C, op);
@@ -276,7 +260,7 @@ static int wm_gpencil_export_pdf_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -306,9 +290,9 @@ static int wm_gpencil_export_pdf_exec(bContext *C, wmOperator *op)
.v3d = v3d,
.ob = ob,
.mode = GP_EXPORT_TO_PDF,
- .frame_start = SFRA,
- .frame_end = EFRA,
- .frame_cur = CFRA,
+ .frame_start = scene->r.sfra,
+ .frame_end = scene->r.efra,
+ .frame_cur = scene->r.cfra,
.flag = flag,
.scale = 1.0f,
.select_mode = select_mode,
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index 45f5441616f..eb53f66d8b8 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -9,6 +9,8 @@
# include "BLI_path_util.h"
+# include "MEM_guardedalloc.h"
+
# include "DNA_gpencil_types.h"
# include "DNA_space_types.h"
@@ -63,7 +65,8 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false) ||
+ !(RNA_struct_find_property(op->ptr, "directory"))) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -75,9 +78,6 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
}
View3D *v3d = get_invoke_view3d(C);
- char filename[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", filename);
-
/* Set flags. */
int flag = 0;
@@ -90,9 +90,9 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
.v3d = v3d,
.ob = NULL,
.mode = GP_IMPORT_FROM_SVG,
- .frame_start = CFRA,
- .frame_end = CFRA,
- .frame_cur = CFRA,
+ .frame_start = scene->r.cfra,
+ .frame_end = scene->r.cfra,
+ .frame_cur = scene->r.cfra,
.flag = flag,
.scale = scale,
.select_mode = 0,
@@ -101,13 +101,31 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
.resolution = resolution,
};
- /* Do Import. */
- WM_cursor_wait(1);
- const bool done = gpencil_io_import(filename, &params);
- WM_cursor_wait(0);
-
- if (!done) {
- BKE_report(op->reports, RPT_WARNING, "Unable to import SVG");
+ /* Loop all selected files to import them. All SVG imported shared the same import
+ * parameters, but they are created in separated grease pencil objects. */
+ PropertyRNA *prop;
+ if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
+ char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL);
+
+ if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
+ char file_path[FILE_MAX];
+ RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
+ BLI_join_dirfile(file_path, sizeof(file_path), directory, filename);
+ MEM_freeN(filename);
+
+ /* Do Import. */
+ WM_cursor_wait(1);
+ RNA_string_get(&itemptr, "name", params.filename);
+ const bool done = gpencil_io_import(file_path, &params);
+ WM_cursor_wait(0);
+ if (!done) {
+ BKE_reportf(op->reports, RPT_WARNING, "Unable to import '%s'", file_path);
+ }
+ }
+ RNA_PROP_END;
+ }
+ MEM_freeN(directory);
}
return OPERATOR_FINISHED;
@@ -149,10 +167,11 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
ot->check = wm_gpencil_import_svg_common_check;
WM_operator_properties_filesel(ot,
- FILE_TYPE_OBJECT_IO,
+ FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
FILE_BLENDER,
FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS |
+ WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index 4819ae09785..0c935a0e1da 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -18,6 +18,7 @@
# include "BLT_translation.h"
+# include "ED_fileselect.h"
# include "ED_outliner.h"
# include "MEM_guardedalloc.h"
@@ -58,20 +59,7 @@ static const EnumPropertyItem io_obj_path_mode[] = {
static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- Main *bmain = CTX_data_main(C);
- char filepath[FILE_MAX];
-
- if (BKE_main_blendfile_path(bmain)[0] == '\0') {
- BLI_strncpy(filepath, "untitled", sizeof(filepath));
- }
- else {
- BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
- }
-
- BLI_path_extension_replace(filepath, sizeof(filepath), ".obj");
- RNA_string_set(op->ptr, "filepath", filepath);
- }
+ ED_fileselect_ensure_default_filepath(C, op, ".obj");
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -79,7 +67,7 @@ static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
static int wm_obj_export_exec(bContext *C, wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -208,11 +196,11 @@ static bool wm_obj_export_check(bContext *C, wmOperator *op)
int end = RNA_int_get(op->ptr, "end_frame");
/* Set the defaults. */
if (start == INT_MIN) {
- start = SFRA;
+ start = scene->r.sfra;
changed = true;
}
if (end == INT_MAX) {
- end = EFRA;
+ end = scene->r.efra;
changed = true;
}
/* Fix user errors. */
@@ -266,7 +254,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Export multiple frames instead of the current frame only");
RNA_def_int(ot->srna,
"start_frame",
- INT_MIN, /* wm_obj_export_check uses this to set SFRA. */
+ INT_MIN, /* wm_obj_export_check uses this to set scene->r.sfra. */
INT_MIN,
INT_MAX,
"Start Frame",
@@ -275,7 +263,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
INT_MAX);
RNA_def_int(ot->srna,
"end_frame",
- INT_MAX, /* wm_obj_export_check uses this to set EFRA. */
+ INT_MAX, /* wm_obj_export_check uses this to set scene->r.efra. */
INT_MIN,
INT_MAX,
"End Frame",
@@ -382,19 +370,43 @@ static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
static int wm_obj_import_exec(bContext *C, wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- BKE_report(op->reports, RPT_ERROR, "No filename given");
- return OPERATOR_CANCELLED;
- }
-
struct OBJImportParams import_params;
RNA_string_get(op->ptr, "filepath", import_params.filepath);
import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size");
import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
import_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ import_params.import_vertex_groups = RNA_boolean_get(op->ptr, "import_vertex_groups");
import_params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
-
- OBJ_import(C, &import_params);
+ import_params.relative_paths = ((U.flag & USER_RELPATHS) != 0);
+ import_params.clear_selection = true;
+
+ int files_len = RNA_collection_length(op->ptr, "files");
+ if (files_len) {
+ /* Importing multiple files: loop over them and import one by one. */
+ PointerRNA fileptr;
+ PropertyRNA *prop;
+ char dir_only[FILE_MAX], file_only[FILE_MAX];
+
+ RNA_string_get(op->ptr, "directory", dir_only);
+ prop = RNA_struct_find_property(op->ptr, "files");
+ for (int i = 0; i < files_len; i++) {
+ RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
+ RNA_string_get(&fileptr, "name", file_only);
+ BLI_join_dirfile(
+ import_params.filepath, sizeof(import_params.filepath), dir_only, file_only);
+ import_params.clear_selection = (i == 0);
+ OBJ_import(C, &import_params);
+ }
+ }
+ else if (RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
+ /* Importing one file. */
+ RNA_string_get(op->ptr, "filepath", import_params.filepath);
+ OBJ_import(C, &import_params);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
Scene *scene = CTX_data_scene(C);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -422,6 +434,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr)
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Options"), ICON_EXPORT);
col = uiLayoutColumn(box, false);
+ uiItemR(col, imfptr, "import_vertex_groups", 0, NULL, ICON_NONE);
uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
}
@@ -451,7 +464,8 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS |
+ WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
RNA_def_float(
@@ -468,6 +482,11 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_boolean(ot->srna,
+ "import_vertex_groups",
+ false,
+ "Vertex Groups",
+ "Import OBJ groups as vertex groups");
+ RNA_def_boolean(ot->srna,
"validate_meshes",
false,
"Validate Meshes",
diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c
index 7db32cd6f18..858ea131577 100644
--- a/source/blender/editors/io/io_stl_ops.c
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -53,7 +53,7 @@ static int wm_stl_import_execute(bContext *C, wmOperator *op)
STL_import(C, &params);
}
}
- else if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ else if (RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
RNA_string_get(op->ptr, "filepath", params.filepath);
STL_import(C, &params);
}
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index a59cdf60243..74ce0cca16c 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -21,6 +21,7 @@
# include "BLT_translation.h"
+# include "ED_fileselect.h"
# include "ED_object.h"
# include "MEM_guardedalloc.h"
@@ -84,21 +85,7 @@ static int wm_usd_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
options->as_background_job = true;
op->customdata = options;
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- Main *bmain = CTX_data_main(C);
- char filepath[FILE_MAX];
- const char *main_blendfile_path = BKE_main_blendfile_path(bmain);
-
- if (main_blendfile_path[0] == '\0') {
- BLI_strncpy(filepath, "untitled", sizeof(filepath));
- }
- else {
- BLI_strncpy(filepath, main_blendfile_path, sizeof(filepath));
- }
-
- BLI_path_extension_replace(filepath, sizeof(filepath), ".usdc");
- RNA_string_set(op->ptr, "filepath", filepath);
- }
+ ED_fileselect_ensure_default_filepath(C, op, ".usdc");
WM_event_add_fileselect(C, op);
@@ -107,7 +94,7 @@ static int wm_usd_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
static int wm_usd_export_exec(bContext *C, wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -331,7 +318,7 @@ static int wm_usd_import_invoke(bContext *C, wmOperator *op, const wmEvent *even
static int wm_usd_import_exec(bContext *C, wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 7615a57c8fe..64c03c217de 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -46,7 +46,7 @@ static CLG_LogRef LOG = {"ed.undo.lattice"};
/** \name Undo Conversion
* \{ */
-/* TODO(Campbell): this could contain an entire 'Lattice' struct. */
+/* TODO(@campbellbarton): this could contain an entire 'Lattice' struct. */
typedef struct UndoLattice {
BPoint *def;
int pntsu, pntsv, pntsw, actbp;
@@ -132,7 +132,7 @@ static int validate_undoLatt(void *data, void *edata)
static Object *editlatt_object_from_context(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit && obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
if (lt->editlatt != NULL) {
diff --git a/source/blender/editors/mask/CMakeLists.txt b/source/blender/editors/mask/CMakeLists.txt
index fdb0d13f364..593eeb6c69d 100644
--- a/source/blender/editors/mask/CMakeLists.txt
+++ b/source/blender/editors/mask/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 194170b1677..df30870007f 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -258,7 +258,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
&u,
NULL)) {
Scene *scene = CTX_data_scene(C);
- const float ctime = CFRA;
+ const float ctime = scene->r.cfra;
MaskSplinePoint *new_point;
int point_index = point - spline->points;
@@ -295,7 +295,7 @@ static bool add_vertex_extrude(const bContext *C,
const float co[2])
{
Scene *scene = CTX_data_scene(C);
- const float ctime = CFRA;
+ const float ctime = scene->r.cfra;
MaskSpline *spline;
MaskSplinePoint *point;
@@ -394,7 +394,7 @@ static bool add_vertex_extrude(const bContext *C,
static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer, const float co[2])
{
Scene *scene = CTX_data_scene(C);
- const float ctime = CFRA;
+ const float ctime = scene->r.cfra;
MaskSpline *spline;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
@@ -583,7 +583,7 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
/* api callbacks */
ot->exec = add_vertex_exec;
ot->invoke = add_vertex_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -862,7 +862,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = primitive_circle_add_exec;
ot->invoke = primitive_add_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -874,7 +874,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Primitive Add Suqare Operator
+/** \name Primitive Add Square Operator
* \{ */
static int primitive_square_add_exec(bContext *C, wmOperator *op)
@@ -897,7 +897,7 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = primitive_square_add_exec;
ot->invoke = primitive_add_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index aab4007854f..3b16497f09f 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -110,7 +110,7 @@ static void draw_single_handle(const MaskLayer *mask_layer,
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uchar rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3ubv(rgb_gray);
/* this could be split into its own loop */
@@ -171,12 +171,10 @@ static void draw_single_handle(const MaskLayer *mask_layer,
static void draw_spline_points(const bContext *C,
MaskLayer *mask_layer,
MaskSpline *spline,
- const char draw_flag,
const char draw_type)
{
const bool is_spline_sel = (spline->flag & SELECT) &&
(mask_layer->visibility_flag & MASK_HIDE_SELECT) == 0;
- const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
uchar rgb_spline[4];
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
@@ -253,9 +251,7 @@ static void draw_spline_points(const bContext *C,
immUnbindProgram();
- if (is_smooth) {
- GPU_line_smooth(true);
- }
+ GPU_line_smooth(true);
/* control points */
INIT_MINMAX2(min, max);
@@ -323,9 +319,7 @@ static void draw_spline_points(const bContext *C,
minmax_v2v2_v2(min, max, vert);
}
- if (is_smooth) {
- GPU_line_smooth(false);
- }
+ GPU_line_smooth(false);
if (is_spline_sel) {
float x = (min[0] + max[0]) * 0.5f;
@@ -414,7 +408,7 @@ static void mask_draw_curve_type(const bContext *C,
/* TODO(merwin): use fancy line shader here
* probably better with geometry shader (after core profile switch)
*/
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_width(3.0f);
@@ -433,7 +427,7 @@ static void mask_draw_curve_type(const bContext *C,
case MASK_DT_BLACK:
case MASK_DT_WHITE:
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_width(1.0f);
if (draw_type == MASK_DT_BLACK) {
@@ -471,7 +465,7 @@ static void mask_draw_curve_type(const bContext *C,
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
rgba_uchar_to_float(colors[1], rgb_tmp);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -502,7 +496,6 @@ static void mask_draw_curve_type(const bContext *C,
static void draw_spline_curve(const bContext *C,
MaskLayer *mask_layer,
MaskSpline *spline,
- const char draw_flag,
const char draw_type,
const bool is_active,
const int width,
@@ -515,7 +508,6 @@ static void draw_spline_curve(const bContext *C,
const bool is_spline_sel = (spline->flag & SELECT) &&
(mask_layer->visibility_flag & MASK_HIDE_SELECT) == 0;
- const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
uint tot_diff_point;
@@ -530,9 +522,7 @@ static void draw_spline_curve(const bContext *C,
return;
}
- if (is_smooth) {
- GPU_line_smooth(true);
- }
+ GPU_line_smooth(true);
feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
spline, resol, (is_fill != false), &tot_feather_point);
@@ -567,14 +557,11 @@ static void draw_spline_curve(const bContext *C,
C, spline, diff_points, tot_diff_point, false, is_active, rgb_tmp, draw_type);
MEM_freeN(diff_points);
- if (is_smooth) {
- GPU_line_smooth(false);
- }
+ GPU_line_smooth(false);
}
static void draw_layer_splines(const bContext *C,
MaskLayer *layer,
- const char draw_flag,
const char draw_type,
const int width,
const int height,
@@ -582,11 +569,11 @@ static void draw_layer_splines(const bContext *C,
{
LISTBASE_FOREACH (MaskSpline *, spline, &layer->splines) {
/* draw curve itself first... */
- draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_curve(C, layer, spline, draw_type, is_active, width, height);
if (!(layer->visibility_flag & MASK_HIDE_SELECT)) {
/* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ draw_spline_points(C, layer, spline, draw_type);
}
/* show undeform for testing */
@@ -594,19 +581,15 @@ static void draw_layer_splines(const bContext *C,
void *back = spline->points_deform;
spline->points_deform = NULL;
- draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
- draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ draw_spline_curve(C, layer, spline, draw_type, is_active, width, height);
+ draw_spline_points(C, layer, spline, draw_type);
spline->points_deform = back;
}
}
}
-static void draw_mask_layers(const bContext *C,
- Mask *mask,
- const char draw_flag,
- const char draw_type,
- const int width,
- const int height)
+static void draw_mask_layers(
+ const bContext *C, Mask *mask, const char draw_type, const int width, const int height)
{
GPU_blend(GPU_BLEND_ALPHA);
GPU_program_point_size(true);
@@ -628,11 +611,11 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- draw_layer_splines(C, mask_layer, draw_flag, draw_type, width, height, is_active);
+ draw_layer_splines(C, mask_layer, draw_type, width, height, is_active);
}
if (active != NULL) {
- draw_layer_splines(C, active, draw_flag, draw_type, width, height, true);
+ draw_layer_splines(C, active, draw_type, width, height, true);
}
GPU_program_point_size(false);
@@ -663,6 +646,7 @@ void ED_mask_draw_region(
const char draw_flag,
const char draw_type,
const eMaskOverlayMode overlay_mode,
+ const float blend_factor,
/* convert directly into aspect corrected vars */
const int width_i,
const int height_i,
@@ -721,12 +705,14 @@ void ED_mask_draw_region(
}
if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
- const float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float buf_col[4] = {1.0f, 0.0f, 0.0f, 0.0f};
float *buffer = mask_rasterize(mask_eval, width, height);
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
/* More blending types could be supported in the future. */
- GPU_blend(GPU_BLEND_MULTIPLY);
+ GPU_blend(GPU_BLEND_ALPHA);
+ buf_col[0] = -1.0f;
+ buf_col[3] = 1.0f;
}
GPU_matrix_push();
@@ -737,10 +723,18 @@ void ED_mask_draw_region(
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTexTiled(
- &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, buf_col);
+
+ if (overlay_mode == MASK_OVERLAY_COMBINED) {
+ const float blend_col[4] = {0.0f, 0.0f, 0.0f, blend_factor};
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, blend_col);
+ }
+ else {
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ }
GPU_matrix_pop();
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
@@ -765,7 +759,9 @@ void ED_mask_draw_region(
}
/* draw! */
- draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height);
+ if (draw_flag & MASK_DRAWFLAG_SPLINE) {
+ draw_mask_layers(C, mask_eval, draw_type, width, height);
+ }
if (do_draw_cb) {
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
@@ -796,7 +792,7 @@ void ED_mask_draw_frames(
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(255, 175, 0, 255);
immBegin(GPU_PRIM_LINES, 2 * num_lines);
@@ -806,7 +802,7 @@ void ED_mask_draw_frames(
mask_layer_shape = mask_layer_shape->next) {
int frame = mask_layer_shape->frame;
- // draw_keyframe(i, CFRA, sfra, framelen, 1);
+ // draw_keyframe(i, scene->r.cfra, sfra, framelen, 1);
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
immVertex2i(pos, x, region_bottom);
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index b2d49bcc642..915f90a1537 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -42,6 +42,22 @@ bool ED_maskedit_poll(bContext *C)
return false;
}
+bool ED_maskedit_visible_splines_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_CLIP:
+ return ED_space_clip_maskedit_visible_splines_poll(C);
+ case SPACE_SEQ:
+ return ED_space_sequencer_maskedit_poll(C);
+ case SPACE_IMAGE:
+ return ED_space_image_maskedit_visible_splines_poll(C);
+ }
+ }
+ return false;
+}
+
bool ED_maskedit_mask_poll(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -58,6 +74,22 @@ bool ED_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ const ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_CLIP:
+ return ED_space_clip_maskedit_mask_visible_splines_poll(C);
+ case SPACE_SEQ:
+ return ED_space_sequencer_maskedit_mask_poll(C);
+ case SPACE_IMAGE:
+ return ED_space_image_maskedit_mask_visible_splines_poll(C);
+ }
+ }
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index 8a23a53a5d2..9819532224e 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -304,7 +304,7 @@ static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *
static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
{
if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
- mask_layer_shape->frame = (int)CFRA;
+ mask_layer_shape->frame = (int)scene->r.cfra;
}
return false;
}
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index c620d781c7f..2e99b45f215 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -86,9 +86,6 @@ void ED_mask_select_flush_all(struct Mask *mask);
/* mask_editor.c */
-bool ED_maskedit_poll(struct bContext *C);
-bool ED_maskedit_mask_poll(struct bContext *C);
-
/* Generalized solution for preserving editor viewport when making changes while lock-to-selection
* is enabled.
* Any mask operator can use this API, without worrying that some editors do not have an idea of
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 3c0e7ee399c..d34b274c111 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -113,7 +113,7 @@ void MASK_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_new_exec;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_poll;
/* properties */
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask");
@@ -146,7 +146,7 @@ void MASK_OT_layer_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_new_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -181,7 +181,7 @@ void MASK_OT_layer_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_remove_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -856,7 +856,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Don't key sliding feather UW's. */
if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(data->mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(data->mask_layer, scene->r.cfra);
}
}
@@ -907,7 +907,7 @@ void MASK_OT_slide_point(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_point_invoke;
ot->modal = slide_point_modal;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1262,7 +1262,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
if (event->type == slide_data->event_invoke_type && event->val == KM_RELEASE) {
/* Don't key sliding feather UW's. */
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(slide_data->mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(slide_data->mask_layer, scene->r.cfra);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
@@ -1297,7 +1297,7 @@ void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_spline_curvature_invoke;
ot->modal = slide_spline_curvature_modal;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1336,7 +1336,7 @@ void MASK_OT_cyclic_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = cyclic_toggle_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1493,7 +1493,7 @@ void MASK_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = delete_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1525,7 +1525,7 @@ static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
if (changed_layer) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(mask_layer, scene->r.cfra);
}
}
}
@@ -1551,7 +1551,7 @@ void MASK_OT_switch_direction(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_switch_direction_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1587,7 +1587,7 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
if (changed_layer) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(mask_layer, scene->r.cfra);
}
}
}
@@ -1613,7 +1613,7 @@ void MASK_OT_normals_make_consistent(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_normals_make_consistent_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1693,7 +1693,7 @@ void MASK_OT_handle_type_set(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = set_handle_type_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1849,7 +1849,7 @@ void MASK_OT_feather_weight_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_feather_weight_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2043,7 +2043,7 @@ void MASK_OT_duplicate(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_duplicate_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2084,7 +2084,7 @@ void MASK_OT_copy_splines(wmOperatorType *ot)
static bool paste_splines_poll(bContext *C)
{
- if (ED_maskedit_mask_poll(C)) {
+ if (ED_maskedit_mask_visible_splines_poll(C)) {
return BKE_mask_clipboard_is_empty() == false;
}
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index 02e1524e23e..bb865e925d7 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -682,8 +682,7 @@ void ED_mask_get_size(ScrArea *area, int *width, int *height)
}
case SPACE_SEQ: {
// Scene *scene = CTX_data_scene(C);
- // *width = (scene->r.size * scene->r.xsch) / 100;
- // *height = (scene->r.size * scene->r.ysch) / 100;
+ // BKE_render_resolution(&scene->r, false, width, height);
break;
}
case SPACE_IMAGE: {
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 9d8b84de66b..1f175ce51fc 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -21,6 +21,7 @@
#include "WM_types.h"
#include "ED_clip.h" /* frame remapping functions */
+#include "ED_mask.h"
#include "ED_screen.h"
#include "mask_intern.h" /* own include */
@@ -61,7 +62,7 @@ void MASK_OT_parent_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_parent_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index e5fe108b6cd..95cad3f54ca 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -31,8 +31,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph.h"
-
#include "mask_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -222,7 +220,7 @@ void MASK_OT_select_all(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_all_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -398,7 +396,7 @@ void MASK_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_exec;
ot->invoke = select_invoke;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->get_name = ED_select_pick_get_name;
/* flags */
@@ -504,7 +502,7 @@ void MASK_OT_select_box(wmOperatorType *ot)
ot->invoke = WM_gesture_box_invoke;
ot->exec = box_select_exec;
ot->modal = WM_gesture_box_modal;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -627,7 +625,7 @@ void MASK_OT_select_lasso(wmOperatorType *ot)
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = clip_lasso_select_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
@@ -745,7 +743,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->get_name = ED_select_circle_get_name;
/* flags */
@@ -809,7 +807,7 @@ void MASK_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = mask_select_linked_pick_invoke;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -864,7 +862,7 @@ void MASK_OT_select_linked(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_linked_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -963,7 +961,7 @@ void MASK_OT_select_more(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_more_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -983,7 +981,7 @@ void MASK_OT_select_less(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_less_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index dd54d84a90b..48944c081a8 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -33,7 +33,7 @@
static int mask_shape_key_insert_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -67,7 +67,7 @@ void MASK_OT_shape_key_insert(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_insert_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -76,7 +76,7 @@ void MASK_OT_shape_key_insert(wmOperatorType *ot)
static int mask_shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -113,7 +113,7 @@ void MASK_OT_shape_key_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -122,7 +122,7 @@ void MASK_OT_shape_key_clear(wmOperatorType *ot)
static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -197,7 +197,7 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_feather_reset_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -214,7 +214,7 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot)
static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -356,7 +356,7 @@ void MASK_OT_shape_key_rekey(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_rekey_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 28ac913a3e3..218564eaf30 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -17,7 +17,6 @@ set(INC
../../render
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc
index 69fe69fe117..f729db29b8c 100644
--- a/source/blender/editors/mesh/editface.cc
+++ b/source/blender/editors/mesh/editface.cc
@@ -17,6 +17,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
@@ -36,14 +37,16 @@
/* own include */
-void paintface_flush_flags(bContext *C, Object *ob, short flag)
+void paintface_flush_flags(bContext *C,
+ Object *ob,
+ const bool flush_selection,
+ const bool flush_hidden)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
- MPoly *polys, *mp_orig;
const int *index_array = nullptr;
- int totpoly;
- BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0);
+ BLI_assert(flush_selection || flush_hidden);
if (me == nullptr) {
return;
@@ -53,7 +56,7 @@ void paintface_flush_flags(bContext *C, Object *ob, short flag)
/* we could call this directly in all areas that change selection,
* since this could become slow for realtime updates (circle-select for eg) */
- if (flag & SELECT) {
+ if (flush_selection) {
BKE_mesh_flush_select_from_polys(me);
}
@@ -64,40 +67,57 @@ void paintface_flush_flags(bContext *C, Object *ob, short flag)
return;
}
+ bke::AttributeAccessor attributes_me = me->attributes();
Mesh *me_orig = (Mesh *)ob_eval->runtime.data_orig;
+ bke::MutableAttributeAccessor attributes_orig = me_orig->attributes_for_write();
Mesh *me_eval = (Mesh *)ob_eval->runtime.data_eval;
+ bke::MutableAttributeAccessor attributes_eval = me_eval->attributes_for_write();
bool updated = false;
+ const Span<MPoly> me_polys = me->polys();
if (me_orig != nullptr && me_eval != nullptr && me_orig->totpoly == me->totpoly) {
/* Update the COW copy of the mesh. */
+ MutableSpan<MPoly> orig_polys = me_orig->polys_for_write();
for (int i = 0; i < me->totpoly; i++) {
- me_orig->mpoly[i].flag = me->mpoly[i].flag;
+ orig_polys[i].flag = me_polys[i].flag;
}
-
- /* If the mesh has only deform modifiers, the evaluated mesh shares arrays. */
- if (me_eval->mpoly == me_orig->mpoly) {
- updated = true;
+ if (flush_hidden) {
+ const VArray<bool> hide_poly_me = attributes_me.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+ bke::SpanAttributeWriter<bool> hide_poly_orig =
+ attributes_orig.lookup_or_add_for_write_only_span<bool>(".hide_poly", ATTR_DOMAIN_FACE);
+ hide_poly_me.materialize(hide_poly_orig.span);
+ hide_poly_orig.finish();
}
- /* Mesh polys => Final derived polys */
- else if ((index_array = (const int *)CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) {
- polys = me_eval->mpoly;
- totpoly = me_eval->totpoly;
+ /* Mesh polys => Final derived polys */
+ if ((index_array = (const int *)CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) {
+ MutableSpan<MPoly> eval_polys = me_orig->polys_for_write();
/* loop over final derived polys */
- for (int i = 0; i < totpoly; i++) {
+ for (const int i : eval_polys.index_range()) {
if (index_array[i] != ORIGINDEX_NONE) {
/* Copy flags onto the final derived poly from the original mesh poly */
- mp_orig = me->mpoly + index_array[i];
- polys[i].flag = mp_orig->flag;
+ eval_polys[i].flag = me_polys[index_array[i]].flag;
}
}
+ const VArray<bool> hide_poly_orig = attributes_orig.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+ bke::SpanAttributeWriter<bool> hide_poly_eval =
+ attributes_eval.lookup_or_add_for_write_only_span<bool>(".hide_poly", ATTR_DOMAIN_FACE);
+ for (const int i : IndexRange(me_eval->totpoly)) {
+ const int orig_poly_index = index_array[i];
+ if (orig_poly_index != ORIGINDEX_NONE) {
+ hide_poly_eval.span[i] = hide_poly_orig[orig_poly_index];
+ }
+ }
+ hide_poly_eval.finish();
updated = true;
}
}
if (updated) {
- if (flag & ME_HIDE) {
+ if (flush_hidden) {
BKE_mesh_batch_cache_dirty_tag(me_eval, BKE_MESH_BATCH_DIRTY_ALL);
}
else {
@@ -115,74 +135,99 @@ void paintface_flush_flags(bContext *C, Object *ob, short flag)
void paintface_hide(bContext *C, Object *ob, const bool unselected)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
if (me == nullptr || me->totpoly == 0) {
return;
}
+ MutableSpan<MPoly> polys = me->polys_for_write();
+ bke::MutableAttributeAccessor attributes = me->attributes_for_write();
+ bke::SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_span<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE);
+
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mpoly = &me->mpoly[i];
- if ((mpoly->flag & ME_HIDE) == 0) {
+ MPoly *mpoly = &polys[i];
+ if (!hide_poly.span[i]) {
if (((mpoly->flag & ME_FACE_SEL) == 0) == unselected) {
- mpoly->flag |= ME_HIDE;
+ hide_poly.span[i] = true;
}
}
- if (mpoly->flag & ME_HIDE) {
+ if (hide_poly.span[i]) {
mpoly->flag &= ~ME_FACE_SEL;
}
}
+ hide_poly.finish();
+
BKE_mesh_flush_hidden_from_polys(me);
- paintface_flush_flags(C, ob, SELECT | ME_HIDE);
+ paintface_flush_flags(C, ob, true, true);
}
void paintface_reveal(bContext *C, Object *ob, const bool select)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
if (me == nullptr || me->totpoly == 0) {
return;
}
- for (int i = 0; i < me->totpoly; i++) {
- MPoly *mpoly = &me->mpoly[i];
- if (mpoly->flag & ME_HIDE) {
- SET_FLAG_FROM_TEST(mpoly->flag, select, ME_FACE_SEL);
- mpoly->flag &= ~ME_HIDE;
+ MutableSpan<MPoly> polys = me->polys_for_write();
+ bke::MutableAttributeAccessor attributes = me->attributes_for_write();
+
+ if (select) {
+ const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+ for (int i = 0; i < me->totpoly; i++) {
+ MPoly *mpoly = &polys[i];
+ if (hide_poly[i]) {
+ mpoly->flag |= ME_FACE_SEL;
+ }
}
}
+ attributes.remove(".hide_poly");
+
BKE_mesh_flush_hidden_from_polys(me);
- paintface_flush_flags(C, ob, SELECT | ME_HIDE);
+ paintface_flush_flags(C, ob, true, true);
}
/* Set object-mode face selection seams based on edge data, uses hash table to find seam edges. */
static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select)
{
+ using namespace blender;
bool do_it = true;
bool mark = false;
BLI_bitmap *edge_tag = BLI_BITMAP_NEW(me->totedge, __func__);
BLI_bitmap *poly_tag = BLI_BITMAP_NEW(me->totpoly, __func__);
+ const Span<MEdge> edges = me->edges();
+ MutableSpan<MPoly> polys = me->polys_for_write();
+ const Span<MLoop> loops = me->loops();
+ bke::AttributeAccessor attributes = me->attributes();
+ const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+
if (index != (uint)-1) {
/* only put face under cursor in array */
- MPoly *mp = &me->mpoly[index];
- BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
+ const MPoly *mp = &polys[index];
+ BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, &loops[mp->loopstart]);
BLI_BITMAP_ENABLE(poly_tag, index);
}
else {
/* fill array by selection */
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mp = &me->mpoly[i];
- if (mp->flag & ME_HIDE) {
+ MPoly *mp = &polys[i];
+ if (hide_poly[i]) {
/* pass */
}
else if (mp->flag & ME_FACE_SEL) {
- BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
+ BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, &loops[mp->loopstart]);
BLI_BITMAP_ENABLE(poly_tag, i);
}
}
@@ -193,17 +238,17 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
/* expand selection */
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mp = &me->mpoly[i];
- if (mp->flag & ME_HIDE) {
+ MPoly *mp = &polys[i];
+ if (hide_poly[i]) {
continue;
}
if (!BLI_BITMAP_TEST(poly_tag, i)) {
mark = false;
- MLoop *ml = me->mloop + mp->loopstart;
+ const MLoop *ml = &loops[mp->loopstart];
for (int b = 0; b < mp->totloop; b++, ml++) {
- if ((me->medge[ml->e].flag & ME_SEAM) == 0) {
+ if ((edges[ml->e].flag & ME_SEAM) == 0) {
if (BLI_BITMAP_TEST(edge_tag, ml->e)) {
mark = true;
break;
@@ -213,7 +258,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
if (mark) {
BLI_BITMAP_ENABLE(poly_tag, i);
- BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
+ BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, &loops[mp->loopstart]);
do_it = true;
}
}
@@ -223,7 +268,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bo
MEM_freeN(edge_tag);
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mp = &me->mpoly[i];
+ MPoly *mp = &polys[index];
if (BLI_BITMAP_TEST(poly_tag, i)) {
SET_FLAG_FROM_TEST(mp->flag, select, ME_FACE_SEL);
}
@@ -249,22 +294,28 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b
select_linked_tfaces_with_seams(me, index, select);
- paintface_flush_flags(C, ob, SELECT);
+ paintface_flush_flags(C, ob, true, false);
}
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
if (me == nullptr) {
return false;
}
+ MutableSpan<MPoly> polys = me->polys_for_write();
+ bke::AttributeAccessor attributes = me->attributes();
+ const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mpoly = &me->mpoly[i];
- if ((mpoly->flag & ME_HIDE) == 0 && mpoly->flag & ME_FACE_SEL) {
+ MPoly *mpoly = &polys[i];
+ if (!hide_poly[i] && mpoly->flag & ME_FACE_SEL) {
action = SEL_DESELECT;
break;
}
@@ -274,8 +325,8 @@ bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool fl
bool changed = false;
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mpoly = &me->mpoly[i];
- if ((mpoly->flag & ME_HIDE) == 0) {
+ MPoly *mpoly = &polys[i];
+ if (!hide_poly[i]) {
switch (action) {
case SEL_SELECT:
if ((mpoly->flag & ME_FACE_SEL) == 0) {
@@ -299,7 +350,7 @@ bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool fl
if (changed) {
if (flush_flags) {
- paintface_flush_flags(C, ob, SELECT);
+ paintface_flush_flags(C, ob, true, false);
}
}
return changed;
@@ -307,26 +358,33 @@ bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool fl
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
{
+ using namespace blender;
bool ok = false;
float vec[3], bmat[3][3];
const Mesh *me = BKE_mesh_from_object(ob);
- if (!me || !me->mloopuv) {
+ if (!me || !CustomData_has_layer(&me->ldata, CD_MLOOPUV)) {
return ok;
}
- const MVert *mvert = me->mvert;
copy_m3_m4(bmat, ob->obmat);
+ const Span<MVert> verts = me->verts();
+ const Span<MPoly> polys = me->polys();
+ const Span<MLoop> loops = me->loops();
+ bke::AttributeAccessor attributes = me->attributes();
+ const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+
for (int i = 0; i < me->totpoly; i++) {
- MPoly *mp = &me->mpoly[i];
- if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL)) {
+ const MPoly *mp = &polys[i];
+ if (hide_poly[i] || !(mp->flag & ME_FACE_SEL)) {
continue;
}
- const MLoop *ml = me->mloop + mp->loopstart;
+ const MLoop *ml = &loops[mp->loopstart];
for (int b = 0; b < mp->totloop; b++, ml++) {
- mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
+ mul_v3_m3v3(vec, bmat, verts[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
minmax_v3v3_v3(r_min, r_max, vec);
}
@@ -342,6 +400,7 @@ bool paintface_mouse_select(bContext *C,
const SelectPick_Params *params,
Object *ob)
{
+ using namespace blender;
MPoly *mpoly_sel = nullptr;
uint index;
bool changed = false;
@@ -350,10 +409,15 @@ bool paintface_mouse_select(bContext *C,
/* Get the face under the cursor */
Mesh *me = BKE_mesh_from_object(ob);
+ MutableSpan<MPoly> polys = me->polys_for_write();
+ bke::AttributeAccessor attributes = me->attributes();
+ const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+
if (ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
if (index < me->totpoly) {
- mpoly_sel = me->mpoly + index;
- if ((mpoly_sel->flag & ME_HIDE) == 0) {
+ mpoly_sel = polys.data() + index;
+ if (!hide_poly[index]) {
found = true;
}
}
@@ -402,7 +466,7 @@ bool paintface_mouse_select(bContext *C,
/* image window redraw */
- paintface_flush_flags(C, ob, SELECT);
+ paintface_flush_flags(C, ob, true, false);
ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
changed = true;
}
@@ -411,12 +475,10 @@ bool paintface_mouse_select(bContext *C,
void paintvert_flush_flags(Object *ob)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
- MVert *mvert_eval, *mv;
const int *index_array = nullptr;
- int totvert;
- int i;
if (me == nullptr) {
return;
@@ -432,23 +494,21 @@ void paintvert_flush_flags(Object *ob)
index_array = (const int *)CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
- mvert_eval = me_eval->mvert;
- totvert = me_eval->totvert;
-
- mv = mvert_eval;
+ const Span<MVert> verts = me->verts_for_write();
+ MutableSpan<MVert> verts_eval = me_eval->verts_for_write();
if (index_array) {
int orig_index;
- for (i = 0; i < totvert; i++, mv++) {
+ for (const int i : verts_eval.index_range()) {
orig_index = index_array[i];
if (orig_index != ORIGINDEX_NONE) {
- mv->flag = me->mvert[index_array[i]].flag;
+ verts_eval[i].flag = verts[index_array[i]].flag;
}
}
}
else {
- for (i = 0; i < totvert; i++, mv++) {
- mv->flag = me->mvert[i].flag;
+ for (const int i : verts_eval.index_range()) {
+ verts_eval[i].flag = verts[i].flag;
}
}
@@ -463,17 +523,23 @@ void paintvert_tag_select_update(bContext *C, Object *ob)
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
if (me == nullptr) {
return false;
}
+ MutableSpan<MVert> verts = me->verts_for_write();
+ bke::AttributeAccessor attributes = me->attributes();
+ const VArray<bool> hide_vert = attributes.lookup_or_default<bool>(
+ ".hide_vert", ATTR_DOMAIN_POINT, false);
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
for (int i = 0; i < me->totvert; i++) {
- MVert *mvert = &me->mvert[i];
- if ((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) {
+ MVert *mvert = &verts[i];
+ if (!hide_vert[i] && mvert->flag & SELECT) {
action = SEL_DESELECT;
break;
}
@@ -482,8 +548,8 @@ bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
bool changed = false;
for (int i = 0; i < me->totvert; i++) {
- MVert *mvert = &me->mvert[i];
- if ((mvert->flag & ME_HIDE) == 0) {
+ MVert *mvert = &verts[i];
+ if (!hide_vert[i]) {
switch (action) {
case SEL_SELECT:
if ((mvert->flag & SELECT) == 0) {
@@ -526,9 +592,13 @@ bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
{
+ using namespace blender;
Mesh *me = BKE_mesh_from_object(ob);
-
- if (me == nullptr || me->dvert == nullptr) {
+ if (me == nullptr) {
+ return;
+ }
+ const Span<MDeformVert> dverts = me->deform_verts();
+ if (dverts.is_empty()) {
return;
}
@@ -536,10 +606,15 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
+ MutableSpan<MVert> verts = me->verts_for_write();
+ bke::AttributeAccessor attributes = me->attributes();
+ const VArray<bool> hide_vert = attributes.lookup_or_default<bool>(
+ ".hide_vert", ATTR_DOMAIN_POINT, false);
+
for (int i = 0; i < me->totvert; i++) {
- MVert *mv = &me->mvert[i];
- MDeformVert *dv = &me->dvert[i];
- if ((mv->flag & ME_HIDE) == 0) {
+ MVert *mv = &verts[i];
+ const MDeformVert *dv = &dverts[i];
+ if (!hide_vert[i]) {
if (dv->dw == nullptr) {
/* if null weight then not grouped */
mv->flag |= SELECT;
@@ -551,3 +626,65 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
paintvert_flush_flags(ob);
}
}
+
+void paintvert_hide(bContext *C, Object *ob, const bool unselected)
+{
+ using namespace blender;
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr || me->totvert == 0) {
+ return;
+ }
+
+ MutableSpan<MVert> verts = me->verts_for_write();
+ bke::MutableAttributeAccessor attributes = me->attributes_for_write();
+ bke::SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_span<bool>(
+ ".hide_vert", ATTR_DOMAIN_POINT);
+
+ for (const int i : verts.index_range()) {
+ MVert &vert = verts[i];
+ if (!hide_vert.span[i]) {
+ if (((vert.flag & SELECT) == 0) == unselected) {
+ hide_vert.span[i] = true;
+ }
+ }
+
+ if (hide_vert.span[i]) {
+ vert.flag &= ~SELECT;
+ }
+ }
+ hide_vert.finish();
+
+ BKE_mesh_flush_hidden_from_verts(me);
+
+ paintvert_flush_flags(ob);
+ paintvert_tag_select_update(C, ob);
+}
+
+void paintvert_reveal(bContext *C, Object *ob, const bool select)
+{
+ using namespace blender;
+ Mesh *me = BKE_mesh_from_object(ob);
+ if (me == nullptr || me->totvert == 0) {
+ return;
+ }
+
+ MutableSpan<MVert> verts = me->verts_for_write();
+ bke::MutableAttributeAccessor attributes = me->attributes_for_write();
+ const VArray<bool> hide_vert = attributes.lookup_or_default<bool>(
+ ".hide_vert", ATTR_DOMAIN_POINT, false);
+
+ for (const int i : verts.index_range()) {
+ MVert &vert = verts[i];
+ if (hide_vert[i]) {
+ SET_FLAG_FROM_TEST(vert.flag, select, SELECT);
+ }
+ }
+
+ /* Remove the hide attribute to reveal all vertices. */
+ attributes.remove(".hide_vert");
+
+ BKE_mesh_flush_hidden_from_verts(me);
+
+ paintvert_flush_flags(ob);
+ paintvert_tag_select_update(C, ob);
+}
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 8d63b1ea020..330008d92d1 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -702,7 +702,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
- (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
+ (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST));
/* First calculate the center of transformation. */
zero_v3(center);
diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c
index cc493cab0f9..5addd67ab58 100644
--- a/source/blender/editors/mesh/editmesh_extrude_screw.c
+++ b/source/blender/editors/mesh/editmesh_extrude_screw.c
@@ -41,7 +41,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
int valence;
uint objects_empty_len = 0;
uint failed_axis_len = 0;
- uint failed_vertices_len = 0;
+ uint failed_verts_len = 0;
turns = RNA_int_get(op->ptr, "turns");
steps = RNA_int_get(op->ptr, "steps");
@@ -97,7 +97,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
}
if (v1 == NULL || v2 == NULL) {
- failed_vertices_len++;
+ failed_verts_len++;
continue;
}
@@ -151,7 +151,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
if (failed_axis_len == objects_len - objects_empty_len) {
BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
}
- else if (failed_vertices_len == objects_len - objects_empty_len) {
+ else if (failed_verts_len == objects_len - objects_empty_len) {
BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too");
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 5680865ae67..6062048e993 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -489,7 +489,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd)
wmOrtho2_region_pixelspace(kcd->region);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
char numstr[256];
float numstr_size[2];
@@ -629,7 +629,7 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd,
uint pos_2d = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Angle as string. */
char numstr[256];
@@ -4300,7 +4300,7 @@ static void knifetool_finish_single_pre(KnifeTool_OpData *kcd, Object *ob)
}
/**
- * A post version is needed to to delay recalculating tessellation after making cuts.
+ * A post version is needed to delay recalculating tessellation after making cuts.
* Without this, knife-project can't use the BVH tree to select geometry after a cut, see: T98349.
*/
static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object *ob)
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 7634ce6af9e..6a080e78086 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -486,7 +486,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
Mesh *new_mesh = (Mesh *)BKE_id_copy(bmain, &mesh->id);
if (ob->mode == OB_MODE_SCULPT) {
- ED_sculpt_undo_geometry_begin(ob, "mask slice");
+ ED_sculpt_undo_geometry_begin(ob, op);
}
BMesh *bm;
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index f2e7150e791..6f2f43b844e 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -679,7 +679,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
em_setup_viewcontext(C, &vc);
copy_v2_v2_int(vc.mval, event->mval);
- Base *basact = BASACT(vc.view_layer);
+ Base *basact = vc.view_layer->basact;
BMEditMesh *em = vc.em;
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index c931cb4948b..c71ad02537e 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -12,6 +12,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -1416,6 +1418,7 @@ void MESH_OT_select_similar(wmOperatorType *ot)
/* properties */
prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MESH);
RNA_def_enum_funcs(prop, select_similar_type_itemf);
RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 1febc429edc..7de5ad9f151 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -936,7 +936,7 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totvertsel == 0)) {
+ if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
continue;
}
@@ -8692,7 +8692,7 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *
* Free the data here, then use #point_normals_ensure to add it back on demand. */
if (ret == OPERATOR_PASS_THROUGH) {
/* Don't free on mouse-move, causes creation/freeing of the loop data in an inefficient way. */
- if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (!ISMOUSE_MOTION(event->type)) {
point_normals_free(op);
}
}
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index d75c92f963f..7bb1dc3723f 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -361,8 +361,6 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool
if (create) {
um_arraystore.users += 1;
}
-
- BKE_mesh_update_customdata_pointers(me, false);
}
/**
@@ -465,9 +463,6 @@ static void um_arraystore_expand(UndoMesh *um)
BLI_assert(me->totselect == (state_len / stride));
UNUSED_VARS_NDEBUG(stride);
}
-
- /* not essential, but prevents accidental dangling pointer access */
- BKE_mesh_update_customdata_pointers(me, false);
}
static void um_arraystore_free(UndoMesh *um)
@@ -594,6 +589,10 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key, Undo
/* Uncomment for troubleshooting. */
// BM_mesh_validate(em->bm);
+ /* Copy the ID name characters to the mesh so code that depends on accessing the ID type can work
+ * on it. Necessary to use the attribute API. */
+ strcpy(um->me.id.name, "MEundomesh_from_editmesh");
+
BM_mesh_bm_to_me(
NULL,
em->bm,
@@ -732,7 +731,7 @@ static void undomesh_free_data(UndoMesh *um)
static Object *editmesh_object_from_context(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit && obedit->type == OB_MESH) {
Mesh *me = obedit->data;
if (me->edit_mesh != NULL) {
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 04030583f5c..a6a6b095c31 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -593,45 +593,304 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
return vmap->vert[v];
}
+struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *element_map)
+{
+ if (element_map->head_table) {
+ return element_map->head_table;
+ }
+
+ /* For each UvElement, locate the "separate" UvElement that precedes it in the linked list. */
+ element_map->head_table = MEM_mallocN(sizeof(*element_map->head_table) * element_map->total_uvs,
+ "uv_element_map_head_table");
+ UvElement **head_table = element_map->head_table;
+ for (int i = 0; i < element_map->total_uvs; i++) {
+ UvElement *head = element_map->storage + i;
+ if (head->separate) {
+ UvElement *element = head;
+ while (element) {
+ head_table[element - element_map->storage] = head;
+ element = element->next;
+ if (element && element->separate) {
+ break;
+ }
+ }
+ }
+ }
+ return element_map->head_table;
+}
+
+#define INVALID_ISLAND ((unsigned int)-1)
+
+static void bm_uv_assign_island(UvElementMap *element_map,
+ UvElement *element,
+ int nisland,
+ uint *map,
+ UvElement *islandbuf,
+ int islandbufsize)
+{
+ element->island = nisland;
+ map[element - element_map->storage] = islandbufsize;
+
+ /* Copy *element to islandbuf[islandbufsize]. */
+ islandbuf[islandbufsize].l = element->l;
+ islandbuf[islandbufsize].separate = element->separate;
+ islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index;
+ islandbuf[islandbufsize].island = element->island;
+ islandbuf[islandbufsize].flag = element->flag;
+}
+
+static int bm_uv_edge_select_build_islands(UvElementMap *element_map,
+ const Scene *scene,
+ UvElement *islandbuf,
+ uint *map,
+ bool uv_selected,
+ const int cd_loop_uv_offset)
+{
+ BM_uv_element_map_ensure_head_table(element_map);
+
+ int total_uvs = element_map->total_uvs;
+
+ /* Depth first search the graph, building islands as we go. */
+ int nislands = 0;
+ int islandbufsize = 0;
+ int stack_upper_bound = total_uvs;
+ UvElement **stack_uv = MEM_mallocN(sizeof(*stack_uv) * stack_upper_bound,
+ "uv_island_element_stack");
+ int stacksize_uv = 0;
+ for (int i = 0; i < total_uvs; i++) {
+ UvElement *element = element_map->storage + i;
+ if (element->island != INVALID_ISLAND) {
+ /* Unique UV (element and all it's children) are already part of an island. */
+ continue;
+ }
+
+ /* Create a new island, i.e. nislands++. */
+
+ BLI_assert(element->separate); /* Ensure we're the head of this unique UV. */
+
+ /* Seed the graph search. */
+ stack_uv[stacksize_uv++] = element;
+ while (element) {
+ bm_uv_assign_island(element_map, element, nislands, map, islandbuf, islandbufsize++);
+ element = element->next;
+ if (element && element->separate) {
+ break;
+ }
+ }
+
+ /* Traverse the graph. */
+ while (stacksize_uv) {
+ BLI_assert(stacksize_uv < stack_upper_bound);
+ element = stack_uv[--stacksize_uv];
+ while (element) {
+
+ /* Scan forwards around the BMFace that contains element->l. */
+ if (!uv_selected || uvedit_edge_select_test(scene, element->l, cd_loop_uv_offset)) {
+ UvElement *next = BM_uv_element_get(element_map, element->l->next->f, element->l->next);
+ if (next->island == INVALID_ISLAND) {
+ UvElement *tail = element_map->head_table[next - element_map->storage];
+ stack_uv[stacksize_uv++] = tail;
+ while (tail) {
+ bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
+ tail = tail->next;
+ if (tail && tail->separate) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Scan backwards around the BMFace that contains element->l. */
+ if (!uv_selected || uvedit_edge_select_test(scene, element->l->prev, cd_loop_uv_offset)) {
+ UvElement *prev = BM_uv_element_get(element_map, element->l->prev->f, element->l->prev);
+ if (prev->island == INVALID_ISLAND) {
+ UvElement *tail = element_map->head_table[prev - element_map->storage];
+ stack_uv[stacksize_uv++] = tail;
+ while (tail) {
+ bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
+ tail = tail->next;
+ if (tail && tail->separate) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* The same for all the UvElements in this unique UV. */
+ element = element->next;
+ if (element && element->separate) {
+ break;
+ }
+ }
+ }
+ nislands++;
+ }
+ BLI_assert(islandbufsize == total_uvs);
+
+ MEM_SAFE_FREE(stack_uv);
+ MEM_SAFE_FREE(element_map->head_table);
+
+ return nislands;
+}
+
+static void bm_uv_build_islands(UvElementMap *element_map,
+ BMesh *bm,
+ const Scene *scene,
+ bool uv_selected)
+{
+ int totuv = element_map->total_uvs;
+ int nislands = 0;
+ int islandbufsize = 0;
+
+ /* map holds the map from current vmap->buf to the new, sorted map */
+ uint *map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
+ BMFace **stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
+ UvElement *islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
+ /* Island number for BMFaces. */
+ int *island_number = MEM_callocN(sizeof(*island_number) * bm->totface, "uv_island_number_face");
+ copy_vn_i(island_number, bm->totface, INVALID_ISLAND);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ const bool use_uv_edge_connectivity = scene->toolsettings->uv_flag & UV_SYNC_SELECTION ?
+ scene->toolsettings->selectmode & SCE_SELECT_EDGE :
+ scene->toolsettings->uv_selectmode & UV_SELECT_EDGE;
+ if (use_uv_edge_connectivity) {
+ nislands = bm_uv_edge_select_build_islands(
+ element_map, scene, islandbuf, map, uv_selected, cd_loop_uv_offset);
+ islandbufsize = totuv;
+ }
+
+ for (int i = 0; i < totuv; i++) {
+ if (element_map->storage[i].island == INVALID_ISLAND) {
+ int stacksize = 0;
+ element_map->storage[i].island = nislands;
+ stack[0] = element_map->storage[i].l->f;
+ island_number[BM_elem_index_get(stack[0])] = nislands;
+ stacksize = 1;
+
+ while (stacksize > 0) {
+ BMFace *efa = stack[--stacksize];
+
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ UvElement *initelement = element_map->vertex[BM_elem_index_get(l->v)];
+
+ for (UvElement *element = initelement; element; element = element->next) {
+ if (element->separate) {
+ initelement = element;
+ }
+
+ if (element->l->f == efa) {
+ /* found the uv corresponding to our face and vertex.
+ * Now fill it to the buffer */
+ bm_uv_assign_island(element_map, element, nislands, map, islandbuf, islandbufsize++);
+
+ for (element = initelement; element; element = element->next) {
+ if (element->separate && element != initelement) {
+ break;
+ }
+
+ if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
+ stack[stacksize++] = element->l->f;
+ island_number[BM_elem_index_get(element->l->f)] = nislands;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ nislands++;
+ }
+ }
+
+ MEM_SAFE_FREE(island_number);
+
+ /* remap */
+ for (int i = 0; i < bm->totvert; i++) {
+ /* important since we may do selection only. Some of these may be NULL */
+ if (element_map->vertex[i]) {
+ element_map->vertex[i] = &islandbuf[map[element_map->vertex[i] - element_map->storage]];
+ }
+ }
+
+ element_map->island_indices = MEM_callocN(sizeof(*element_map->island_indices) * nislands,
+ __func__);
+ element_map->island_total_uvs = MEM_callocN(sizeof(*element_map->island_total_uvs) * nislands,
+ __func__);
+ element_map->island_total_unique_uvs = MEM_callocN(
+ sizeof(*element_map->island_total_unique_uvs) * nislands, __func__);
+ int j = 0;
+ for (int i = 0; i < totuv; i++) {
+ UvElement *next = element_map->storage[i].next;
+ islandbuf[map[i]].next = next ? &islandbuf[map[next - element_map->storage]] : NULL;
+
+ if (islandbuf[i].island != j) {
+ j++;
+ element_map->island_indices[j] = i;
+ }
+ BLI_assert(islandbuf[i].island == j);
+ element_map->island_total_uvs[j]++;
+ if (islandbuf[i].separate) {
+ element_map->island_total_unique_uvs[j]++;
+ }
+ }
+
+ MEM_SAFE_FREE(element_map->storage);
+ element_map->storage = islandbuf;
+ islandbuf = NULL;
+ element_map->total_islands = nislands;
+ MEM_SAFE_FREE(stack);
+ MEM_SAFE_FREE(map);
+}
+
UvElementMap *BM_uv_element_map_create(BMesh *bm,
const Scene *scene,
- const bool face_selected,
const bool uv_selected,
const bool use_winding,
const bool do_islands)
{
+ /* In uv sync selection, all UVs are visible. */
+ const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
+
BMVert *ev;
BMFace *efa;
- BMLoop *l;
BMIter iter, liter;
- /* vars from original func */
- UvElementMap *element_map;
- UvElement *buf;
- bool *winding = NULL;
BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
-
MLoopUV *luv;
- int totverts, totfaces, i, totuv, j;
-
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset < 0) {
+ return NULL;
+ }
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
- totfaces = bm->totface;
- totverts = bm->totvert;
- totuv = 0;
-
- /* generate UvElement array */
+ /* Count total uvs. */
+ int totuv = 0;
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- if (!uv_selected) {
- totuv += efa->len;
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- totuv++;
- }
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
+ if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
+ }
+
+ if (!uv_selected) {
+ totuv += efa->len;
+ }
+ else {
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ totuv++;
}
}
}
@@ -641,93 +900,108 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
return NULL;
}
- element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
- element_map->totalUVs = totuv;
- element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts,
- "UvElementVerts");
- buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv,
- "UvElement");
+ UvElementMap *element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
+ element_map->total_uvs = totuv;
+ element_map->vertex = (UvElement **)MEM_callocN(sizeof(*element_map->vertex) * bm->totvert,
+ "UvElementVerts");
+ element_map->storage = (UvElement *)MEM_callocN(sizeof(*element_map->storage) * totuv,
+ "UvElement");
- if (use_winding) {
- winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
- }
+ bool *winding = use_winding ? MEM_callocN(sizeof(*winding) * bm->totface, "winding") : NULL;
+ UvElement *buf = element_map->storage;
+ int j;
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
- if (use_winding) {
- winding[j] = false;
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ continue;
}
- if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- float(*tf_uv)[2] = NULL;
-
- if (use_winding) {
- tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
- }
+ if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
+ }
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- continue;
- }
+ float(*tf_uv)[2] = NULL;
- buf->l = l;
- buf->separate = 0;
- buf->island = INVALID_ISLAND;
- buf->loop_of_poly_index = i;
+ if (use_winding) {
+ tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
+ }
- buf->next = element_map->vert[BM_elem_index_get(l->v)];
- element_map->vert[BM_elem_index_get(l->v)] = buf;
+ int i;
+ BMLoop *l;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
- if (use_winding) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(tf_uv[i], luv->uv);
- }
+ buf->l = l;
+ buf->island = INVALID_ISLAND;
+ buf->loop_of_poly_index = i;
- buf++;
- }
+ /* Insert to head of linked list associated with BMVert. */
+ buf->next = element_map->vertex[BM_elem_index_get(l->v)];
+ element_map->vertex[BM_elem_index_get(l->v)] = buf;
if (use_winding) {
- winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
}
+
+ buf++;
}
- }
- /* sort individual uvs for each vert */
- BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) {
- UvElement *newvlist = NULL, *vlist = element_map->vert[i];
- UvElement *iterv, *v, *lastv, *next;
- const float *uv, *uv2;
- bool uv_vert_sel, uv2_vert_sel;
+ if (winding) {
+ winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
+ }
+ }
+ BLI_buffer_free(&tf_uv_buf);
+ /* For each BMVert, sort associated linked list into unique uvs. */
+ int ev_index;
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, ev_index) {
+ UvElement *newvlist = NULL;
+ UvElement *vlist = element_map->vertex[ev_index];
while (vlist) {
- v = vlist;
+
+ /* Detach head from unsorted list. */
+ UvElement *v = vlist;
vlist = vlist->next;
v->next = newvlist;
newvlist = v;
- l = v->l;
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- uv = luv->uv;
- uv_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ luv = BM_ELEM_CD_GET_VOID_P(v->l, cd_loop_uv_offset);
+ const float *uv = luv->uv;
+ bool uv_vert_sel = uvedit_uv_select_test(scene, v->l, cd_loop_uv_offset);
- lastv = NULL;
- iterv = vlist;
+ UvElement *lastv = NULL;
+ UvElement *iterv = vlist;
+ /* Scan through unsorted list, finding UvElements which are connected to `v`. */
while (iterv) {
- next = iterv->next;
+ UvElement *next = iterv->next;
+ luv = BM_ELEM_CD_GET_VOID_P(iterv->l, cd_loop_uv_offset);
- l = iterv->l;
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- uv2 = luv->uv;
- uv2_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ bool connected = true; /* Assume connected unless we can prove otherwise. */
+
+ if (connected) {
+ /* Are the two UVs close together? */
+ const float *uv2 = luv->uv;
+ connected = compare_v2v2(uv2, uv, STD_UV_CONNECT_LIMIT);
+ }
- /* Check if the uv loops share the same selection state (if not, they are not connected as
- * they have been ripped or other edit commands have separated them). */
- const bool connected = (uv_vert_sel == uv2_vert_sel) &&
- compare_v2v2(uv2, uv, STD_UV_CONNECT_LIMIT);
+ if (connected) {
+ /* Check if the uv loops share the same selection state (if not, they are not connected
+ * as they have been ripped or other edit commands have separated them). */
+ const bool uv2_vert_sel = uvedit_uv_select_test(scene, iterv->l, cd_loop_uv_offset);
+ connected = (uv_vert_sel == uv2_vert_sel);
+ }
+
+ if (connected && use_winding) {
+ connected = winding[BM_elem_index_get(iterv->l->f)] ==
+ winding[BM_elem_index_get(v->l->f)];
+ }
- if (connected && (!use_winding || winding[BM_elem_index_get(iterv->l->f)] ==
- winding[BM_elem_index_get(v->l->f)])) {
+ if (connected) {
if (lastv) {
lastv->next = next;
}
@@ -744,126 +1018,30 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
iterv = next;
}
- newvlist->separate = 1;
+ element_map->total_unique_uvs++;
+ newvlist->separate = true;
}
- element_map->vert[i] = newvlist;
+ /* Write back sorted list. */
+ element_map->vertex[ev_index] = newvlist;
}
- if (use_winding) {
- MEM_freeN(winding);
- }
+ MEM_SAFE_FREE(winding);
+ /* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
+ * Now we should sort uv's in islands. */
if (do_islands) {
- uint *map;
- BMFace **stack;
- int stacksize = 0;
- UvElement *islandbuf;
- /* island number for faces */
- int *island_number = NULL;
-
- int nislands = 0, islandbufsize = 0;
-
- /* map holds the map from current vmap->buf to the new, sorted map */
- map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
- stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
- islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
- island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
- copy_vn_i(island_number, totfaces, INVALID_ISLAND);
-
- /* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
- * Now we should sort uv's in islands. */
- for (i = 0; i < totuv; i++) {
- if (element_map->buf[i].island == INVALID_ISLAND) {
- element_map->buf[i].island = nislands;
- stack[0] = element_map->buf[i].l->f;
- island_number[BM_elem_index_get(stack[0])] = nislands;
- stacksize = 1;
-
- while (stacksize > 0) {
- efa = stack[--stacksize];
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- continue;
- }
-
- UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)];
-
- for (element = initelement; element; element = element->next) {
- if (element->separate) {
- initelement = element;
- }
-
- if (element->l->f == efa) {
- /* found the uv corresponding to our face and vertex.
- * Now fill it to the buffer */
- element->island = nislands;
- map[element - element_map->buf] = islandbufsize;
- islandbuf[islandbufsize].l = element->l;
- islandbuf[islandbufsize].separate = element->separate;
- islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index;
- islandbuf[islandbufsize].island = nislands;
- islandbufsize++;
-
- for (element = initelement; element; element = element->next) {
- if (element->separate && element != initelement) {
- break;
- }
-
- if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
- stack[stacksize++] = element->l->f;
- island_number[BM_elem_index_get(element->l->f)] = nislands;
- }
- }
- break;
- }
- }
- }
- }
-
- nislands++;
- }
- }
-
- MEM_freeN(island_number);
-
- /* remap */
- for (i = 0; i < bm->totvert; i++) {
- /* important since we may do selection only. Some of these may be NULL */
- if (element_map->vert[i]) {
- element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]];
- }
- }
-
- element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands,
- "UvElementMap_island_indices");
- j = 0;
- for (i = 0; i < totuv; i++) {
- UvElement *element = element_map->buf[i].next;
- if (element == NULL) {
- islandbuf[map[i]].next = NULL;
- }
- else {
- islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]];
- }
+ bm_uv_build_islands(element_map, bm, scene, uv_selected);
+ }
- if (islandbuf[i].island != j) {
- j++;
- element_map->islandIndices[j] = i;
- }
+ /* TODO: Confirm element_map->total_unique_uvs doesn't require recalculating. */
+ element_map->total_unique_uvs = 0;
+ for (int i = 0; i < element_map->total_uvs; i++) {
+ if (element_map->storage[i].separate) {
+ element_map->total_unique_uvs++;
}
-
- MEM_freeN(element_map->buf);
-
- element_map->buf = islandbuf;
- element_map->totalIslands = nislands;
- MEM_freeN(stack);
- MEM_freeN(map);
}
- BLI_buffer_free(&tf_uv_buf);
-
return element_map;
}
@@ -883,30 +1061,38 @@ void BM_uv_vert_map_free(UvVertMap *vmap)
void BM_uv_element_map_free(UvElementMap *element_map)
{
if (element_map) {
- if (element_map->vert) {
- MEM_freeN(element_map->vert);
- }
- if (element_map->buf) {
- MEM_freeN(element_map->buf);
- }
- if (element_map->islandIndices) {
- MEM_freeN(element_map->islandIndices);
- }
- MEM_freeN(element_map);
+ MEM_SAFE_FREE(element_map->storage);
+ MEM_SAFE_FREE(element_map->vertex);
+ MEM_SAFE_FREE(element_map->head_table);
+ MEM_SAFE_FREE(element_map->island_indices);
+ MEM_SAFE_FREE(element_map->island_total_uvs);
+ MEM_SAFE_FREE(element_map->island_total_unique_uvs);
+ MEM_SAFE_FREE(element_map);
}
}
-UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
+UvElement *BM_uv_element_get(const UvElementMap *element_map, const BMFace *efa, const BMLoop *l)
{
- for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; element; element = element->next) {
+ UvElement *element = element_map->vertex[BM_elem_index_get(l->v)];
+ while (element) {
if (element->l->f == efa) {
return element;
}
+ element = element->next;
}
return NULL;
}
+UvElement *BM_uv_element_get_head(UvElementMap *element_map, UvElement *child)
+{
+ if (!child) {
+ return NULL;
+ }
+
+ return element_map->vertex[BM_elem_index_get(child->l->v)];
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1376,7 +1562,7 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
}
if (params->is_destructive) {
- /* TODO(campbell): we may be able to remove this now! */
+ /* TODO(@campbellbarton): we may be able to remove this now! */
// BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP);
}
else {
@@ -1646,12 +1832,13 @@ void EDBM_project_snap_verts(
depsgraph,
region,
CTX_wm_view3d(C),
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
.snap_target_select = SCE_SNAP_TARGET_NOT_ACTIVE,
.edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
+ NULL,
mval,
NULL,
NULL,
diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc
index 67834bf05ce..4ee518b5662 100644
--- a/source/blender/editors/mesh/mesh_data.cc
+++ b/source/blender/editors/mesh/mesh_data.cc
@@ -18,6 +18,7 @@
#include "BLI_utildefines.h"
#include "BKE_attribute.h"
+#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@@ -44,6 +45,8 @@
#include "mesh_intern.h" /* own include */
using blender::Array;
+using blender::MutableSpan;
+using blender::Span;
static CustomData *mesh_customdata_get_type(Mesh *me, const char htype, int *r_tot)
{
@@ -128,7 +131,6 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer)
}
else {
CustomData_free_layer(data, type, tot, layer_index + n);
- BKE_mesh_update_customdata_pointers(me, true);
}
}
@@ -186,7 +188,7 @@ static void mesh_uv_reset_bmface(BMFace *f, const int cd_loop_uv_offset)
mesh_uv_reset_array(fuv.data(), f->len);
}
-static void mesh_uv_reset_mface(MPoly *mp, MLoopUV *mloopuv)
+static void mesh_uv_reset_mface(const MPoly *mp, MLoopUV *mloopuv)
{
Array<float *, BM_DEFAULT_NGON_STACK_SIZE> fuv(mp->totloop);
@@ -208,7 +210,7 @@ void ED_mesh_uv_loop_reset_ex(Mesh *me, const int layernum)
BMFace *efa;
BMIter iter;
- BLI_assert(cd_loop_uv_offset != -1);
+ BLI_assert(cd_loop_uv_offset >= 0);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
@@ -223,8 +225,9 @@ void ED_mesh_uv_loop_reset_ex(Mesh *me, const int layernum)
BLI_assert(CustomData_has_layer(&me->ldata, CD_MLOOPUV));
MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, layernum);
+ const MPoly *polys = BKE_mesh_polys(me);
for (int i = 0; i < me->totpoly; i++) {
- mesh_uv_reset_mface(&me->mpoly[i], mloopuv);
+ mesh_uv_reset_mface(&polys[i], mloopuv);
}
}
@@ -280,20 +283,23 @@ int ED_mesh_uv_add(
return -1;
}
- if (me->mloopuv && do_init) {
- CustomData_add_layer_named(
- &me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop, name);
+ if (CustomData_has_layer(&me->ldata, CD_MLOOPUV) && do_init) {
+ CustomData_add_layer_named(&me->ldata,
+ CD_MLOOPUV,
+ CD_DUPLICATE,
+ CustomData_get_layer(&me->ldata, CD_MLOOPUV),
+ me->totloop,
+ name);
is_init = true;
}
else {
- CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, name);
+ CustomData_add_layer_named(
+ &me->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, me->totloop, name);
}
if (active_set || layernum_dst == 0) {
CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum_dst);
}
-
- BKE_mesh_update_customdata_pointers(me, true);
}
/* don't overwrite our copied coords */
@@ -368,8 +374,11 @@ bool ED_mesh_uv_remove_named(Mesh *me, const char *name)
return false;
}
-int ED_mesh_color_add(
- Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
+int ED_mesh_color_add(Mesh *me,
+ const char *name,
+ const bool active_set,
+ const bool do_init,
+ ReportList *UNUSED(reports))
{
/* NOTE: keep in sync with #ED_mesh_uv_add. */
@@ -380,10 +389,6 @@ int ED_mesh_color_add(
em = me->edit_mesh;
layernum = CustomData_number_of_layers(&em->bm->ldata, CD_PROP_BYTE_COLOR);
- if (layernum >= MAX_MCOL) {
- BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
- return -1;
- }
/* CD_PROP_BYTE_COLOR */
BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_PROP_BYTE_COLOR, name);
@@ -398,25 +403,25 @@ int ED_mesh_color_add(
}
else {
layernum = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR);
- if (layernum >= MAX_MCOL) {
- BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
- return -1;
- }
- if (me->mloopcol && do_init) {
- CustomData_add_layer_named(
- &me->ldata, CD_PROP_BYTE_COLOR, CD_DUPLICATE, me->mloopcol, me->totloop, name);
+ if (CustomData_get_active_layer(&me->ldata, CD_PROP_BYTE_COLOR) != -1 && do_init) {
+ CustomData_add_layer_named(&me->ldata,
+ CD_PROP_BYTE_COLOR,
+ CD_DUPLICATE,
+ CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR),
+ me->totloop,
+ name);
}
else {
CustomData_add_layer_named(
- &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name);
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&me->ldata, CD_PROP_BYTE_COLOR, layernum);
}
- BKE_mesh_update_customdata_pointers(me, true);
+ BKE_mesh_tessface_clear(me);
}
DEG_id_tag_update(&me->id, 0);
@@ -432,11 +437,11 @@ bool ED_mesh_color_ensure(Mesh *me, const char *name)
if (!layer) {
CustomData_add_layer_named(
- &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name);
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name);
layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
BKE_id_attributes_active_color_set(&me->id, layer);
- BKE_mesh_update_customdata_pointers(me, true);
+ BKE_mesh_tessface_clear(me);
}
DEG_id_tag_update(&me->id, 0);
@@ -444,44 +449,6 @@ bool ED_mesh_color_ensure(Mesh *me, const char *name)
return (layer != nullptr);
}
-bool ED_mesh_color_remove_index(Mesh *me, const int n)
-{
- CustomData *ldata = GET_CD_DATA(me, ldata);
- CustomDataLayer *cdl;
- int index;
-
- index = CustomData_get_layer_index_n(ldata, CD_PROP_BYTE_COLOR, n);
- cdl = (index == -1) ? nullptr : &ldata->layers[index];
-
- if (!cdl) {
- return false;
- }
-
- delete_customdata_layer(me, cdl);
- DEG_id_tag_update(&me->id, 0);
- WM_main_add_notifier(NC_GEOM | ND_DATA, me);
-
- return true;
-}
-bool ED_mesh_color_remove_active(Mesh *me)
-{
- CustomData *ldata = GET_CD_DATA(me, ldata);
- const int n = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
- if (n != -1) {
- return ED_mesh_color_remove_index(me, n);
- }
- return false;
-}
-bool ED_mesh_color_remove_named(Mesh *me, const char *name)
-{
- CustomData *ldata = GET_CD_DATA(me, ldata);
- const int n = CustomData_get_named_layer(ldata, CD_PROP_BYTE_COLOR, name);
- if (n != -1) {
- return ED_mesh_color_remove_index(me, n);
- }
- return false;
-}
-
/*********************** General poll ************************/
static bool layers_poll(bContext *C)
@@ -494,25 +461,10 @@ static bool layers_poll(bContext *C)
/*********************** Sculpt Vertex colors operators ************************/
-static bool sculpt_vertex_color_remove_poll(bContext *C)
-{
- if (!layers_poll(C)) {
- return false;
- }
-
- Object *ob = ED_object_context(C);
- Mesh *me = static_cast<Mesh *>(ob->data);
- CustomData *vdata = GET_CD_DATA(me, vdata);
- const int active = CustomData_get_active_layer(vdata, CD_PROP_COLOR);
- if (active != -1) {
- return true;
- }
-
- return false;
-}
-
-int ED_mesh_sculpt_color_add(
- Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
+int ED_mesh_sculpt_color_add(Mesh *me,
+ const char *name,
+ const bool do_init,
+ ReportList *UNUSED(reports))
{
/* NOTE: keep in sync with #ED_mesh_uv_add. */
@@ -523,11 +475,6 @@ int ED_mesh_sculpt_color_add(
em = me->edit_mesh;
layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR);
- if (layernum >= MAX_MCOL) {
- BKE_reportf(
- reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
- return -1;
- }
/* CD_PROP_COLOR */
BM_data_layer_add_named(em->bm, &em->bm->vdata, CD_PROP_COLOR, name);
@@ -536,17 +483,12 @@ int ED_mesh_sculpt_color_add(
const int layernum_dst = CustomData_get_active_layer(&em->bm->vdata, CD_PROP_COLOR);
BM_data_layer_copy(em->bm, &em->bm->vdata, CD_PROP_COLOR, layernum_dst, layernum);
}
- if (active_set || layernum == 0) {
+ if (layernum == 0) {
CustomData_set_layer_active(&em->bm->vdata, CD_PROP_COLOR, layernum);
}
}
else {
layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR);
- if (layernum >= MAX_MCOL) {
- BKE_reportf(
- reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
- return -1;
- }
if (CustomData_has_layer(&me->vdata, CD_PROP_COLOR) && do_init) {
const MPropCol *color_data = (const MPropCol *)CustomData_get_layer(&me->vdata,
@@ -556,14 +498,14 @@ int ED_mesh_sculpt_color_add(
}
else {
CustomData_add_layer_named(
- &me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name);
+ &me->vdata, CD_PROP_COLOR, CD_SET_DEFAULT, nullptr, me->totvert, name);
}
- if (active_set || layernum == 0) {
+ if (layernum == 0) {
CustomData_set_layer_active(&me->vdata, CD_PROP_COLOR, layernum);
}
- BKE_mesh_update_customdata_pointers(me, true);
+ BKE_mesh_tessface_clear(me);
}
DEG_id_tag_update(&me->id, 0);
@@ -572,58 +514,6 @@ int ED_mesh_sculpt_color_add(
return layernum;
}
-bool ED_mesh_sculpt_color_ensure(Mesh *me, const char *name)
-{
- BLI_assert(me->edit_mesh == nullptr);
-
- if (me->totvert && !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) {
- CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name);
- BKE_mesh_update_customdata_pointers(me, true);
- }
-
- DEG_id_tag_update(&me->id, 0);
-
- return (me->mloopcol != nullptr);
-}
-
-bool ED_mesh_sculpt_color_remove_index(Mesh *me, const int n)
-{
- CustomData *vdata = GET_CD_DATA(me, vdata);
- CustomDataLayer *cdl;
- int index;
-
- index = CustomData_get_layer_index_n(vdata, CD_PROP_COLOR, n);
- cdl = (index == -1) ? nullptr : &vdata->layers[index];
-
- if (!cdl) {
- return false;
- }
-
- delete_customdata_layer(me, cdl);
- DEG_id_tag_update(&me->id, 0);
- WM_main_add_notifier(NC_GEOM | ND_DATA, me);
-
- return true;
-}
-bool ED_mesh_sculpt_color_remove_active(Mesh *me)
-{
- CustomData *vdata = GET_CD_DATA(me, vdata);
- const int n = CustomData_get_active_layer(vdata, CD_PROP_COLOR);
- if (n != -1) {
- return ED_mesh_sculpt_color_remove_index(me, n);
- }
- return false;
-}
-bool ED_mesh_sculpt_color_remove_named(Mesh *me, const char *name)
-{
- CustomData *vdata = GET_CD_DATA(me, vdata);
- const int n = CustomData_get_named_layer(vdata, CD_PROP_COLOR, name);
- if (n != -1) {
- return ED_mesh_sculpt_color_remove_index(me, n);
- }
- return false;
-}
-
/*********************** UV texture operators ************************/
static bool uv_texture_remove_poll(bContext *C)
@@ -709,135 +599,6 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/*********************** vertex color operators ************************/
-
-static bool vertex_color_remove_poll(bContext *C)
-{
- if (!layers_poll(C)) {
- return false;
- }
-
- Object *ob = ED_object_context(C);
- Mesh *me = static_cast<Mesh *>(ob->data);
- CustomData *ldata = GET_CD_DATA(me, ldata);
- const int active = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
- if (active != -1) {
- return true;
- }
-
- return false;
-}
-
-static int mesh_vertex_color_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- Mesh *me = static_cast<Mesh *>(ob->data);
-
- if (ED_mesh_color_add(me, nullptr, true, true, op->reports) == -1) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertex_color_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Vertex Color";
- ot->description = "Add vertex color layer";
- ot->idname = "MESH_OT_vertex_color_add";
-
- /* api callbacks */
- ot->poll = layers_poll;
- ot->exec = mesh_vertex_color_add_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int mesh_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_context(C);
- Mesh *me = static_cast<Mesh *>(ob->data);
-
- if (!ED_mesh_color_remove_active(me)) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertex_color_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Vertex Color";
- ot->description = "Remove vertex color layer";
- ot->idname = "MESH_OT_vertex_color_remove";
-
- /* api callbacks */
- ot->exec = mesh_vertex_color_remove_exec;
- ot->poll = vertex_color_remove_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/*********************** Sculpt Vertex Color Operators ************************/
-
-static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- Mesh *me = static_cast<Mesh *>(ob->data);
-
- if (ED_mesh_sculpt_color_add(me, nullptr, true, true, op->reports) == -1) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_sculpt_vertex_color_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Sculpt Vertex Color";
- ot->description = "Add vertex color layer";
- ot->idname = "MESH_OT_sculpt_vertex_color_add";
-
- /* api callbacks */
- ot->poll = layers_poll;
- ot->exec = mesh_sculpt_vertex_color_add_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int mesh_sculpt_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_context(C);
- Mesh *me = static_cast<Mesh *>(ob->data);
-
- if (!ED_mesh_sculpt_color_remove_active(me)) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_sculpt_vertex_color_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Sculpt Vertex Color";
- ot->description = "Remove vertex color layer";
- ot->idname = "MESH_OT_sculpt_vertex_color_remove";
-
- /* api callbacks */
- ot->exec = mesh_sculpt_vertex_color_remove_exec;
- ot->poll = sculpt_vertex_color_remove_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* *** CustomData clear functions, we need an operator for each *** */
static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int type)
@@ -1015,19 +776,24 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve autosmooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
- BKE_edges_sharp_from_angle_set(me->mvert,
- me->totvert,
- me->medge,
- me->totedge,
- me->mloop,
- me->totloop,
- me->mpoly,
+ const Span<MVert> verts = me->verts();
+ MutableSpan<MEdge> edges = me->edges_for_write();
+ const Span<MPoly> polys = me->polys();
+ const Span<MLoop> loops = me->loops();
+
+ BKE_edges_sharp_from_angle_set(verts.data(),
+ verts.size(),
+ edges.data(),
+ edges.size(),
+ loops.data(),
+ loops.size(),
+ polys.data(),
BKE_mesh_poly_normals_ensure(me),
- me->totpoly,
+ polys.size(),
me->smoothresh);
}
- CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, nullptr, me->totloop);
+ CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, me->totloop);
}
DEG_id_tag_update(&me->id, 0);
@@ -1112,36 +878,31 @@ static void mesh_add_verts(Mesh *mesh, int len)
int totvert = mesh->totvert + len;
CustomData vdata;
- CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert);
+ CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
if (!CustomData_has_layer(&vdata, CD_MVERT)) {
- CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert);
+ CustomData_add_layer(&vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, totvert);
}
CustomData_free(&mesh->vdata, mesh->totvert);
mesh->vdata = vdata;
- BKE_mesh_update_customdata_pointers(mesh, false);
BKE_mesh_runtime_clear_cache(mesh);
- /* scan the input list and insert the new vertices */
+ const int old_vertex_num = mesh->totvert;
+ mesh->totvert = totvert;
- /* set default flags */
- MVert *mvert = &mesh->mvert[mesh->totvert];
- for (int i = 0; i < len; i++, mvert++) {
- mvert->flag |= SELECT;
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ for (MVert &vert : verts.drop_front(old_vertex_num)) {
+ vert.flag = SELECT;
}
-
- /* set final vertex list size */
- mesh->totvert = totvert;
}
static void mesh_add_edges(Mesh *mesh, int len)
{
CustomData edata;
- MEdge *medge;
- int i, totedge;
+ int totedge;
if (len == 0) {
return;
@@ -1150,26 +911,25 @@ static void mesh_add_edges(Mesh *mesh, int len)
totedge = mesh->totedge + len;
/* Update custom-data. */
- CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge);
+ CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
if (!CustomData_has_layer(&edata, CD_MEDGE)) {
- CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
+ CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge);
}
CustomData_free(&mesh->edata, mesh->totedge);
mesh->edata = edata;
- BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */
BKE_mesh_runtime_clear_cache(mesh);
- /* set default flags */
- medge = &mesh->medge[mesh->totedge];
- for (i = 0; i < len; i++, medge++) {
- medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
- }
-
+ const int old_edges_num = mesh->totedge;
mesh->totedge = totedge;
+
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ for (MEdge &edge : edges.drop_front(old_edges_num)) {
+ edge.flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
+ }
}
static void mesh_add_loops(Mesh *mesh, int len)
@@ -1184,18 +944,17 @@ static void mesh_add_loops(Mesh *mesh, int len)
totloop = mesh->totloop + len; /* new face count */
/* update customdata */
- CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop);
+ CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
if (!CustomData_has_layer(&ldata, CD_MLOOP)) {
- CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop);
+ CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop);
}
BKE_mesh_runtime_clear_cache(mesh);
CustomData_free(&mesh->ldata, mesh->totloop);
mesh->ldata = ldata;
- BKE_mesh_update_customdata_pointers(mesh, true);
mesh->totloop = totloop;
}
@@ -1203,8 +962,7 @@ static void mesh_add_loops(Mesh *mesh, int len)
static void mesh_add_polys(Mesh *mesh, int len)
{
CustomData pdata;
- MPoly *mpoly;
- int i, totpoly;
+ int totpoly;
if (len == 0) {
return;
@@ -1213,26 +971,25 @@ static void mesh_add_polys(Mesh *mesh, int len)
totpoly = mesh->totpoly + len; /* new face count */
/* update customdata */
- CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly);
+ CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
if (!CustomData_has_layer(&pdata, CD_MPOLY)) {
- CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly);
+ CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly);
}
CustomData_free(&mesh->pdata, mesh->totpoly);
mesh->pdata = pdata;
- BKE_mesh_update_customdata_pointers(mesh, true);
BKE_mesh_runtime_clear_cache(mesh);
- /* set default flags */
- mpoly = &mesh->mpoly[mesh->totpoly];
- for (i = 0; i < len; i++, mpoly++) {
- mpoly->flag = ME_FACE_SEL;
- }
-
+ const int old_polys_num = mesh->totpoly;
mesh->totpoly = totpoly;
+
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ for (MPoly &poly : polys.drop_front(old_polys_num)) {
+ poly.flag = ME_FACE_SEL;
+ }
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 303234df48c..7c8dbffeb31 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -308,10 +308,6 @@ void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
-void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
-void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
-void MESH_OT_sculpt_vertex_color_add(struct wmOperatorType *ot);
-void MESH_OT_sculpt_vertex_color_remove(struct wmOperatorType *ot);
void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
index 82e77a88a57..ad5a5d362f1 100644
--- a/source/blender/editors/mesh/mesh_mirror.c
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -55,11 +55,9 @@ void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *me_eva
}
}
else {
- MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
- int i;
-
- for (i = 0; i < totvert; i++, mvert++) {
- BLI_kdtree_3d_insert(MirrKdStore.tree, i, mvert->co);
+ const MVert *verts = BKE_mesh_verts(me_eval ? me_eval : me);
+ for (int i = 0; i < totvert; i++) {
+ BLI_kdtree_3d_insert(MirrKdStore.tree, i, verts[i].co);
}
}
@@ -164,7 +162,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
BLI_assert(me == NULL);
}
const bool is_editmode = (em != NULL);
- MEdge *medge = NULL, *med;
+ const MEdge *medge = NULL, *med;
/* Edit-mode variables. */
BMEdge *eed;
@@ -210,8 +208,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
}
else {
totedge = me->totedge;
- medge = me->medge;
-
+ medge = BKE_mesh_edges(me);
for (a = 0, med = medge; a < totedge; a++, med++) {
const uint i1 = med->v1, i2 = med->v2;
topo_hash[i1]++;
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index be7f60b0da0..b9e78740e3c 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -134,10 +134,6 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);
- WM_operatortype_append(MESH_OT_vertex_color_add);
- WM_operatortype_append(MESH_OT_vertex_color_remove);
- WM_operatortype_append(MESH_OT_sculpt_vertex_color_add);
- WM_operatortype_append(MESH_OT_sculpt_vertex_color_remove);
WM_operatortype_append(MESH_OT_customdata_mask_clear);
WM_operatortype_append(MESH_OT_customdata_skin_add);
WM_operatortype_append(MESH_OT_customdata_skin_clear);
diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc
index 9e28e1bafdd..d6713724e15 100644
--- a/source/blender/editors/mesh/meshtools.cc
+++ b/source/blender/editors/mesh/meshtools.cc
@@ -10,6 +10,8 @@
#include "MEM_guardedalloc.h"
+#include "BLI_virtual_array.hh"
+
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -21,6 +23,7 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -52,6 +55,9 @@
#include "WM_api.h"
#include "WM_types.h"
+using blender::MutableSpan;
+using blender::Span;
+
/* * ********************** no editmode!!! *********** */
/*********************** JOIN ***************************/
@@ -100,7 +106,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag;
/* standard data */
- CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert);
+ CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
/* vertex groups */
@@ -199,7 +205,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
if (me->totedge) {
- CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge);
+ CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge);
for (a = 0; a < me->totedge; a++, medge++) {
@@ -220,7 +226,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
}
- CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop);
+ CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop);
for (a = 0; a < me->totloop; a++, mloop++) {
@@ -244,12 +250,22 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
}
- CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly);
+ CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
+ blender::bke::AttributeWriter<int> material_indices =
+ me->attributes_for_write().lookup_for_write<int>("material_index");
+ if (material_indices) {
+ blender::MutableVArraySpan<int> material_indices_span(material_indices.varray);
+ for (const int i : material_indices_span.index_range()) {
+ material_indices_span[i] = matmap ? matmap[material_indices_span[i]] : 0;
+ }
+ material_indices_span.save();
+ material_indices.finish();
+ }
+
for (a = 0; a < me->totpoly; a++, mpoly++) {
mpoly->loopstart += *loopofs;
- mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
}
/* Face maps. */
@@ -571,10 +587,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
CustomData_reset(&ldata);
CustomData_reset(&pdata);
- mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert);
- medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
- mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop);
- mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly);
+ mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, totvert);
+ medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge);
+ mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop);
+ mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly);
vertofs = 0;
edgeofs = 0;
@@ -678,9 +694,6 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
me->ldata = ldata;
me->pdata = pdata;
- /* tessface data removed above, no need to update */
- BKE_mesh_update_customdata_pointers(me, false);
-
/* Tag normals dirty because vertex positions could be changed from the original. */
BKE_mesh_normals_tag_dirty(me);
@@ -893,13 +906,13 @@ static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
{
Mesh *me = static_cast<Mesh *>(ob->data);
- MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
+ const Span<MVert> verts = me_eval ? me_eval->verts() : me->verts();
+
float vec[3];
- mvert = &mvert[index];
- vec[0] = -mvert->co[0];
- vec[1] = mvert->co[1];
- vec[2] = mvert->co[2];
+ vec[0] = -verts[index].co[0];
+ vec[1] = verts[index].co[1];
+ vec[2] = verts[index].co[2];
return ED_mesh_mirror_spatial_table_lookup(ob, nullptr, me_eval, vec);
}
@@ -1115,8 +1128,8 @@ static bool mirror_facecmp(const void *a, const void *b)
int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
Mesh *me = static_cast<Mesh *>(ob->data);
- MVert *mv, *mvert;
- MFace mirrormf, *mf, *hashmf, *mface;
+ const MVert *mv;
+ MFace mirrormf, *mf, *hashmf;
GHash *fhash;
int *mirrorverts, *mirrorfaces;
@@ -1130,12 +1143,12 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
mirrorverts = static_cast<int *>(MEM_callocN(sizeof(int) * totvert, "MirrorVerts"));
mirrorfaces = static_cast<int *>(MEM_callocN(sizeof(int[2]) * totface, "MirrorFaces"));
- mvert = me_eval ? me_eval->mvert : me->mvert;
- mface = me_eval ? me_eval->mface : me->mface;
+ const Span<MVert> verts = me_eval ? me_eval->verts() : me->verts();
+ MFace *mface = (MFace *)CustomData_get_layer(&(me_eval ? me_eval : me)->fdata, CD_MFACE);
ED_mesh_mirror_spatial_table_begin(ob, em, me_eval);
- for (a = 0, mv = mvert; a < totvert; a++, mv++) {
+ for (a = 0, mv = verts.data(); a < totvert; a++, mv++) {
mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology);
}
@@ -1262,42 +1275,28 @@ bool ED_mesh_pick_face_vert(
const float mval_f[2] = {(float)mval[0], (float)mval[1]};
float len_best = FLT_MAX;
- MPoly *me_eval_mpoly;
- MLoop *me_eval_mloop;
- MVert *me_eval_mvert;
- uint me_eval_mpoly_len;
-
- me_eval_mpoly = me_eval->mpoly;
- me_eval_mloop = me_eval->mloop;
- me_eval_mvert = me_eval->mvert;
-
- me_eval_mpoly_len = me_eval->totpoly;
+ const Span<MVert> verts = me_eval->verts();
+ const Span<MPoly> polys = me_eval->polys();
+ const Span<MLoop> loops = me_eval->loops();
const int *index_mp_to_orig = (const int *)CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
/* tag all verts using this face */
if (index_mp_to_orig) {
- uint i;
-
- for (i = 0; i < me_eval_mpoly_len; i++) {
+ for (const int i : polys.index_range()) {
if (index_mp_to_orig[i] == poly_index) {
- ed_mesh_pick_face_vert__mpoly_find(region,
- mval_f,
- &me_eval_mpoly[i],
- me_eval_mvert,
- me_eval_mloop,
- &len_best,
- &v_idx_best);
+ ed_mesh_pick_face_vert__mpoly_find(
+ region, mval_f, &polys[i], verts.data(), loops.data(), &len_best, &v_idx_best);
}
}
}
else {
- if (poly_index < me_eval_mpoly_len) {
+ if (poly_index < polys.size()) {
ed_mesh_pick_face_vert__mpoly_find(region,
mval_f,
- &me_eval_mpoly[poly_index],
- me_eval_mvert,
- me_eval_mloop,
+ &polys[poly_index],
+ verts.data(),
+ loops.data(),
&len_best,
&v_idx_best);
}
@@ -1329,6 +1328,7 @@ bool ED_mesh_pick_face_vert(
*/
struct VertPickData {
const MVert *mvert;
+ const bool *hide_vert;
const float *mval_f; /* [2] */
ARegion *region;
@@ -1343,16 +1343,16 @@ static void ed_mesh_pick_vert__mapFunc(void *userData,
const float UNUSED(no[3]))
{
VertPickData *data = static_cast<VertPickData *>(userData);
- if ((data->mvert[index].flag & ME_HIDE) == 0) {
- float sco[2];
-
- if (ED_view3d_project_float_object(data->region, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) ==
- V3D_PROJ_RET_OK) {
- const float len = len_manhattan_v2v2(data->mval_f, sco);
- if (len < data->len_best) {
- data->len_best = len;
- data->v_idx_best = index;
- }
+ if (data->hide_vert && data->hide_vert[index]) {
+ return;
+ }
+ float sco[2];
+ if (ED_view3d_project_float_object(data->region, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) ==
+ V3D_PROJ_RET_OK) {
+ const float len = len_manhattan_v2v2(data->mval_f, sco);
+ if (len < data->len_best) {
+ data->len_best = len;
+ data->v_idx_best = index;
}
}
}
@@ -1411,11 +1411,14 @@ bool ED_mesh_pick_vert(
}
/* setup data */
- data.mvert = me->mvert;
+ const Span<MVert> verts = me->verts();
+ data.mvert = verts.data();
data.region = region;
data.mval_f = mval_f;
data.len_best = FLT_MAX;
data.v_idx_best = -1;
+ data.hide_vert = (const bool *)CustomData_get_layer_named(
+ &me_eval->vdata, CD_PROP_BOOL, ".hide_vert");
BKE_mesh_foreach_mapped_vert(me_eval, ed_mesh_pick_vert__mapFunc, &data, MESH_FOREACH_NOP);
@@ -1463,10 +1466,11 @@ MDeformVert *ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
if (r_index) {
*r_index = index;
}
- if (index == -1 || me->dvert == nullptr) {
+ if (index == -1 || me->deform_verts().is_empty()) {
return nullptr;
}
- return me->dvert + index;
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
+ return &dverts[index];
}
MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index 5f13e822f84..6b60967de48 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -110,7 +110,7 @@ static void undomball_free_data(UndoMBall *umb)
static Object *editmball_object_from_context(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit && obedit->type == OB_MBALL) {
MetaBall *mb = obedit->data;
if (mb->editelems != NULL) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 06a649e5b6c..6a5d620b546 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -744,7 +744,7 @@ Base *ED_mball_base_and_elem_from_select_buffer(Base **bases,
const uint hit_object = select_id & 0xFFFF;
Base *base = NULL;
MetaElem *ml = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
+ /* TODO(@campbellbarton): optimize, eg: sort & binary search. */
for (uint base_index = 0; base_index < bases_len; base_index++) {
if (bases[base_index]->object->runtime.select_id == hit_object) {
base = bases[base_index];
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 97376a495c1..17365cc5488 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -21,7 +21,6 @@ set(INC
../../shader_fx
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# dna_type_offsets.h in BLO_read_write.h
@@ -53,7 +52,7 @@ set(SRC
object_shapekey.c
object_transform.cc
object_utils.c
- object_vgroup.c
+ object_vgroup.cc
object_volume.c
object_warp.c
@@ -76,7 +75,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
add_definitions(-DWITH_POINT_CLOUD)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
endif()
blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index 041a1383b28..1068da6816f 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -24,6 +24,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
@@ -36,6 +37,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -71,6 +73,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_nla.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcloud.h"
@@ -113,6 +116,10 @@
#include "object_intern.h"
+using blender::float3;
+using blender::float4x4;
+using blender::Vector;
+
/* -------------------------------------------------------------------- */
/** \name Local Enum Declarations
* \{ */
@@ -602,7 +609,7 @@ Object *ED_object_add_type_with_obdata(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
{
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit != nullptr) {
ED_object_editmode_exit_ex(bmain, scene, obedit, EM_FREEDATA);
}
@@ -622,7 +629,7 @@ Object *ED_object_add_type_with_obdata(bContext *C,
ob = BKE_object_add(bmain, view_layer, type, name);
}
- Base *ob_base_act = BASACT(view_layer);
+ Base *ob_base_act = view_layer->basact;
/* While not getting a valid base is not a good thing, it can happen in convoluted corner cases,
* better not crash on it in releases. */
BLI_assert(ob_base_act != nullptr);
@@ -650,8 +657,7 @@ Object *ED_object_add_type_with_obdata(bContext *C,
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
- /* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
ED_outliner_select_sync_from_object_tag(C);
@@ -984,7 +990,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
}
bool newob = false;
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit == nullptr || obedit->type != OB_MBALL) {
obedit = ED_object_add_type(C, OB_MBALL, nullptr, loc, rot, true, local_view_bits);
newob = true;
@@ -1093,7 +1099,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
bool newob = false;
@@ -1328,21 +1334,21 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
const char *ob_name = nullptr;
switch (type) {
case GP_EMPTY: {
- ob_name = "GPencil";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "GPencil");
break;
}
case GP_MONKEY: {
- ob_name = "Suzanne";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "Suzanne");
break;
}
case GP_STROKE: {
- ob_name = "Stroke";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "Stroke");
break;
}
case GP_LRT_OBJECT:
case GP_LRT_SCENE:
case GP_LRT_COLLECTION: {
- ob_name = "Line Art";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "LineArt");
break;
}
default: {
@@ -1984,7 +1990,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
AnimData *adt = BKE_animdata_ensure_id(&ob->id);
NlaTrack *nlt = BKE_nlatrack_add(adt, nullptr, is_liboverride);
NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, static_cast<Speaker *>(ob->data));
- strip->start = CFRA;
+ strip->start = scene->r.cfra;
strip->end += strip->start;
/* hook them up */
@@ -2023,14 +2029,6 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot)
/** \name Add Curves Operator
* \{ */
-static bool object_curves_add_poll(bContext *C)
-{
- if (!U.experimental.use_new_curves_type) {
- return false;
- }
- return ED_operator_objectmode(C);
-}
-
static int object_curves_random_add_exec(bContext *C, wmOperator *op)
{
using namespace blender;
@@ -2043,7 +2041,6 @@ static int object_curves_random_add_exec(bContext *C, wmOperator *op)
}
Object *object = ED_object_add_type(C, OB_CURVES, nullptr, loc, rot, false, local_view_bits);
- object->dtx |= OB_DRAWBOUNDOX; /* TODO: remove once there is actual drawing. */
Curves *curves_id = static_cast<Curves *>(object->data);
bke::CurvesGeometry::wrap(curves_id->geometry) = ed::curves::primitive_random_sphere(500, 8);
@@ -2060,7 +2057,7 @@ void OBJECT_OT_curves_random_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_curves_random_add_exec;
- ot->poll = object_curves_add_poll;
+ ot->poll = ED_operator_objectmode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2070,38 +2067,48 @@ void OBJECT_OT_curves_random_add(wmOperatorType *ot)
static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
+
ushort local_view_bits;
- float loc[3], rot[3];
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr)) {
+ C, op, 'Z', nullptr, nullptr, nullptr, nullptr, &local_view_bits, nullptr)) {
return OPERATOR_CANCELLED;
}
Object *surface_ob = CTX_data_active_object(C);
+ BLI_assert(surface_ob != nullptr);
- Object *object = ED_object_add_type(C, OB_CURVES, nullptr, loc, rot, false, local_view_bits);
- object->dtx |= OB_DRAWBOUNDOX; /* TODO: remove once there is actual drawing. */
+ Object *curves_ob = ED_object_add_type(
+ C, OB_CURVES, nullptr, nullptr, nullptr, false, local_view_bits);
+ BKE_object_apply_mat4(curves_ob, surface_ob->obmat, false, false);
- if (surface_ob != nullptr && surface_ob->type == OB_MESH) {
- Curves *curves_id = static_cast<Curves *>(object->data);
- curves_id->surface = surface_ob;
- id_us_plus(&surface_ob->id);
+ /* Set surface object. */
+ Curves *curves_id = static_cast<Curves *>(curves_ob->data);
+ curves_id->surface = surface_ob;
- Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data);
- const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->ldata, CD_MLOOPUV);
- if (uv_name != nullptr) {
- curves_id->surface_uv_map = BLI_strdup(uv_name);
- }
+ /* Parent to surface object. */
+ ED_object_parent_set(
+ op->reports, C, scene, curves_ob, surface_ob, PAR_OBJECT, false, true, nullptr);
+
+ /* Decide which UV map to use for attachment. */
+ Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data);
+ const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->ldata, CD_MLOOPUV);
+ if (uv_name != nullptr) {
+ curves_id->surface_uv_map = BLI_strdup(uv_name);
}
+ /* Add deformation modifier. */
+ blender::ed::curves::ensure_surface_deformation_node_exists(*C, *curves_ob);
+
+ /* Make sure the surface object has a rest position attribute which is necessary for
+ * deformations. */
+ surface_ob->modifier_flag |= OB_MODIFIER_FLAG_ADD_REST_POSITION;
+
return OPERATOR_FINISHED;
}
static bool object_curves_empty_hair_add_poll(bContext *C)
{
- if (!U.experimental.use_new_curves_type) {
- return false;
- }
if (!ED_operator_objectmode(C)) {
return false;
}
@@ -2763,47 +2770,6 @@ static const EnumPropertyItem convert_target_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
-static const EnumPropertyItem *convert_target_items_fn(bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- EnumPropertyItem *items = nullptr;
- int items_num = 0;
- for (const EnumPropertyItem *item = convert_target_items; item->identifier != nullptr; item++) {
- if (item->value == OB_CURVES) {
- if (U.experimental.use_new_curves_type) {
- RNA_enum_item_add(&items, &items_num, item);
- }
- }
- else {
- RNA_enum_item_add(&items, &items_num, item);
- }
- }
- RNA_enum_item_end(&items, &items_num);
- *r_free = true;
- return items;
-}
-
-static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- if (ob->runtime.curve_cache == nullptr) {
- /* Force creation. This is normally not needed but on operator
- * redo we might end up with an object which isn't evaluated yet.
- * Also happens in case we are working on a copy of the object
- * (all its caches have been nuked then).
- */
- if (ELEM(ob->type, OB_SURF, OB_CURVES_LEGACY, OB_FONT)) {
- /* We need 'for render' ON here, to enable computing bevel #DispList if needed.
- * Also makes sense anyway, we would not want e.g. to lose hidden parts etc. */
- BKE_displist_make_curveTypes(depsgraph, scene, ob, true);
- }
- else if (ob->type == OB_MBALL) {
- BKE_displist_make_mball(depsgraph, scene, ob);
- }
- }
-}
-
static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob)
{
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
@@ -2922,7 +2888,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
const bool use_faces = RNA_boolean_get(op->ptr, "faces");
const float offset = RNA_float_get(op->ptr, "offset");
- int a, mballConverted = 0;
+ int mballConverted = 0;
bool gpencilConverted = false;
bool gpencilCurveConverted = false;
@@ -3192,9 +3158,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
}
/* Anonymous attributes shouldn't be available on the applied geometry. */
- MeshComponent component;
- component.replace(new_mesh, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ new_mesh->attributes_for_write().remove_anonymous();
BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
}
@@ -3272,7 +3236,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
/* No assumption should be made that the resulting objects is a mesh, as conversion can
* fail. */
object_data_convert_curve_to_mesh(bmain, depsgraph, newob);
- /* meshes doesn't use displist */
+ /* Meshes doesn't use the "curve cache". */
BKE_object_free_curve_cache(newob);
}
else if (target == OB_GPENCIL) {
@@ -3307,7 +3271,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
/* No assumption should be made that the resulting objects is a mesh, as conversion can
* fail. */
object_data_convert_curve_to_mesh(bmain, depsgraph, newob);
- /* meshes doesn't use displist */
+ /* Meshes don't use the "curve cache". */
BKE_object_free_curve_cache(newob);
}
else if (target == OB_GPENCIL) {
@@ -3348,21 +3312,13 @@ static int object_convert_exec(bContext *C, wmOperator *op)
MetaBall *mb = static_cast<MetaBall *>(newob->data);
id_us_min(&mb->id);
- newob->data = BKE_mesh_add(bmain, "Mesh");
- newob->type = OB_MESH;
+ /* Find the evaluated mesh of the basis metaball object. */
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, baseob);
+ Mesh *mesh = BKE_mesh_new_from_object_to_bmain(bmain, depsgraph, object_eval, true);
- Mesh *me = static_cast<Mesh *>(newob->data);
- me->totcol = mb->totcol;
- if (newob->totcol) {
- me->mat = static_cast<Material **>(MEM_dupallocN(mb->mat));
- for (a = 0; a < newob->totcol; a++) {
- id_us_plus((ID *)me->mat[a]);
- }
- }
-
- object_data_convert_ensure_curve_cache(depsgraph, scene, baseob);
- BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp,
- static_cast<Mesh *>(newob->data));
+ id_us_plus(&mesh->id);
+ newob->data = mesh;
+ newob->type = OB_MESH;
if (obact->type == OB_MBALL) {
basact = basen;
@@ -3411,7 +3367,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
/* If the original object is active then make this object active */
if (basen) {
if (ob == obact) {
- /* store new active base to update BASACT */
+ /* Store new active base to update view layer. */
basact = basen;
}
@@ -3485,11 +3441,11 @@ static int object_convert_exec(bContext *C, wmOperator *op)
if (basact) {
/* active base was changed */
ED_object_base_activate(C, basact);
- BASACT(view_layer) = basact;
+ view_layer->basact = basact;
}
- else if (BASACT(view_layer)->object->flag & OB_DONE) {
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT(view_layer)->object);
- WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT(view_layer)->object);
+ else if (view_layer->basact->object->flag & OB_DONE) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, view_layer->basact->object);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DATA, view_layer->basact->object);
}
DEG_relations_tag_update(bmain);
@@ -3544,7 +3500,6 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(
ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to");
- RNA_def_enum_funcs(ot->prop, convert_target_items_fn);
RNA_def_boolean(ot->srna,
"keep_original",
false,
@@ -3600,7 +3555,8 @@ static Base *object_add_duplicate_internal(Main *bmain,
ViewLayer *view_layer,
Object *ob,
const eDupli_ID_Flags dupflag,
- const eLibIDDuplicateFlags duplicate_options)
+ const eLibIDDuplicateFlags duplicate_options,
+ Object **r_ob_new)
{
Base *base, *basen = nullptr;
Object *obn;
@@ -3611,6 +3567,9 @@ static Base *object_add_duplicate_internal(Main *bmain,
else {
obn = static_cast<Object *>(
ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
+ if (r_ob_new) {
+ *r_ob_new = obn;
+ }
DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
base = BKE_view_layer_base_find(view_layer, ob);
@@ -3623,7 +3582,7 @@ static Base *object_add_duplicate_internal(Main *bmain,
}
basen = BKE_view_layer_base_find(view_layer, obn);
- if (base != nullptr) {
+ if (base != nullptr && basen != nullptr) {
basen->local_view_bits = base->local_view_bits;
}
@@ -3654,7 +3613,8 @@ Base *ED_object_add_duplicate(
base->object,
dupflag,
LIB_ID_DUPLICATE_IS_SUBPROCESS |
- LIB_ID_DUPLICATE_IS_ROOT_ID);
+ LIB_ID_DUPLICATE_IS_ROOT_ID,
+ nullptr);
if (basen == nullptr) {
return nullptr;
}
@@ -3687,46 +3647,75 @@ static int duplicate_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
const bool linked = RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
- bool changed = false;
/* We need to handle that here ourselves, because we may duplicate several objects, in which case
* we also want to remap pointers between those... */
BKE_main_id_newptr_and_tag_clear(bmain);
- CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
- Base *basen = object_add_duplicate_internal(bmain,
- scene,
- view_layer,
- base->object,
- dupflag,
- LIB_ID_DUPLICATE_IS_SUBPROCESS |
- LIB_ID_DUPLICATE_IS_ROOT_ID);
+ /* Do not do collection re-syncs for each object; will do it once afterwards.
+ * However this means we can't get to new duplicated Base's immediately, will
+ * have to process them after the sync. */
+ BKE_layer_collection_resync_forbid();
- /* note that this is safe to do with this context iterator,
- * the list is made in advance */
- ED_object_base_select(base, BA_DESELECT);
- ED_object_base_select(basen, BA_SELECT);
- changed = true;
+ /* Duplicate the selected objects, remember data needed to process
+ * after the sync (the base of the original object, and the copy of the
+ * original object). */
+ blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects;
+ Object *ob_new_active = nullptr;
- if (basen == nullptr) {
+ CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
+ Object *ob_new = nullptr;
+ object_add_duplicate_internal(bmain,
+ scene,
+ view_layer,
+ base->object,
+ dupflag,
+ LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID,
+ &ob_new);
+ if (ob_new == nullptr) {
continue;
}
+ source_bases_new_objects.append({base, ob_new});
- /* new object becomes active */
- if (BASACT(view_layer) == base) {
- ED_object_base_activate(C, basen);
- }
+ /* note that this is safe to do with this context iterator,
+ * the list is made in advance */
+ ED_object_base_select(base, BA_DESELECT);
- if (basen->object->data) {
- DEG_id_tag_update(static_cast<ID *>(basen->object->data), 0);
+ /* new object will become active */
+ if (view_layer->basact == base) {
+ ob_new_active = ob_new;
}
}
CTX_DATA_END;
+ BKE_layer_collection_resync_allow();
- if (!changed) {
+ if (source_bases_new_objects.is_empty()) {
return OPERATOR_CANCELLED;
}
+ /* Sync the collection now, after everything is duplicated. */
+ BKE_main_collection_sync(bmain);
+
+ /* After sync we can get to the new Base data, process it here. */
+ for (const auto &item : source_bases_new_objects) {
+ Object *ob_new = item.second;
+ Base *base_source = item.first;
+ Base *base_new = BKE_view_layer_base_find(view_layer, ob_new);
+ if (base_new == nullptr) {
+ continue;
+ }
+ ED_object_base_select(base_new, BA_SELECT);
+ if (ob_new == ob_new_active) {
+ ED_object_base_activate(C, base_new);
+ }
+ if (base_new->object->data) {
+ DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0);
+ }
+ /* #object_add_duplicate_internal will not have done this, since
+ * before the collection sync it would not have found the new base yet. */
+ base_new->local_view_bits = base_source->local_view_bits;
+ }
+
/* Note that this will also clear newid pointers and tags. */
copy_object_set_idnew(C);
@@ -3808,7 +3797,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
* the case here. So we have to do the new-ID relinking ourselves
* (#copy_object_set_idnew()).
*/
- LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID);
+ LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID,
+ nullptr);
if (basen == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
@@ -3904,7 +3894,7 @@ static int object_transform_to_mouse_exec(bContext *C, wmOperator *op)
WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
if (!ob) {
- ob = OBACT(view_layer);
+ ob = BKE_view_layer_active_object_get(view_layer);
}
if (ob == nullptr) {
@@ -3976,7 +3966,7 @@ void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
/* api callbacks */
ot->invoke = object_add_drop_xy_generic_invoke;
ot->exec = object_transform_to_mouse_exec;
- ot->poll = ED_operator_objectmode;
+ ot->poll = ED_operator_objectmode_poll_msg;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index effbde41c38..8d505bbca3e 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -155,15 +155,16 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
break;
}
- if (!me->mloopuv) {
+ if (!CustomData_has_layer(&me->ldata, CD_MLOOPUV)) {
BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking");
ok = false;
}
else {
+ const int *material_indices = BKE_mesh_material_indices(me);
a = me->totpoly;
while (ok && a--) {
- Image *ima = bake_object_image_get(ob, me->mpoly[a].mat_nr);
+ Image *ima = bake_object_image_get(ob, material_indices ? material_indices[a] : 0);
if (!ima) {
BKE_report(
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 006379123f8..8db699cceb8 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -21,8 +21,10 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BKE_attribute.h"
#include "BKE_callbacks.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_image_format.h"
@@ -323,7 +325,7 @@ static bool write_external_bake_pixels(const char *filepath,
const int height,
const int margin,
const int margin_type,
- ImageFormatData *im_format,
+ ImageFormatData const *im_format,
const bool is_noncolor,
Mesh const *mesh_eval,
char const *uv_layer,
@@ -447,14 +449,11 @@ static bool bake_object_check(ViewLayer *view_layer,
}
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
- const MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol == NULL && !mcol_valid) {
+ if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
BKE_reportf(reports,
RPT_ERROR,
- "No vertex colors layer found in the object \"%s\"",
- ob->id.name + 2);
+ "Mesh does not have an active color attribute \"%s\"",
+ me->id.name + 2);
return false;
}
}
@@ -935,23 +934,25 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
/* Vertex Color Bake Targets */
-static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, ReportList *reports)
+static bool bake_targets_init_vertex_colors(Main *bmain,
+ BakeTargets *targets,
+ Object *ob,
+ ReportList *reports)
{
if (ob->type != OB_MESH) {
- BKE_report(
- reports, RPT_ERROR, "Vertex color baking not support with object types other than mesh");
+ BKE_report(reports, RPT_ERROR, "Color attribute baking is only supported for mesh objects");
return false;
}
Mesh *me = ob->data;
- const MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol == NULL && !mcol_valid) {
- BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to");
+ if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active color attribute to bake to");
return false;
}
+ /* Ensure mesh and editmesh topology are in sync. */
+ ED_object_editmode_load(bmain, ob);
+
targets->images = MEM_callocN(sizeof(BakeImage), "BakeTargets.images");
targets->images_num = 1;
@@ -970,7 +971,8 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re
return true;
}
-static int find_original_loop(const Mesh *me_orig,
+static int find_original_loop(const MPoly *orig_polys,
+ const MLoop *orig_loops,
const int *vert_origindex,
const int *poly_origindex,
const int poly_eval,
@@ -986,8 +988,8 @@ static int find_original_loop(const Mesh *me_orig,
}
/* Find matching loop with original vertex in original polygon. */
- MPoly *mpoly_orig = me_orig->mpoly + poly_orig;
- MLoop *mloop_orig = me_orig->mloop + mpoly_orig->loopstart;
+ const MPoly *mpoly_orig = orig_polys + poly_orig;
+ const MLoop *mloop_orig = orig_loops + mpoly_orig->loopstart;
for (int j = 0; j < mpoly_orig->totloop; ++j, ++mloop_orig) {
if (mloop_orig->v == vert_orig) {
return mpoly_orig->loopstart + j;
@@ -997,10 +999,10 @@ static int find_original_loop(const Mesh *me_orig,
return ORIGINDEX_NONE;
}
-static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
- Object *ob,
- Mesh *me_eval,
- BakePixel *pixel_array)
+static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets,
+ Object *ob,
+ Mesh *me_eval,
+ BakePixel *pixel_array)
{
Mesh *me = ob->data;
const int pixels_num = targets->pixels_num;
@@ -1024,23 +1026,31 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
const int tottri = poly_to_tri_count(me_eval->totpoly, me_eval->totloop);
MLoopTri *looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
- BKE_mesh_recalc_looptri(
- me_eval->mloop, me_eval->mpoly, me_eval->mvert, me_eval->totloop, me_eval->totpoly, looptri);
+ const MLoop *loops = BKE_mesh_loops(me_eval);
+ BKE_mesh_recalc_looptri(loops,
+ BKE_mesh_polys(me_eval),
+ BKE_mesh_verts(me_eval),
+ me_eval->totloop,
+ me_eval->totpoly,
+ looptri);
/* For mapping back to original mesh in case there are modifiers. */
const int *vert_origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
const int *poly_origindex = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
+ const MPoly *orig_polys = BKE_mesh_polys(me);
+ const MLoop *orig_loops = BKE_mesh_loops(me);
for (int i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
for (int j = 0; j < 3; j++) {
unsigned int l = lt->tri[j];
- unsigned int v = me_eval->mloop[l].v;
+ unsigned int v = loops[l].v;
/* Map back to original loop if there are modifiers. */
if (vert_origindex != NULL && poly_origindex != NULL) {
- l = find_original_loop(me, vert_origindex, poly_origindex, lt->poly, v);
+ l = find_original_loop(
+ orig_polys, orig_loops, vert_origindex, poly_origindex, lt->poly, v);
if (l == ORIGINDEX_NONE || l >= me->totloop) {
continue;
}
@@ -1095,24 +1105,46 @@ static void bake_result_add_to_rgba(float rgba[4], const float *result, const in
}
}
+static void convert_float_color_to_byte_color(const MPropCol *float_colors,
+ const int num,
+ const bool is_noncolor,
+ MLoopCol *byte_colors)
+{
+ if (is_noncolor) {
+ for (int i = 0; i < num; i++) {
+ unit_float_to_uchar_clamp_v4(&byte_colors->r, float_colors[i].color);
+ }
+ }
+ else {
+ for (int i = 0; i < num; i++) {
+ linearrgb_to_srgb_uchar4(&byte_colors[i].r, float_colors[i].color);
+ }
+ }
+}
+
static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
{
Mesh *me = ob->data;
- MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
+ BMEditMesh *em = me->edit_mesh;
+ CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
+ BLI_assert(active_color_layer != NULL);
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, active_color_layer);
+
const int channels_num = targets->channels_num;
+ const bool is_noncolor = targets->is_noncolor;
const float *result = targets->result;
- if (mcol_valid) {
+ if (domain == ATTR_DOMAIN_POINT) {
const int totvert = me->totvert;
const int totloop = me->totloop;
+ MPropCol *mcol = MEM_malloc_arrayN(totvert, sizeof(MPropCol), __func__);
+
/* Accumulate float vertex colors in scene linear color space. */
int *num_loops_for_vertex = MEM_callocN(sizeof(int) * me->totvert, "num_loops_for_vertex");
memset(mcol, 0, sizeof(MPropCol) * me->totvert);
- MLoop *mloop = me->mloop;
+ const MLoop *mloop = BKE_mesh_loops(me);
for (int i = 0; i < totloop; i++, mloop++) {
const int v = mloop->v;
bake_result_add_to_rgba(mcol[v].color, &result[i * channels_num], channels_num);
@@ -1126,24 +1158,82 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
}
}
- MEM_SAFE_FREE(num_loops_for_vertex);
- }
- else {
- /* Byte loop colors in sRGB colors space. */
- MLoop *mloop = me->mloop;
- const int totloop = me->totloop;
- const bool is_noncolor = targets->is_noncolor;
+ if (em) {
+ /* Copy to bmesh. */
+ const int active_color_offset = CustomData_get_offset_named(
+ &em->bm->vdata, active_color_layer->type, active_color_layer->name);
+ BMVert *v;
+ BMIter viter;
+ int i = 0;
+ BM_ITER_MESH (v, &viter, em->bm, BM_VERTS_OF_MESH) {
+ void *data = BM_ELEM_CD_GET_VOID_P(v, active_color_offset);
+ if (active_color_layer->type == CD_PROP_COLOR) {
+ memcpy(data, &mcol[i], sizeof(MPropCol));
+ }
+ else {
+ convert_float_color_to_byte_color(&mcol[i], 1, is_noncolor, data);
+ }
+ i++;
+ }
+ }
+ else {
+ /* Copy to mesh. */
+ if (active_color_layer->type == CD_PROP_COLOR) {
+ memcpy(active_color_layer->data, mcol, sizeof(MPropCol) * me->totvert);
+ }
+ else {
+ convert_float_color_to_byte_color(mcol, totvert, is_noncolor, active_color_layer->data);
+ }
+ }
- for (int i = 0; i < totloop; i++, mloop++, mloopcol++) {
- float rgba[4];
- zero_v4(rgba);
- bake_result_add_to_rgba(rgba, &result[i * channels_num], channels_num);
+ MEM_freeN(mcol);
- if (is_noncolor) {
- unit_float_to_uchar_clamp_v4(&mloopcol->r, rgba);
+ MEM_SAFE_FREE(num_loops_for_vertex);
+ }
+ else if (domain == ATTR_DOMAIN_CORNER) {
+ if (em) {
+ /* Copy to bmesh. */
+ const int active_color_offset = CustomData_get_offset_named(
+ &em->bm->ldata, active_color_layer->type, active_color_layer->name);
+ BMFace *f;
+ BMIter fiter;
+ int i = 0;
+ BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MPropCol color;
+ zero_v4(color.color);
+ bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num);
+ i++;
+
+ void *data = BM_ELEM_CD_GET_VOID_P(l, active_color_offset);
+ if (active_color_layer->type == CD_PROP_COLOR) {
+ memcpy(data, &color, sizeof(MPropCol));
+ }
+ else {
+ convert_float_color_to_byte_color(&color, 1, is_noncolor, data);
+ }
+ }
+ }
+ }
+ else {
+ /* Copy to mesh. */
+ if (active_color_layer->type == CD_PROP_COLOR) {
+ MPropCol *colors = active_color_layer->data;
+ for (int i = 0; i < me->totloop; i++) {
+ zero_v4(colors[i].color);
+ bake_result_add_to_rgba(colors[i].color, &result[i * channels_num], channels_num);
+ }
}
else {
- linearrgb_to_srgb_uchar4(&mloopcol->r, rgba);
+ MLoopCol *colors = active_color_layer->data;
+ for (int i = 0; i < me->totloop; i++) {
+ MPropCol color;
+ zero_v4(color.color);
+ bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num);
+ convert_float_color_to_byte_color(&color, 1, is_noncolor, &colors[i]);
+ }
}
}
}
@@ -1174,7 +1264,7 @@ static bool bake_targets_init(const BakeAPIRender *bkr,
}
}
else if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
- if (!bake_targets_init_vertex_colors(targets, ob, reports)) {
+ if (!bake_targets_init_vertex_colors(bkr->main, targets, ob, reports)) {
return false;
}
}
@@ -1198,7 +1288,7 @@ static void bake_targets_populate_pixels(const BakeAPIRender *bkr,
BakePixel *pixel_array)
{
if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
- bake_targets_populate_pixels_vertex_colors(targets, ob, me_eval, pixel_array);
+ bake_targets_populate_pixels_color_attributes(targets, ob, me_eval, pixel_array);
}
else {
RE_bake_pixels_populate(me_eval, pixel_array, targets->pixels_num, targets, bkr->uv_layer);
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index 39951c2ab6e..426f33e53ca 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -16,6 +16,7 @@
#include "BKE_collection.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -202,7 +203,7 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
int single_collection_index = RNA_enum_get(op->ptr, "collection");
Collection *single_collection = collection_object_active_find_index(
bmain, scene, ob, single_collection_index);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index bf3b71178e8..28ba2b04b6f 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -50,6 +50,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "ED_keyframing.h"
@@ -2313,7 +2314,7 @@ static bool get_new_constraint_target(
if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
Object *obt;
/* add new target object */
@@ -2335,7 +2336,7 @@ static bool get_new_constraint_target(
}
/* restore, BKE_object_add sets active */
- BASACT(view_layer) = base;
+ view_layer->basact = base;
ED_object_base_select(base, BA_SELECT);
/* make our new target the new object */
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 4837b538bf6..78b059d5514 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -45,7 +45,7 @@
* Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */
/* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */
static const EnumPropertyItem DT_layer_items[] = {
- RNA_ENUM_ITEM_HEADING("Vertex Data", NULL),
+ RNA_ENUM_ITEM_HEADING(N_("Vertex Data"), NULL),
{DT_TYPE_MDEFORMVERT,
"VGROUP_WEIGHTS",
0,
@@ -61,7 +61,7 @@ static const EnumPropertyItem DT_layer_items[] = {
#endif
{DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"},
- RNA_ENUM_ITEM_HEADING("Edge Data", NULL),
+ RNA_ENUM_ITEM_HEADING(N_("Edge Data"), NULL),
{DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"},
{DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"},
{DT_TYPE_CREASE, "CREASE", 0, "Subdivision Crease", "Transfer crease values"},
@@ -72,12 +72,12 @@ static const EnumPropertyItem DT_layer_items[] = {
"Freestyle Mark",
"Transfer Freestyle edge mark"},
- RNA_ENUM_ITEM_HEADING("Face Corner Data", NULL),
+ RNA_ENUM_ITEM_HEADING(N_("Face Corner Data"), NULL),
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
{DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP, "VCOL", 0, "Colors", "Color Attributes"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
- RNA_ENUM_ITEM_HEADING("Face Data", NULL),
+ RNA_ENUM_ITEM_HEADING(N_("Face Data"), NULL),
{DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"},
{DT_TYPE_FREESTYLE_FACE,
"FREESTYLE_FACE",
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index e5dd9fb2c8b..1bfb0c5f260 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -141,7 +141,7 @@ Object **ED_object_array_in_mode_or_selected(bContext *C,
{
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_active = OBACT(view_layer);
+ Object *ob_active = BKE_view_layer_active_object_get(view_layer);
ID *id_pin = NULL;
const bool use_objects_in_mode = (ob_active != NULL) &&
(ob_active->mode & (OB_MODE_EDIT | OB_MODE_POSE));
@@ -194,13 +194,13 @@ Object **ED_object_array_in_mode_or_selected(bContext *C,
/* When in a mode that supports multiple active objects, use "objects in mode"
* instead of the object's selection. */
if (use_objects_in_mode) {
- objects = BKE_view_layer_array_from_objects_in_mode(view_layer,
- v3d,
- r_objects_len,
- {.object_mode = ob_active->mode,
- .no_dup_data = true,
- .filter_fn = filter_fn,
- .filter_userdata = filter_user_data});
+ struct ObjectsInModeParams params = {0};
+ params.object_mode = ob_active->mode;
+ params.no_dup_data = true;
+ params.filter_fn = filter_fn;
+ params.filter_userdata = filter_user_data;
+ objects = BKE_view_layer_array_from_objects_in_mode_params(
+ view_layer, v3d, r_objects_len, &params);
}
else {
objects = BKE_view_layer_array_selected_objects(
@@ -701,7 +701,7 @@ bool ED_object_editmode_free_ex(Main *bmain, Object *obedit)
bool ED_object_editmode_exit_multi_ex(Main *bmain, Scene *scene, ViewLayer *view_layer, int flag)
{
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit == NULL) {
return false;
}
@@ -841,7 +841,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
const int mode_flag = OB_MODE_EDIT;
const bool is_mode_set = (obact->mode & mode_flag) != 0;
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
@@ -889,13 +889,13 @@ static bool editmode_toggle_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- /* covers proxies too */
+ /* Covers liboverrides too. */
if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob) ||
ID_IS_OVERRIDE_LIBRARY(ob->data)) {
return false;
}
- /* if hidden but in edit mode, we still display */
+ /* If hidden but in edit mode, we still display. */
if ((ob->visibility_flag & OB_HIDE_VIEWPORT) && !(ob->mode & OB_MODE_EDIT)) {
return false;
}
@@ -953,7 +953,7 @@ static int posemode_exec(bContext *C, wmOperator *op)
}
{
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obact == obedit) {
ED_object_editmode_exit_ex(bmain, scene, obedit, EM_FREEDATA);
is_mode_set = false;
@@ -1244,7 +1244,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
- /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ /* NOTE: the notifier below isn't actually correct, but kept around just to be on the safe side.
* If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
@@ -1316,7 +1316,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *op)
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
- /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ /* NOTE: the notifier below isn't actually correct, but kept around just to be on the safe side.
* If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
@@ -1469,8 +1469,6 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
- const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
- const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
bool changed_multi = false;
bool has_linked_data = false;
@@ -1480,7 +1478,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
/* For modes that only use an active object, don't handle the whole selection. */
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
if (obact && ((obact->mode & OB_MODE_ALL_PAINT))) {
ctx_ob_single_active.ptr.data = obact;
BLI_addtail(&ctx_objects, &ctx_ob_single_active);
@@ -1518,7 +1516,11 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
bool changed = false;
if (ob->type == OB_MESH) {
BKE_mesh_smooth_flag_set(ob->data, use_smooth);
- BKE_mesh_auto_smooth_flag_set(ob->data, use_auto_smooth, auto_smooth_angle);
+ if (use_smooth) {
+ const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
+ const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
+ BKE_mesh_auto_smooth_flag_set(ob->data, use_auto_smooth, auto_smooth_angle);
+ }
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
changed = true;
}
@@ -1549,7 +1551,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
static bool shade_poll(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
if (obact != NULL) {
/* Doesn't handle edit-data, sculpt dynamic-topology, or their undo systems. */
if (obact->mode & (OB_MODE_EDIT | OB_MODE_SCULPT) || obact->data == NULL ||
diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c
index dddf5e40e87..4364375a4e3 100644
--- a/source/blender/editors/object/object_facemap_ops.c
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -53,7 +53,7 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
/* if there's is no facemap layer then create one */
if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) {
- facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
+ facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, NULL, me->totpoly);
}
facemap[facenum] = fmap_nr;
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 573f048e6b6..42ac6d166b4 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -680,8 +680,7 @@ static int gpencil_modifier_move_to_index_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_active_context(C);
GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
int index = RNA_int_get(op->ptr, "index");
-
- if (!ED_object_gpencil_modifier_move_to_index(op->reports, ob, md, index)) {
+ if (!(md && ED_object_gpencil_modifier_move_to_index(op->reports, ob, md, index))) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index b5862d4d957..63f010cd526 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -49,10 +49,14 @@ void OBJECT_OT_vertex_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_track_set(struct wmOperatorType *ot);
void OBJECT_OT_track_clear(struct wmOperatorType *ot);
void OBJECT_OT_make_local(struct wmOperatorType *ot);
-void OBJECT_OT_make_override_library(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
+
+void OBJECT_OT_make_override_library(struct wmOperatorType *ot);
+void OBJECT_OT_reset_override_library(struct wmOperatorType *ot);
+void OBJECT_OT_clear_override_library(struct wmOperatorType *ot);
+
/**
* Used for drop-box.
* Assigns to object under cursor, only first material slot.
@@ -259,7 +263,7 @@ void CONSTRAINT_OT_objectsolver_set_inverse(struct wmOperatorType *ot);
void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot);
void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot);
-/* object_vgroup.c */
+/* object_vgroup.cc */
void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 0055cdf9ea1..27d8c326d41 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -191,7 +191,7 @@ bool ED_object_mode_set_ex(bContext *C, eObjectMode mode, bool use_undo, ReportL
{
wmWindowManager *wm = CTX_wm_manager(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob == NULL) {
return (mode == OB_MODE_OBJECT);
}
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 202c6d96a47..9bb82cc086c 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -47,9 +47,11 @@
#include "BKE_gpencil_modifier.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
@@ -92,6 +94,8 @@
#include "object_intern.h"
+using blender::Span;
+
static void modifier_skin_customdata_delete(struct Object *ob);
/* ------------------------------------------------------------------- */
@@ -111,7 +115,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *
BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval);
}
else if (ob->type == OB_MBALL) {
- BKE_displist_make_mball(depsgraph, scene_eval, ob_eval);
+ BKE_mball_data_update(depsgraph, scene_eval, ob_eval);
}
else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false);
@@ -486,6 +490,9 @@ bool ED_object_modifier_move_to_index(ReportList *reports,
}
}
+ /* NOTE: Dependency graph only uses modifier nodes for visibility updates, and exact order of
+ * modifier nodes in the graph does not matter. */
+
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
@@ -582,12 +589,14 @@ bool ED_object_modifier_convert_psys_to_mesh(ReportList *UNUSED(reports),
me->totvert = verts_num;
me->totedge = edges_num;
- me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, verts_num);
- me->medge = (MEdge *)CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, edges_num);
- me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, nullptr, 0);
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, verts_num);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, edges_num);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, 0);
- MVert *mvert = me->mvert;
- MEdge *medge = me->medge;
+ blender::MutableSpan<MVert> verts = me->verts_for_write();
+ blender::MutableSpan<MEdge> edges = me->edges_for_write();
+ MVert *mvert = verts.data();
+ MEdge *medge = edges.data();
/* copy coordinates */
cache = psys_eval->pathcache;
@@ -757,9 +766,7 @@ static bool modifier_apply_obdata(
BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true);
/* Anonymous attributes shouldn't be available on the applied geometry. */
- MeshComponent component;
- component.replace(me, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ me->attributes_for_write().remove_anonymous();
if (md_eval->type == eModifierType_Multires) {
multires_customdata_delete(me);
@@ -820,7 +827,7 @@ static bool modifier_apply_obdata(
/* Create a temporary geometry set and component. */
GeometrySet geometry_set;
geometry_set.get_component_for_write<CurveComponent>().replace(
- &curves, GeometryOwnershipType::Editable);
+ &curves, GeometryOwnershipType::ReadOnly);
ModifierEvalContext mectx = {depsgraph, ob, (ModifierApplyFlag)0};
mti->modifyGeometrySet(md_eval, &mectx, &geometry_set);
@@ -828,20 +835,18 @@ static bool modifier_apply_obdata(
BKE_report(reports, RPT_ERROR, "Evaluated geometry from modifier does not contain curves");
return false;
}
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
Curves &curves_eval = *geometry_set.get_curves_for_write();
/* Anonymous attributes shouldn't be available on the applied geometry. */
- component.attributes_remove_anonymous();
+ blender::bke::CurvesGeometry::wrap(curves_eval.geometry)
+ .attributes_for_write()
+ .remove_anonymous();
- /* If the modifier's output is a different curves data-block, copy the relevant information to
- * the original. */
- if (&curves_eval != &curves) {
- blender::bke::CurvesGeometry::wrap(curves.geometry) = std::move(
- blender::bke::CurvesGeometry::wrap(curves_eval.geometry));
- Main *bmain = DEG_get_bmain(depsgraph);
- BKE_object_material_from_eval_data(bmain, ob, &curves_eval.id);
- }
+ /* Copy the relevant information to the original. */
+ blender::bke::CurvesGeometry::wrap(curves.geometry) = std::move(
+ blender::bke::CurvesGeometry::wrap(curves_eval.geometry));
+ Main *bmain = DEG_get_bmain(depsgraph);
+ BKE_object_material_from_eval_data(bmain, ob, &curves_eval.id);
}
else {
/* TODO: implement for point clouds and volumes. */
@@ -1227,7 +1232,7 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
/* if cloth/softbody was removed, particle mode could be cleared */
if (mode_orig & OB_MODE_PARTICLE_EDIT) {
if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
- if (ob == OBACT(view_layer)) {
+ if (ob == BKE_view_layer_active_object_get(view_layer)) {
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
@@ -1367,7 +1372,7 @@ static int modifier_move_to_index_exec(bContext *C, wmOperator *op)
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int index = RNA_int_get(op->ptr, "index");
- if (!ED_object_modifier_move_to_index(op->reports, ob, md, index)) {
+ if (!(md && ED_object_modifier_move_to_index(op->reports, ob, md, index))) {
return OPERATOR_CANCELLED;
}
@@ -1440,7 +1445,6 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
- const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
const bool do_report = RNA_boolean_get(op->ptr, "report");
const bool do_single_user = RNA_boolean_get(op->ptr, "single_user");
const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata");
@@ -1449,6 +1453,8 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
return OPERATOR_CANCELLED;
}
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
+
if (do_single_user && ID_REAL_USERS(ob->data) > 1) {
ED_object_single_obdata_user(bmain, scene, ob);
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -1671,6 +1677,7 @@ static int modifier_copy_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -2586,8 +2593,8 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot)
}
static void skin_armature_bone_create(Object *skin_ob,
- MVert *mvert,
- MEdge *medge,
+ const MVert *mvert,
+ const MEdge *medge,
bArmature *arm,
BLI_bitmap *edges_visited,
const MeshElemMap *emap,
@@ -2632,15 +2639,18 @@ static void skin_armature_bone_create(Object *skin_ob,
static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, Object *skin_ob)
{
Mesh *me = static_cast<Mesh *>(skin_ob->data);
+ const Span<MVert> me_verts = me->verts();
+ const Span<MEdge> me_edges = me->edges();
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, skin_ob);
- Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
- MVert *mvert = me_eval_deform->mvert;
+ const Mesh *me_eval_deform = mesh_get_eval_deform(
+ depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+ const Span<MVert> verts_eval = me_eval_deform->verts();
/* add vertex weights to original mesh */
- CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, me->totvert);
+ CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, me->totvert);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
Object *arm_ob = BKE_object_add(bmain, view_layer, OB_ARMATURE, nullptr);
@@ -2655,7 +2665,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain,
CustomData_get_layer(&me->vdata, CD_MVERT_SKIN));
int *emap_mem;
MeshElemMap *emap;
- BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
+ BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me_edges.data(), me->totvert, me->totedge);
BLI_bitmap *edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited");
@@ -2671,15 +2681,16 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain,
if (emap[v].count > 1) {
bone = ED_armature_ebone_add(arm, "Bone");
- copy_v3_v3(bone->head, me->mvert[v].co);
- copy_v3_v3(bone->tail, me->mvert[v].co);
+ copy_v3_v3(bone->head, me_verts[v].co);
+ copy_v3_v3(bone->tail, me_verts[v].co);
bone->head[1] = 1.0f;
bone->rad_head = bone->rad_tail = 0.25;
}
if (emap[v].count >= 1) {
- skin_armature_bone_create(skin_ob, mvert, me->medge, arm, edges_visited, emap, bone, v);
+ skin_armature_bone_create(
+ skin_ob, verts_eval.data(), me_edges.data(), arm, edges_visited, emap, bone, v);
}
}
}
@@ -3347,6 +3358,7 @@ void OBJECT_OT_geometry_nodes_input_attribute_toggle(wmOperatorType *ot)
ot->idname = "OBJECT_OT_geometry_nodes_input_attribute_toggle";
ot->exec = geometry_nodes_input_attribute_toggle_exec;
+ ot->poll = ED_operator_object_active;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -3364,9 +3376,8 @@ static int geometry_node_tree_copy_assign_exec(bContext *C, wmOperator *UNUSED(o
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
-
ModifierData *md = BKE_object_active_modifier(ob);
- if (md->type != eModifierType_Nodes) {
+ if (!(md && md->type == eModifierType_Nodes)) {
return OPERATOR_CANCELLED;
}
@@ -3398,6 +3409,7 @@ void OBJECT_OT_geometry_node_tree_copy_assign(wmOperatorType *ot)
ot->idname = "OBJECT_OT_geometry_node_tree_copy_assign";
ot->exec = geometry_node_tree_copy_assign_exec;
+ ot->poll = ED_operator_object_active;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 8a0d380ff2f..24a4556b075 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -58,11 +58,14 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_track_set);
WM_operatortype_append(OBJECT_OT_track_clear);
WM_operatortype_append(OBJECT_OT_make_local);
- WM_operatortype_append(OBJECT_OT_make_override_library);
WM_operatortype_append(OBJECT_OT_make_single_user);
WM_operatortype_append(OBJECT_OT_make_links_scene);
WM_operatortype_append(OBJECT_OT_make_links_data);
+ WM_operatortype_append(OBJECT_OT_make_override_library);
+ WM_operatortype_append(OBJECT_OT_reset_override_library);
+ WM_operatortype_append(OBJECT_OT_clear_override_library);
+
WM_operatortype_append(OBJECT_OT_select_random);
WM_operatortype_append(OBJECT_OT_select_all);
WM_operatortype_append(OBJECT_OT_select_same_collection);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index f55ffdf0fcd..40dbd6b7bd8 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -263,7 +263,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
else {
Object workob;
- ob->parent = BASACT(view_layer)->object;
+ ob->parent = view_layer->basact->object;
if (par3 != INDEX_UNSET) {
ob->partype = PARVERT3;
ob->par1 = par1;
@@ -951,7 +951,7 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
1);
struct {
- bool mesh, gpencil;
+ bool mesh, gpencil, curves;
} has_children_of_type = {0};
CTX_DATA_BEGIN (C, Object *, child, selected_editable_objects) {
@@ -964,6 +964,9 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
if (child->type == OB_GPENCIL) {
has_children_of_type.gpencil = true;
}
+ if (child->type == OB_CURVES) {
+ has_children_of_type.curves = true;
+ }
}
CTX_DATA_END;
@@ -987,6 +990,11 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
else if (parent->type == OB_LATTICE) {
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE);
}
+ else if (parent->type == OB_MESH) {
+ if (has_children_of_type.curves) {
+ uiItemO(layout, "Object (Attach Curves to Surface)", ICON_NONE, "CURVES_OT_surface_set");
+ }
+ }
/* vertex parenting */
if (OB_TYPE_SUPPORT_PARVERT(parent->type)) {
@@ -1822,6 +1830,11 @@ static void single_obdata_users(
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
switch (ob->type) {
+ case OB_EMPTY:
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
+ break;
case OB_LAMP:
ob->data = la = ID_NEW_SET(
ob->data,
@@ -2267,12 +2280,6 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
ID *id_root = NULL;
bool is_override_instancing_object = false;
- const bool do_fully_editable = RNA_boolean_get(op->ptr, "do_fully_editable");
-
- GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
- BLI_gset_new(BLI_ghashutil_inthash_p,
- BLI_ghashutil_intcmp,
- __func__);
bool user_overrides_from_selected_objects = false;
if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
@@ -2312,6 +2319,21 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
user_overrides_from_selected_objects = true;
}
+ const bool do_fully_editable = !user_overrides_from_selected_objects;
+
+ GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
+ BLI_gset_new(BLI_ghashutil_inthash_p,
+ BLI_ghashutil_intcmp,
+ __func__);
+
+ /* Make already existing selected liboverrides editable. */
+ FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) {
+ ob_iter->id.override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+
if (do_fully_editable) {
/* Pass. */
}
@@ -2334,6 +2356,25 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* For the time being, replace selected linked objects by their overrides in all collections.
+ * While this may not be the absolute best behavior in all cases, in most common one this should
+ * match the expected result. */
+ if (user_overrides_objects_uids != NULL) {
+ LISTBASE_FOREACH (Collection *, coll_iter, &bmain->collections) {
+ if (ID_IS_LINKED(coll_iter)) {
+ continue;
+ }
+ LISTBASE_FOREACH (CollectionObject *, coll_ob_iter, &coll_iter->gobject) {
+ if (BLI_gset_haskey(user_overrides_objects_uids,
+ POINTER_FROM_UINT(coll_ob_iter->ob->id.session_uuid))) {
+ /* Tag for remapping when creating overrides. */
+ coll_iter->id.tag |= LIB_TAG_DOIT;
+ break;
+ }
+ }
+ }
+ }
+
ID *id_root_override;
const bool success = BKE_lib_override_library_create(bmain,
scene,
@@ -2398,6 +2439,8 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
@@ -2422,6 +2465,9 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve
}
if (!ID_IS_LINKED(obact)) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(obact)) {
+ return make_override_library_exec(C, op);
+ }
BKE_report(op->reports, RPT_ERROR, "Cannot make library override from a local object");
return OPERATOR_CANCELLED;
}
@@ -2460,17 +2506,20 @@ static bool make_override_library_poll(bContext *C)
Object *obact = CTX_data_active_object(C);
/* Object must be directly linked to be overridable. */
- return (ED_operator_objectmode(C) && obact != NULL &&
- (ID_IS_LINKED(obact) || (obact->instance_collection != NULL &&
- ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) &&
- !ID_IS_OVERRIDE_LIBRARY(obact))));
+ return (
+ ED_operator_objectmode(C) && obact != NULL &&
+ (ID_IS_LINKED(obact) || ID_IS_OVERRIDE_LIBRARY(obact) ||
+ (obact->instance_collection != NULL &&
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) && !ID_IS_OVERRIDE_LIBRARY(obact))));
}
void OBJECT_OT_make_override_library(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Make Library Override";
- ot->description = "Make a local override of this library linked data-block";
+ ot->description =
+ "Create a local override of the selected linked objects, and their hierarchy of "
+ "dependencies";
ot->idname = "OBJECT_OT_make_override_library";
/* api callbacks */
@@ -2495,13 +2544,129 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
ot->prop = prop;
+}
- prop = RNA_def_boolean(ot->srna,
- "do_fully_editable",
- false,
- "Create Fully Editable",
- "Make all created override data-blocks fully editable");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Reset Library Override Operator
+ * \{ */
+
+static bool reset_clear_override_library_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ /* Object must be local and an override. */
+ return (ED_operator_objectmode(C) && obact != NULL && !ID_IS_LINKED(obact) &&
+ ID_IS_OVERRIDE_LIBRARY(obact));
+}
+
+static int reset_override_library_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+
+ /* Make already existing selected liboverrides editable. */
+ FOREACH_SELECTED_OBJECT_BEGIN (CTX_data_view_layer(C), CTX_wm_view3d(C), ob_iter) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) {
+ BKE_lib_override_library_id_reset(bmain, &ob_iter->id, false);
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_reset_override_library(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reset Library Override";
+ ot->description = "Reset the selected local overrides to their linked references values";
+ ot->idname = "OBJECT_OT_reset_override_library";
+
+ /* api callbacks */
+ ot->exec = reset_override_library_exec;
+ ot->poll = reset_clear_override_library_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Clear Library Override Operator
+ * \{ */
+
+static int clear_override_library_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ LinkNode *todo_objects = NULL, *todo_object_iter;
+
+ /* Make already existing selected liboverrides editable. */
+ FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) {
+ if (ID_IS_LINKED(ob_iter)) {
+ continue;
+ }
+ BLI_linklist_prepend_alloca(&todo_objects, ob_iter);
+ }
+ FOREACH_SELECTED_OBJECT_END;
+
+ for (todo_object_iter = todo_objects; todo_object_iter != NULL;
+ todo_object_iter = todo_object_iter->next) {
+ Object *ob_iter = todo_object_iter->link;
+ if (BKE_lib_override_library_is_hierarchy_leaf(bmain, &ob_iter->id)) {
+ bool do_remap_active = false;
+ if (BKE_view_layer_active_object_get(view_layer) == ob_iter) {
+ do_remap_active = true;
+ }
+ BKE_libblock_remap(bmain,
+ &ob_iter->id,
+ ob_iter->id.override_library->reference,
+ ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (do_remap_active) {
+ Object *ref_object = (Object *)ob_iter->id.override_library->reference;
+ Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
+ if (basact != NULL) {
+ view_layer->basact = basact;
+ }
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ }
+ BKE_id_delete(bmain, &ob_iter->id);
+ }
+ else {
+ BKE_lib_override_library_id_reset(bmain, &ob_iter->id, true);
+ }
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_clear_override_library(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Library Override";
+ ot->description =
+ "Delete the selected local overrides and relink their usages to the linked data-blocks if "
+ "possible, else reset them and mark them as non editable";
+ ot->idname = "OBJECT_OT_clear_override_library";
+
+ /* api callbacks */
+ ot->exec = clear_override_library_exec;
+ ot->poll = reset_clear_override_library_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 71b757b66ff..09489c50e9d 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -73,6 +73,9 @@
#include "object_intern.h" /* own include */
+using blender::IndexRange;
+using blender::Span;
+
/* TODO(sebpa): unstable, can lead to unrecoverable errors. */
// #define USE_MESH_CURVATURE
@@ -128,7 +131,8 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
/* Output mesh will be all smooth or all flat shading. */
- const bool smooth_normals = mesh->mpoly[0].flag & ME_SMOOTH;
+ const Span<MPoly> polys = mesh->polys();
+ const bool smooth_normals = polys.first().flag & ME_SMOOTH;
float isovalue = 0.0f;
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
@@ -144,7 +148,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
if (ob->mode == OB_MODE_SCULPT) {
- ED_sculpt_undo_geometry_begin(ob, op->type->name);
+ ED_sculpt_undo_geometry_begin(ob, op);
}
if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) {
@@ -415,15 +419,15 @@ static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *eve
}
if (event->modifier & KM_CTRL) {
- /* Linear mode, enables jumping to any voxel size. */
- d = d * 0.0005f;
- }
- else {
/* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
* sizes. */
/* When the voxel size is slower, it needs more precision. */
d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
}
+ else {
+ /* Linear mode, enables jumping to any voxel size. */
+ d = d * 0.0005f;
+ }
if (cd->slow_mode) {
cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
}
@@ -577,10 +581,18 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
/* Use the Bounding Box face normal as the basis Z. */
normal_tri_v3(cd->text_mat[2], cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
+ /* Invert object scale. */
+ float scale[3];
+ mat4_to_size(scale, active_object->obmat);
+ invert_v3(scale);
+ size_to_mat4(scale_mat, scale);
+
+ mul_m4_m4_pre(cd->text_mat, scale_mat);
+
/* Write the text position into the matrix. */
copy_v3_v3(cd->text_mat[3], text_pos);
- /* Scale the text. */
+ /* Scale the text to constant viewport size. */
float text_pos_word_space[3];
mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos);
const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space);
@@ -592,7 +604,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_region_tag_redraw(region);
const char *status_str = TIP_(
- "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
+ "Move the mouse to change the voxel size. CTRL: Relative Scale, SHIFT: Precision Mode, "
+ "ENTER/LMB: Confirm Size, ESC/RMB: Cancel");
ED_workspace_status_text(C, status_str);
return OPERATOR_RUNNING_MODAL;
@@ -645,6 +658,7 @@ struct QuadriFlowJob {
short *stop, *do_update;
float *progress;
+ const struct wmOperator *op;
Scene *scene;
int target_faces;
int seed;
@@ -668,9 +682,11 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
* check that the direction of the faces are consistent and doesn't suddenly
* flip
*/
+ const Span<MVert> verts = mesh->verts();
+ const Span<MEdge> edges = mesh->edges();
+ const Span<MLoop> loops = mesh->loops();
bool is_manifold_consistent = true;
- const MLoop *mloop = mesh->mloop;
char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
int *edge_vert = (int *)MEM_malloc_arrayN(
mesh->totedge, sizeof(uint), "remesh_consistent_check");
@@ -679,18 +695,17 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
edge_vert[i] = -1;
}
- for (uint loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
- const MLoop *loop = &mloop[loop_idx];
- edge_faces[loop->e] += 1;
- if (edge_faces[loop->e] > 2) {
+ for (const MLoop &loop : loops) {
+ edge_faces[loop.e] += 1;
+ if (edge_faces[loop.e] > 2) {
is_manifold_consistent = false;
break;
}
- if (edge_vert[loop->e] == -1) {
- edge_vert[loop->e] = loop->v;
+ if (edge_vert[loop.e] == -1) {
+ edge_vert[loop.e] = loop.v;
}
- else if (edge_vert[loop->e] == loop->v) {
+ else if (edge_vert[loop.e] == loop.v) {
/* Mesh has flips in the surface so it is non consistent */
is_manifold_consistent = false;
break;
@@ -698,16 +713,16 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
}
if (is_manifold_consistent) {
- for (uint i = 0; i < mesh->totedge; i++) {
+ for (const int i : edges.index_range()) {
/* Check for wire edges. */
if (edge_faces[i] == 0) {
is_manifold_consistent = false;
break;
}
/* Check for zero length edges */
- MVert *v1 = &mesh->mvert[mesh->medge[i].v1];
- MVert *v2 = &mesh->mvert[mesh->medge[i].v2];
- if (compare_v3v3(v1->co, v2->co, 1e-4f)) {
+ const MVert &v1 = verts[edges[i].v1];
+ const MVert &v2 = verts[edges[i].v2];
+ if (compare_v3v3(v1.co, v2.co, 1e-4f)) {
is_manifold_consistent = false;
break;
}
@@ -882,7 +897,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
if (ob->mode == OB_MODE_SCULPT) {
- ED_sculpt_undo_geometry_begin(ob, "QuadriFlow Remesh");
+ ED_sculpt_undo_geometry_begin(ob, qj->op);
}
if (qj->preserve_paint_mask) {
@@ -940,6 +955,7 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
{
QuadriFlowJob *job = (QuadriFlowJob *)MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
+ job->op = op;
job->owner = CTX_data_active_object(C);
job->scene = CTX_data_scene(C);
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index c3d8fb9cfe5..82c39d38d74 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -120,7 +120,7 @@ void ED_object_base_activate_with_mode_exit_if_needed(bContext *C, Base *base)
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Currently we only need to be concerned with edit-mode. */
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit) {
Object *ob = base->object;
if (((ob->mode & OB_MODE_EDIT) == 0) || (obedit->type != ob->type)) {
@@ -626,7 +626,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
}
- ob = OBACT(view_layer);
+ ob = BKE_view_layer_active_object_get(view_layer);
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
@@ -777,7 +777,8 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv
return changed;
}
-static bool select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
+/* Makes parent active and de-selected BKE_view_layer_active_object_get. */
+static bool select_grouped_parent(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -785,7 +786,8 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel
bool changed = false;
if (!basact || !(basact->object->parent)) {
- return 0; /* we know OBACT is valid */
+ /* We know BKE_view_layer_active_object_get is valid. */
+ return 0;
}
baspar = BKE_view_layer_base_find(view_layer, basact->object->parent);
@@ -1021,7 +1023,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
changed = ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
}
- ob = OBACT(view_layer);
+ ob = BKE_view_layer_active_object_get(view_layer);
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
@@ -1128,7 +1130,7 @@ static int object_select_all_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
if (any_visible == false) {
- /* TODO(campbell): Looks like we could remove this,
+ /* TODO(@campbellbarton): Looks like we could remove this,
* if not comment should say why its needed. */
return OPERATOR_PASS_THROUGH;
}
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index dd7fc192dc1..4b721cb65a1 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -481,12 +481,15 @@ static int shaderfx_remove_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+ if (!fx) {
+ return OPERATOR_CANCELLED;
+ }
/* Store name temporarily for report. */
char name[MAX_NAME];
strcpy(name, fx->name);
- if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) {
+ if (!ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) {
return OPERATOR_CANCELLED;
}
@@ -671,7 +674,9 @@ static int shaderfx_copy_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
-
+ if (!fx) {
+ return OPERATOR_CANCELLED;
+ }
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
if (!nfx) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index ebcf8573ccd..0328f6a6230 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -20,6 +20,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
@@ -112,14 +114,13 @@ static bool object_shape_key_mirror(
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- MVert *mv;
int i1, i2;
float *fp1, *fp2;
float tvec[3];
ED_mesh_mirror_spatial_table_begin(ob, NULL, NULL);
- for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) {
+ for (i1 = 0; i1 < me->totvert; i1++) {
i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology);
if (i2 == i1) {
fp1 = ((float *)kb->data) + i1 * 3;
@@ -299,6 +300,10 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
bool changed = false;
if (RNA_boolean_get(op->ptr, "all")) {
+ if (RNA_boolean_get(op->ptr, "apply_mix")) {
+ float *arr = BKE_key_evaluate_object_ex(ob, NULL, NULL, 0, ob->data);
+ MEM_freeN(arr);
+ }
changed = BKE_object_shapekey_free(bmain, ob);
}
else {
@@ -315,6 +320,34 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+static bool shape_key_remove_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const bool do_all = RNA_enum_get(op->ptr, "all");
+
+ /* Only show seed for randomize action! */
+ if (STREQ(prop_id, "apply_mix") && !do_all) {
+ return false;
+ }
+ return true;
+}
+
+static char *shape_key_remove_get_description(bContext *UNUSED(C),
+ wmOperatorType *UNUSED(ot),
+ PointerRNA *ptr)
+{
+ const bool do_apply_mix = RNA_boolean_get(ptr, "apply_mix");
+
+ if (do_apply_mix) {
+ return BLI_strdup(
+ TIP_("Apply current visible shape to the object data, and delete all shape keys"));
+ }
+
+ return NULL;
+}
+
void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
{
/* identifiers */
@@ -325,12 +358,19 @@ void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
/* api callbacks */
ot->poll = shape_key_mode_exists_poll;
ot->exec = shape_key_remove_exec;
+ ot->poll_property = shape_key_remove_poll_property;
+ ot->get_description = shape_key_remove_get_description;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all shape keys");
+ RNA_def_boolean(ot->srna, "all", false, "All", "Remove all shape keys");
+ RNA_def_boolean(ot->srna,
+ "apply_mix",
+ false,
+ "Apply Mix",
+ "Apply current mix of shape keys to the geometry before removing them");
}
/** \} */
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index 82e67231ec1..e4f96d95173 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -855,7 +855,7 @@ static int apply_objects_internal(bContext *C,
/* calculate translation */
if (apply_loc) {
- copy_v3_v3(mat[3], ob->loc);
+ add_v3_v3v3(mat[3], ob->loc, ob->dloc);
if (!(apply_scale && apply_rot)) {
float tmat[3][3];
@@ -1023,14 +1023,19 @@ static int apply_objects_internal(bContext *C,
else {
if (apply_loc) {
zero_v3(ob->loc);
+ zero_v3(ob->dloc);
}
if (apply_scale) {
- ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0f;
+ copy_v3_fl(ob->scale, 1.0f);
+ copy_v3_fl(ob->dscale, 1.0f);
}
if (apply_rot) {
zero_v3(ob->rot);
+ zero_v3(ob->drot);
unit_qt(ob->quat);
+ unit_qt(ob->dquat);
unit_axis_angle(ob->rotAxis, &ob->rotAngle);
+ unit_axis_angle(ob->drotAxis, &ob->drotAngle);
}
}
@@ -1598,6 +1603,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
}
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
}
}
}
@@ -2219,7 +2225,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
bool is_finished = false;
- if (ISMOUSE(xfd->init_event)) {
+ if (ISMOUSE_BUTTON(xfd->init_event)) {
if ((event->type == xfd->init_event) && (event->val == KM_RELEASE)) {
is_finished = true;
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.cc
index 9ad36cacc7d..d2cb7ad4b43 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.cc
@@ -5,9 +5,9 @@
* \ingroup edobj
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -21,14 +21,15 @@
#include "DNA_scene_types.h"
#include "DNA_workspace_types.h"
-#include "BLI_alloca.h"
#include "BLI_array.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_utildefines_stack.h"
+#include "BLI_vector.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -66,6 +67,9 @@
#include "object_intern.h"
+using blender::MutableSpan;
+using blender::Span;
+
static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob);
/* -------------------------------------------------------------------- */
@@ -74,7 +78,7 @@ static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob);
static bool object_array_for_wpaint_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (vertex_group_supported_poll_ex(C, ob)) {
return true;
}
@@ -100,7 +104,7 @@ static bool vertex_group_use_vert_sel(Object *ob)
static Lattice *vgroup_edit_lattice(Object *ob)
{
- Lattice *lt = ob->data;
+ Lattice *lt = static_cast<Lattice *>(ob->data);
BLI_assert(ob->type == OB_LATTICE);
return (lt->editlatt) ? lt->editlatt->latt : lt;
}
@@ -115,7 +119,7 @@ bool ED_vgroup_sync_from_pose(Object *ob)
{
Object *armobj = BKE_object_pose_armature_get(ob);
if (armobj && (armobj->mode & OB_MODE_POSE)) {
- struct bArmature *arm = armobj->data;
+ bArmature *arm = static_cast<bArmature *>(armobj->data);
if (arm->act_bone) {
int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name);
if (def_num != -1) {
@@ -151,7 +155,7 @@ bool ED_vgroup_parray_alloc(ID *id,
const bool use_vert_sel)
{
*dvert_tot = 0;
- *dvert_arr = NULL;
+ *dvert_arr = nullptr;
if (id) {
switch (GS(id->name)) {
@@ -172,42 +176,45 @@ bool ED_vgroup_parray_alloc(ID *id,
i = em->bm->totvert;
- *dvert_arr = MEM_mallocN(sizeof(void *) * i, "vgroup parray from me");
+ *dvert_arr = static_cast<MDeformVert **>(MEM_mallocN(sizeof(void *) * i, __func__));
*dvert_tot = i;
i = 0;
if (use_vert_sel) {
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
(*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ?
- BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset) :
- NULL;
+ static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)) :
+ nullptr;
i++;
}
}
else {
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- (*dvert_arr)[i] = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ (*dvert_arr)[i] = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
i++;
}
}
return true;
}
- if (me->dvert) {
- MVert *mvert = me->mvert;
- MDeformVert *dvert = me->dvert;
+ if (!me->deform_verts().is_empty()) {
+ const Span<MVert> verts = me->verts();
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
*dvert_tot = me->totvert;
- *dvert_arr = MEM_mallocN(sizeof(void *) * me->totvert, "vgroup parray from me");
+ *dvert_arr = static_cast<MDeformVert **>(
+ MEM_mallocN(sizeof(void *) * me->totvert, __func__));
if (use_vert_sel) {
for (int i = 0; i < me->totvert; i++) {
- (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? &dvert[i] : NULL;
+ (*dvert_arr)[i] = (verts[i].flag & SELECT) ? &dverts[i] : nullptr;
}
}
else {
for (int i = 0; i < me->totvert; i++) {
- (*dvert_arr)[i] = me->dvert + i;
+ (*dvert_arr)[i] = &dverts[i];
}
}
@@ -222,11 +229,12 @@ bool ED_vgroup_parray_alloc(ID *id,
if (lt->dvert) {
BPoint *def = lt->def;
*dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
- *dvert_arr = MEM_mallocN(sizeof(void *) * (*dvert_tot), "vgroup parray from me");
+ *dvert_arr = static_cast<MDeformVert **>(
+ MEM_mallocN(sizeof(void *) * (*dvert_tot), __func__));
if (use_vert_sel) {
for (int i = 0; i < *dvert_tot; i++) {
- (*dvert_arr)[i] = (def->f1 & SELECT) ? &lt->dvert[i] : NULL;
+ (*dvert_arr)[i] = (def->f1 & SELECT) ? &lt->dvert[i] : nullptr;
}
}
else {
@@ -255,11 +263,12 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
const int vgroup_tot)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
- MDeformVert **dvert_array_all = NULL;
+ MDeformVert **dvert_array_all = nullptr;
int dvert_tot_all;
/* get an array of all verts, not only selected */
- if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) {
+ if (ED_vgroup_parray_alloc(
+ static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) == false) {
BLI_assert(0);
return;
}
@@ -271,10 +280,10 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
const int *flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, true);
for (int i_src = 0; i_src < dvert_tot; i_src++) {
- if (dvert_array[i_src] != NULL) {
+ if (dvert_array[i_src] != nullptr) {
/* its selected, check if its mirror exists */
int i_dst = ED_mesh_mirror_get_vert(ob, i_src);
- if (i_dst != -1 && dvert_array_all[i_dst] != NULL) {
+ if (i_dst != -1 && dvert_array_all[i_dst] != nullptr) {
/* we found a match! */
const MDeformVert *dv_src = dvert_array[i_src];
MDeformVert *dv_dst = dvert_array_all[i_dst];
@@ -294,11 +303,12 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
- MDeformVert **dvert_array_all = NULL;
+ MDeformVert **dvert_array_all = nullptr;
int dvert_tot_all;
/* get an array of all verts, not only selected */
- if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) {
+ if (ED_vgroup_parray_alloc(
+ static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) == false) {
BLI_assert(0);
return;
}
@@ -308,7 +318,7 @@ void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const
}
for (int i = 0; i < dvert_tot; i++) {
- if (dvert_array[i] == NULL) {
+ if (dvert_array[i] == nullptr) {
/* its unselected, check if its mirror is */
int i_sel = ED_mesh_mirror_get_vert(ob, i);
if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) {
@@ -357,8 +367,8 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array,
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
- MDeformVert **dvert_array_from = NULL, **dvf;
- MDeformVert **dvert_array = NULL, **dv;
+ MDeformVert **dvert_array_from = nullptr, **dvf;
+ MDeformVert **dvert_array = nullptr, **dv;
int dvert_tot_from;
int dvert_tot;
int i;
@@ -378,17 +388,18 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
/* In case we copy vgroup between two objects using same data,
* we only have to care about object side of things. */
if (ob->data != ob_from->data) {
- ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
+ ED_vgroup_parray_alloc(
+ static_cast<ID *>(ob_from->data), &dvert_array_from, &dvert_tot_from, false);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
- if ((dvert_array == NULL) && (dvert_array_from != NULL) &&
- BKE_object_defgroup_data_create(ob->data)) {
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
+ if ((dvert_array == nullptr) && (dvert_array_from != nullptr) &&
+ BKE_object_defgroup_data_create(static_cast<ID *>(ob->data))) {
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
new_vgroup = true;
}
- if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL ||
- dvert_array == NULL) {
+ if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == nullptr ||
+ dvert_array == nullptr) {
if (dvert_array) {
MEM_freeN(dvert_array);
}
@@ -413,7 +424,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
if (defbase_tot_from < defbase_tot) {
/* correct vgroup indices because the number of vgroups is being reduced. */
- int *remap = MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__);
+ blender::Array<int> remap(defbase_tot + 1);
for (i = 0; i <= defbase_tot_from; i++) {
remap[i] = i;
}
@@ -421,11 +432,10 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
remap[i] = 0; /* can't use these, so disable */
}
- BKE_object_defgroup_remap_update_users(ob, remap);
- MEM_freeN(remap);
+ BKE_object_defgroup_remap_update_users(ob, remap.data());
}
- if (dvert_array_from != NULL && dvert_array != NULL) {
+ if (dvert_array_from != nullptr && dvert_array != nullptr) {
dvf = dvert_array_from;
dv = dvert_array;
@@ -434,7 +444,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
*(*dv) = *(*dvf);
if ((*dv)->dw) {
- (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ (*dv)->dw = static_cast<MDeformWeight *>(MEM_dupallocN((*dv)->dw));
}
}
@@ -503,7 +513,7 @@ static void mesh_defvert_mirror_update_internal(Object *ob,
else {
/* Single vgroup. */
MDeformWeight *dw = BKE_defvert_ensure_index(dvert_dst,
- BKE_object_defgroup_flip_index(ob, def_nr, 1));
+ BKE_object_defgroup_flip_index(ob, def_nr, true));
if (dw) {
dw->weight = BKE_defvert_find_weight(dvert_src, def_nr);
}
@@ -513,7 +523,7 @@ static void mesh_defvert_mirror_update_internal(Object *ob,
static void ED_mesh_defvert_mirror_update_em(
Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
BMVert *eve_mirr;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@@ -521,8 +531,10 @@ static void ED_mesh_defvert_mirror_update_em(
eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology);
if (eve_mirr && eve_mirr != eve) {
- MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
+ MDeformVert *dvert_src = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
+ MDeformVert *dvert_dst = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset));
mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
}
}
@@ -530,25 +542,26 @@ static void ED_mesh_defvert_mirror_update_em(
static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
{
int vidx_mirr;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
if (vidx == -1) {
return;
}
- vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology);
+ vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology);
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
- MDeformVert *dvert_src = &me->dvert[vidx];
- MDeformVert *dvert_dst = &me->dvert[vidx_mirr];
+ MDeformVert *dvert_src = &dverts[vidx];
+ MDeformVert *dvert_dst = &dverts[vidx_mirr];
mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr);
}
}
void ED_vgroup_vert_active_mirror(Object *ob, int def_nr)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
MDeformVert *dvert_act;
@@ -584,7 +597,7 @@ static void vgroup_remove_weight(Object *ob, const int def_nr)
static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
BMVert *eve_act;
int v_act;
@@ -599,7 +612,7 @@ static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
}
- if (dvert_act == NULL) {
+ if (dvert_act == nullptr) {
return false;
}
@@ -623,7 +636,7 @@ static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type
static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
{
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
MDeformVert *dvert_act;
int i, vgroup_tot, subset_count;
@@ -639,7 +652,8 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
if (dvert_act) {
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
- MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ MDeformVert *dv = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
if (me->symmetry & ME_SYMMETRY_X) {
ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
@@ -649,15 +663,15 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
}
}
else {
- MDeformVert *dv;
+ const Span<MVert> verts = me->verts();
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
if (dvert_act) {
- dv = me->dvert;
- for (i = 0; i < me->totvert; i++, dv++) {
- if ((me->mvert[i].flag & SELECT) && dv != dvert_act) {
- BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot);
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
+ for (i = 0; i < me->totvert; i++) {
+ if ((verts[i].flag & SELECT) && &dverts[i] != dvert_act) {
+ BKE_defvert_copy_subset(&dverts[i], dvert_act, vgroup_validmap, vgroup_tot);
if (me->symmetry & ME_SYMMETRY_X) {
ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
@@ -688,20 +702,20 @@ static const EnumPropertyItem WT_vertex_group_select_item[] = {
"Deform Pose Bones",
"All Vertex Groups assigned to Deform Bones"},
{WT_VGROUP_ALL, "ALL", 0, "All Groups", "All Vertex Groups"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *C,
PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
+ PropertyRNA *prop,
bool *r_free,
const uint selection_mask)
{
Object *ob;
- EnumPropertyItem *item = NULL;
+ EnumPropertyItem *item = nullptr;
int totitem = 0;
- if (C == NULL) {
+ if (C == nullptr) {
/* needed for docs and i18n tools */
return WT_vertex_group_select_item;
}
@@ -731,6 +745,12 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *
RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ALL);
}
+ /* Set `Deform Bone` as default selection if armature is present. */
+ if (ob) {
+ RNA_def_property_enum_default(
+ prop, BKE_modifiers_is_deformed_by_armature(ob) ? WT_VGROUP_BONE_DEFORM : WT_VGROUP_ALL);
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -791,13 +811,13 @@ static void ED_vgroup_nr_vert_add(
Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode)
{
/* Add the vert to the deform group with the specified number. */
- MDeformVert *dvert = NULL;
+ MDeformVert *dvert = nullptr;
int tot;
/* Get the vert. */
- BKE_object_defgroup_array_get(ob->data, &dvert, &tot);
+ BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot);
- if (dvert == NULL) {
+ if (dvert == nullptr) {
return;
}
@@ -859,7 +879,7 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
const ListBase *defbase = BKE_object_defgroup_list(ob);
const int def_nr = BLI_findindex(defbase, dg);
- MDeformVert *dv = NULL;
+ MDeformVert *dv = nullptr;
int tot;
/* get the deform group number, exit if
@@ -869,8 +889,8 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
/* if there's no deform verts then create some,
*/
- if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL) {
- BKE_object_defgroup_data_create(ob->data);
+ if (BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dv, &tot) && dv == nullptr) {
+ BKE_object_defgroup_data_create(static_cast<ID *>(ob->data));
}
/* call another function to do the work
@@ -885,37 +905,37 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
* deform group.
*/
- /* TODO(campbell): This is slow in a loop, better pass def_nr directly,
+ /* TODO(@campbellbarton): This is slow in a loop, better pass def_nr directly,
* but leave for later. */
const ListBase *defbase = BKE_object_defgroup_list(ob);
const int def_nr = BLI_findindex(defbase, dg);
if (def_nr != -1) {
- MDeformVert *dvert = NULL;
+ MDeformVert *dvert = nullptr;
int tot;
/* get the deform vertices corresponding to the
* vertnum
*/
- BKE_object_defgroup_array_get(ob->data, &dvert, &tot);
+ BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot);
if (dvert) {
MDeformVert *dv = &dvert[vertnum];
MDeformWeight *dw;
dw = BKE_defvert_find_index(dv, def_nr);
- BKE_defvert_remove_group(dv, dw); /* dw can be NULL */
+ BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
}
}
}
static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
{
- MDeformVert *dv = NULL;
+ const MDeformVert *dv = nullptr;
/* get the deform vertices corresponding to the vertnum */
if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (me->edit_mesh) {
BMEditMesh *em = me->edit_mesh;
@@ -926,18 +946,19 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
BMVert *eve;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
eve = BM_vert_at_index(em->bm, vertnum);
- dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ dv = static_cast<const MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
}
else {
return 0.0f;
}
}
else {
- if (me->dvert) {
+ const Span<MDeformVert> dverts = me->deform_verts();
+ if (!dverts.is_empty()) {
if (vertnum >= me->totvert) {
return 0.0f;
}
- dv = &me->dvert[vertnum];
+ dv = &dverts[vertnum];
}
}
}
@@ -998,7 +1019,7 @@ static void vgroup_select_verts(Object *ob, int select)
}
if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (me->edit_mesh) {
BMEditMesh *em = me->edit_mesh;
@@ -1010,7 +1031,8 @@ static void vgroup_select_verts(Object *ob, int select)
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ MDeformVert *dv = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
if (BKE_defvert_find_index(dv, def_nr)) {
BM_vert_select_set(em->bm, eve, select);
}
@@ -1027,17 +1049,18 @@ static void vgroup_select_verts(Object *ob, int select)
}
}
else {
- if (me->dvert) {
+ const Span<MDeformVert> dverts = me->deform_verts();
+ if (!dverts.is_empty()) {
+ const bool *hide_vert = (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".hide_vert");
MVert *mv;
- MDeformVert *dv;
int i;
- mv = me->mvert;
- dv = me->dvert;
+ mv = me->verts_for_write().data();
- for (i = 0; i < me->totvert; i++, mv++, dv++) {
- if (!(mv->flag & ME_HIDE)) {
- if (BKE_defvert_find_index(dv, def_nr)) {
+ for (i = 0; i < me->totvert; i++, mv++) {
+ if (!(hide_vert != nullptr && hide_vert[i])) {
+ if (BKE_defvert_find_index(&dverts[i], def_nr)) {
if (select) {
mv->flag |= SELECT;
}
@@ -1085,12 +1108,13 @@ static void vgroup_duplicate(Object *ob)
bDeformGroup *dg, *cdg;
char name[sizeof(dg->name)];
MDeformWeight *dw_org, *dw_cpy;
- MDeformVert **dvert_array = NULL;
+ MDeformVert **dvert_array = nullptr;
int i, idg, icdg, dvert_tot = 0;
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
- dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
+ dg = static_cast<bDeformGroup *>(
+ BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1));
if (!dg) {
return;
}
@@ -1112,8 +1136,8 @@ static void vgroup_duplicate(Object *ob)
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);
+ /* TODO(@campbellbarton): we might want to allow only copy selected verts here? */
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
if (dvert_array) {
for (i = 0; i < dvert_tot; i++) {
@@ -1134,7 +1158,7 @@ static void vgroup_duplicate(Object *ob)
static bool vgroup_normalize(Object *ob)
{
MDeformWeight *dw;
- MDeformVert *dv, **dvert_array = NULL;
+ MDeformVert *dv, **dvert_array = nullptr;
int dvert_tot = 0;
const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
@@ -1145,7 +1169,7 @@ static bool vgroup_normalize(Object *ob)
return false;
}
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
float weight_max = 0.0f;
@@ -1192,21 +1216,18 @@ static bool vgroup_normalize(Object *ob)
/* This finds all of the vertices face-connected to vert by an edge and returns a
* MEM_allocated array of indices of size count.
* count is an int passed by reference so it can be assigned the value of the length here. */
-static int *getSurroundingVerts(Mesh *me, int vert, int *count)
+static blender::Vector<int> getSurroundingVerts(Mesh *me, int vert)
{
- MPoly *mp = me->mpoly;
+ const MPoly *mp = me->polys().data();
+ const MLoop *loops = me->loops().data();
int i = me->totpoly;
- /* Instead of looping twice on all polys and loops, and use a temp array, let's rather
- * use a BLI_array, with a reasonable starting/reserved size (typically, there are not
- * many vertices face-linked to another one, even 8 might be too high...). */
- int *verts = NULL;
- BLI_array_declare(verts);
- BLI_array_reserve(verts, 8);
+ blender::Vector<int> verts;
+
while (i--) {
int j = mp->totloop;
int first_l = mp->totloop - 1;
- MLoop *ml = &me->mloop[mp->loopstart];
+ const MLoop *ml = &loops[mp->loopstart];
while (j--) {
/* XXX This assume a vert can only be once in a poly, even though
* it seems logical to me, not totally sure of that. */
@@ -1220,7 +1241,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
else if (!j) {
/* We are on the last corner. */
a = (ml - 1)->v;
- b = me->mloop[mp->loopstart].v;
+ b = loops[mp->loopstart].v;
}
else {
a = (ml - 1)->v;
@@ -1228,7 +1249,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
}
/* Append a and b verts to array, if not yet present. */
- k = BLI_array_len(verts);
+ k = verts.size();
/* XXX Maybe a == b is enough? */
while (k-- && !(a == b && a == -1)) {
if (verts[k] == a) {
@@ -1239,10 +1260,10 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
}
}
if (a != -1) {
- BLI_array_append(verts, a);
+ verts.append(a);
}
if (b != -1) {
- BLI_array_append(verts, b);
+ verts.append(b);
}
/* Vert found in this poly, we can go to next one! */
@@ -1253,8 +1274,6 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
mp++;
}
- /* Do not free the array! */
- *count = BLI_array_len(verts);
return verts;
}
@@ -1305,14 +1324,15 @@ static void getVerticalAndHorizontalChange(const float norm[3],
changes[index][1] = len_v3v3(projA, projB);
}
-/* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to
- * distToBe distance away from the provided plane strength can change distToBe so that it moves
- * towards distToBe by that percentage cp changes how much the weights are adjusted
+/**
+ * By changing nonzero weights, try to move a vertex in `me->mverts` with index 'index' to
+ * `distToBe` distance away from the provided plane strength can change `distToBe` so that it moves
+ * towards `distToBe` by that percentage `cp` changes how much the weights are adjusted
* to check the distance
*
- * index is the index of the vertex being moved
- * norm and d are the plane's properties for the equation: ax + by + cz + d = 0
- * coord is a point on the plane
+ * `index` is the index of the vertex being moved.
+ * `norm` and `d` are the plane's properties for the equation: `ax + by + cz + d = 0`.
+ * `coord` is a point on the plane.
*/
static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
Scene *UNUSED(scene),
@@ -1333,20 +1353,21 @@ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
Mesh *me_deform;
MDeformWeight *dw, *dw_eval;
MVert m;
- MDeformVert *dvert = me->dvert + index;
- MDeformVert *dvert_eval = mesh_eval->dvert + index;
+ MDeformVert *dvert = me->deform_verts_for_write().data() + index;
+ MDeformVert *dvert_eval = mesh_eval->deform_verts_for_write().data() + index;
int totweight = dvert->totweight;
float oldw = 0;
float oldPos[3] = {0};
float vc, hc, dist = 0.0f;
int i, k;
- float(*changes)[2] = MEM_mallocN(sizeof(float[2]) * totweight, "vertHorzChange");
- float *dists = MEM_mallocN(sizeof(float) * totweight, "distance");
+ float(*changes)[2] = static_cast<float(*)[2]>(
+ MEM_mallocN(sizeof(float[2]) * totweight, "vertHorzChange"));
+ float *dists = static_cast<float *>(MEM_mallocN(sizeof(float) * totweight, "distance"));
/* track if up or down moved it closer for each bone */
- bool *upDown = MEM_callocN(sizeof(bool) * totweight, "upDownTracker");
+ bool *upDown = static_cast<bool *>(MEM_callocN(sizeof(bool) * totweight, "upDownTracker"));
- int *dwIndices = MEM_callocN(sizeof(int) * totweight, "dwIndexTracker");
+ int *dwIndices = static_cast<int *>(MEM_callocN(sizeof(int) * totweight, "dwIndexTracker"));
float distToStart;
int bestIndex = 0;
bool wasChange;
@@ -1356,7 +1377,8 @@ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
do {
wasChange = false;
me_deform = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
- m = me_deform->mvert[index];
+ const Span<MVert> verts = me_deform->verts();
+ m = verts[index];
copy_v3_v3(oldPos, m.co);
distToStart = dot_v3v3(norm, oldPos) + d;
@@ -1398,7 +1420,7 @@ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
}
dw_eval->weight = dw->weight;
me_deform = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
- m = me_deform->mvert[index];
+ m = verts[index];
getVerticalAndHorizontalChange(
norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
dw->weight = oldw;
@@ -1502,25 +1524,26 @@ static void vgroup_fix(
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
int i;
- Mesh *me = ob->data;
- MVert *mvert = me->mvert;
- int *verts = NULL;
+ Mesh *me = static_cast<Mesh *>(ob->data);
+ MVert *mvert = me->verts_for_write().data();
if (!(me->editflag & ME_EDIT_PAINT_VERT_SEL)) {
return;
}
for (i = 0; i < me->totvert && mvert; i++, mvert++) {
if (mvert->flag & SELECT) {
- int count = 0;
- if ((verts = getSurroundingVerts(me, i, &count))) {
+ blender::Vector<int> verts = getSurroundingVerts(me, i);
+ const int count = verts.size();
+ if (!verts.is_empty()) {
MVert m;
- MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints");
+ MVert *p = static_cast<MVert *>(MEM_callocN(sizeof(MVert) * (count), "deformedPoints"));
int k;
Mesh *me_deform = mesh_get_eval_deform(
depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
+ const Span<MVert> verts_deform = me_deform->verts();
k = count;
while (k--) {
- p[k] = me_deform->mvert[verts[k]];
+ p[k] = verts_deform[verts[k]];
}
if (count >= 3) {
@@ -1528,7 +1551,7 @@ static void vgroup_fix(
float coord[3];
float norm[3];
getSingleCoordinate(p, count, coord);
- m = me_deform->mvert[i];
+ m = verts_deform[i];
sub_v3_v3v3(norm, m.co, coord);
mag = normalize_v3(norm);
if (mag) { /* zeros fix */
@@ -1539,7 +1562,6 @@ static void vgroup_fix(
}
}
- MEM_freeN(verts);
MEM_freeN(p);
}
}
@@ -1554,7 +1576,7 @@ static void vgroup_levels_subset(Object *ob,
const float gain)
{
MDeformWeight *dw;
- MDeformVert *dv, **dvert_array = NULL;
+ MDeformVert *dv, **dvert_array = nullptr;
int dvert_tot = 0;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
@@ -1562,7 +1584,7 @@ static void vgroup_levels_subset(Object *ob,
(((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
false;
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
@@ -1600,7 +1622,7 @@ static bool vgroup_normalize_all(Object *ob,
const bool lock_active,
ReportList *reports)
{
- MDeformVert *dv, **dvert_array = NULL;
+ MDeformVert *dv, **dvert_array = nullptr;
int i, dvert_tot = 0;
const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
@@ -1611,7 +1633,7 @@ static bool vgroup_normalize_all(Object *ob,
return false;
}
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -1619,7 +1641,7 @@ static bool vgroup_normalize_all(Object *ob,
bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
bool changed = false;
- if ((lock_active == true) && (lock_flags != NULL) && (def_nr < defbase_tot)) {
+ if ((lock_active == true) && (lock_flags != nullptr) && (def_nr < defbase_tot)) {
lock_flags[def_nr] = true;
}
@@ -1682,7 +1704,7 @@ static const EnumPropertyItem vgroup_lock_actions[] = {
{VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"},
{VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"},
{VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
enum {
@@ -1701,7 +1723,7 @@ static const EnumPropertyItem vgroup_lock_mask[] = {
0,
"Invert Unselected",
"Apply the opposite of Lock/Unlock to unselected vertex groups"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool *vgroup_selected_get(Object *ob)
@@ -1720,7 +1742,7 @@ static bool *vgroup_selected_get(Object *ob)
}
}
else {
- mask = MEM_callocN(defbase_tot * sizeof(bool), __func__);
+ mask = static_cast<bool *>(MEM_callocN(defbase_tot * sizeof(bool), __func__));
}
const int actdef = BKE_object_defgroup_active_index_get(ob);
@@ -1734,7 +1756,7 @@ static bool *vgroup_selected_get(Object *ob)
static void vgroup_lock_all(Object *ob, int action, int mask)
{
bDeformGroup *dg;
- bool *selected = NULL;
+ bool *selected = nullptr;
int i;
if (mask != VGROUP_MASK_ALL) {
@@ -1745,7 +1767,7 @@ static void vgroup_lock_all(Object *ob, int action, int mask)
if (action == VGROUP_TOGGLE) {
action = VGROUP_LOCK;
- for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
+ for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
switch (mask) {
case VGROUP_MASK_INVERT_UNSELECTED:
case VGROUP_MASK_SELECTED:
@@ -1758,7 +1780,8 @@ static void vgroup_lock_all(Object *ob, int action, int mask)
continue;
}
break;
- default:;
+ default:
+ break;
}
if (dg->flag & DG_LOCK_WEIGHT) {
@@ -1768,7 +1791,7 @@ static void vgroup_lock_all(Object *ob, int action, int mask)
}
}
- for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
+ for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
switch (mask) {
case VGROUP_MASK_SELECTED:
if (!selected[i]) {
@@ -1780,7 +1803,8 @@ static void vgroup_lock_all(Object *ob, int action, int mask)
continue;
}
break;
- default:;
+ default:
+ break;
}
switch (action) {
@@ -1813,14 +1837,14 @@ static void vgroup_invert_subset(Object *ob,
const bool auto_remove)
{
MDeformWeight *dw;
- MDeformVert *dv, **dvert_array = NULL;
+ MDeformVert *dv, **dvert_array = nullptr;
int dvert_tot = 0;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
const bool use_mirror = (ob->type == OB_MESH) ?
(((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
false;
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
for (int i = 0; i < dvert_tot; i++) {
@@ -1870,10 +1894,10 @@ static void vgroup_smooth_subset(Object *ob,
const float fac_expand)
{
const float ifac = 1.0f - fac;
- MDeformVert **dvert_array = NULL;
+ MDeformVert **dvert_array = nullptr;
int dvert_tot = 0;
- int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count);
- float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count);
+ blender::Array<int, 32> vgroup_subset_map(subset_count);
+ blender::Array<float, 32> vgroup_subset_weights(subset_count);
const bool use_mirror = (ob->type == OB_MESH) ?
(((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
false;
@@ -1885,8 +1909,8 @@ static void vgroup_smooth_subset(Object *ob,
const float iexpand = 1.0f - expand;
BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMesh *bm = em ? em->bm : NULL;
- Mesh *me = em ? NULL : ob->data;
+ BMesh *bm = em ? em->bm : nullptr;
+ Mesh *me = em ? nullptr : static_cast<Mesh *>(ob->data);
MeshElemMap *emap;
int *emap_mem;
@@ -1900,31 +1924,37 @@ static void vgroup_smooth_subset(Object *ob,
uint *verts_used;
STACK_DECLARE(verts_used);
- BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map);
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
- memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count);
+ BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map.data());
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false);
+ vgroup_subset_weights.fill(0.0f);
if (bm) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
BM_mesh_elem_index_ensure(bm, BM_VERT);
- emap = NULL;
- emap_mem = NULL;
+ emap = nullptr;
+ emap_mem = nullptr;
}
else {
- BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
+ BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->edges().data(), me->totvert, me->totedge);
}
- weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__);
- weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__);
+ weight_accum_prev = static_cast<float *>(
+ MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__));
+ weight_accum_curr = static_cast<float *>(
+ MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__));
- verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__);
+ verts_used = static_cast<uint *>(MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__));
STACK_INIT(verts_used, dvert_tot);
#define IS_BM_VERT_READ(v) (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true)
#define IS_BM_VERT_WRITE(v) (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true)
-#define IS_ME_VERT_READ(v) (use_hide ? (((v)->flag & ME_HIDE) == 0) : true)
+ const bool *hide_vert = me ? (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".hide_vert") :
+ nullptr;
+
+#define IS_ME_VERT_READ(v) (use_hide ? !(hide_vert && hide_vert[v]) : true)
#define IS_ME_VERT_WRITE(v) (use_select ? (((v)->flag & SELECT) != 0) : true)
/* initialize used verts */
@@ -1945,13 +1975,15 @@ static void vgroup_smooth_subset(Object *ob,
}
}
else {
+ const Span<MVert> verts = me->verts();
+ const blender::Span<MEdge> edges = me->edges();
for (int i = 0; i < dvert_tot; i++) {
- const MVert *v = &me->mvert[i];
+ const MVert *v = &verts[i];
if (IS_ME_VERT_WRITE(v)) {
for (int j = 0; j < emap[i].count; j++) {
- const MEdge *e = &me->medge[emap[i].indices[j]];
- const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1];
- if (IS_ME_VERT_READ(v_other)) {
+ const MEdge *e = &edges[emap[i].indices[j]];
+ const int i_other = (e->v1 == i) ? e->v2 : e->v1;
+ if (IS_ME_VERT_READ(i_other)) {
STACK_PUSH(verts_used, i);
break;
}
@@ -2018,16 +2050,15 @@ static void vgroup_smooth_subset(Object *ob,
}
else {
int j;
+ const blender::Span<MEdge> edges = me->edges();
/* checked already */
- BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i]));
+ BLI_assert(IS_ME_VERT_WRITE(&me->verts()[i]));
for (j = 0; j < emap[i].count; j++) {
- MEdge *e = &me->medge[emap[i].indices[j]];
+ const MEdge *e = &edges[emap[i].indices[j]];
const int i_other = (e->v1 == i ? e->v2 : e->v1);
- MVert *v_other = &me->mvert[i_other];
-
- if (IS_ME_VERT_READ(v_other)) {
+ if (IS_ME_VERT_READ(i_other)) {
WEIGHT_ACCUMULATE;
}
}
@@ -2072,9 +2103,9 @@ static void vgroup_smooth_subset(Object *ob,
MEM_freeN(dvert_array);
}
- /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */
+ /* not so efficient to get 'dvert_array' again just so unselected verts are nullptr'd */
if (use_mirror) {
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, true);
ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot);
if (dvert_array) {
MEM_freeN(dvert_array);
@@ -2090,7 +2121,8 @@ static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
* less than, equal to, or greater than zero corresponding to whether its first argument is
* considered less than, equal to, or greater than its second argument.
* This does the opposite. */
- const struct MDeformWeight *dw1 = a1, *dw2 = a2;
+ const MDeformWeight *dw1 = static_cast<const MDeformWeight *>(a1);
+ const MDeformWeight *dw2 = static_cast<const MDeformWeight *>(a2);
if (dw1->weight < dw2->weight) {
return 1;
@@ -2114,12 +2146,12 @@ static int vgroup_limit_total_subset(Object *ob,
const int subset_count,
const int max_weights)
{
- MDeformVert *dv, **dvert_array = NULL;
+ MDeformVert *dv, **dvert_array = nullptr;
int i, dvert_tot = 0;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
int remove_tot = 0;
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
int num_to_drop = 0;
@@ -2141,7 +2173,8 @@ static int vgroup_limit_total_subset(Object *ob,
if (num_to_drop > 0) {
/* re-pack dw array so that non-bone weights are first, bone-weighted verts at end
* sort the tail, then copy only the truncated array back to dv->dw */
- dw_temp = MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__);
+ dw_temp = static_cast<MDeformWeight *>(
+ MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__));
bone_count = 0;
non_bone_count = 0;
for (j = 0; j < dv->totweight; j++) {
@@ -2164,7 +2197,8 @@ static int vgroup_limit_total_subset(Object *ob,
dv->totweight -= num_to_drop;
/* Do we want to clean/normalize here? */
MEM_freeN(dv->dw);
- dv->dw = MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight);
+ dv->dw = static_cast<MDeformWeight *>(
+ MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight));
remove_tot += num_to_drop;
}
else {
@@ -2185,14 +2219,14 @@ static void vgroup_clean_subset(Object *ob,
const float epsilon,
const bool keep_single)
{
- MDeformVert **dvert_array = NULL;
+ MDeformVert **dvert_array = nullptr;
int dvert_tot = 0;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
const bool use_mirror = (ob->type == OB_MESH) ?
(((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
false;
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
if (use_mirror && use_vert_sel) {
@@ -2215,13 +2249,13 @@ static void vgroup_quantize_subset(Object *ob,
const int UNUSED(subset_count),
const int steps)
{
- MDeformVert **dvert_array = NULL;
+ MDeformVert **dvert_array = nullptr;
int dvert_tot = 0;
const bool use_vert_sel = vertex_group_use_vert_sel(ob);
const bool use_mirror = (ob->type == OB_MESH) ?
(((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 :
false;
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+ ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
const float steps_fl = steps;
@@ -2342,9 +2376,9 @@ void ED_vgroup_mirror(Object *ob,
def_nr)
BMVert *eve, *eve_mirr;
- MDeformVert *dvert, *dvert_mirr;
+ MDeformVert *dvert_mirr;
char sel, sel_mirr;
- int *flip_map = NULL, flip_map_len;
+ int *flip_map = nullptr, flip_map_len;
const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
int totmirr = 0, totfail = 0;
@@ -2353,7 +2387,7 @@ void ED_vgroup_mirror(Object *ob,
const ListBase *defbase = BKE_object_defgroup_list(ob);
if ((mirror_weights == false && flip_vgroups == false) ||
- (BLI_findlink(defbase, def_nr) == NULL)) {
+ (BLI_findlink(defbase, def_nr) == nullptr)) {
return;
}
@@ -2361,21 +2395,21 @@ void ED_vgroup_mirror(Object *ob,
flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, &flip_map_len, false) :
BKE_object_defgroup_flip_map_single(ob, &flip_map_len, false, def_nr);
- BLI_assert(flip_map != NULL);
+ BLI_assert(flip_map != nullptr);
- if (flip_map == NULL) {
+ if (flip_map == nullptr) {
/* something went wrong!, possibly no groups */
return;
}
}
else {
- flip_map = NULL;
+ flip_map = nullptr;
flip_map_len = 0;
}
/* only the active group */
if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
if (em) {
@@ -2400,8 +2434,10 @@ void ED_vgroup_mirror(Object *ob,
sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
if ((sel || sel_mirr) && (eve != eve_mirr)) {
- dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset);
+ MDeformVert *dvert = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
+ dvert_mirr = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset));
VGROUP_MIRR_OP;
totmirr++;
@@ -2422,11 +2458,11 @@ void ED_vgroup_mirror(Object *ob,
}
else {
/* object mode / weight paint */
- MVert *mv, *mv_mirr;
+ const MVert *mv, *mv_mirr;
int vidx, vidx_mirr;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- if (me->dvert == NULL) {
+ if (me->deform_verts().is_empty()) {
goto cleanup;
}
@@ -2435,12 +2471,14 @@ void ED_vgroup_mirror(Object *ob,
}
BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__);
+ const MVert *verts = me->verts().data();
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
- for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) {
+ for (vidx = 0, mv = verts; vidx < me->totvert; vidx++, mv++) {
if (!BLI_BITMAP_TEST(vert_tag, vidx)) {
- if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) {
+ if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) {
if (vidx != vidx_mirr) {
- mv_mirr = &me->mvert[vidx_mirr];
+ mv_mirr = &verts[vidx_mirr];
if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) {
if (use_vert_sel) {
@@ -2449,8 +2487,8 @@ void ED_vgroup_mirror(Object *ob,
}
if (sel || sel_mirr) {
- dvert = &me->dvert[vidx];
- dvert_mirr = &me->dvert[vidx_mirr];
+ MDeformVert *dvert = &dverts[vidx];
+ dvert_mirr = &dvert[vidx_mirr];
VGROUP_MIRR_OP;
totmirr++;
@@ -2477,7 +2515,7 @@ void ED_vgroup_mirror(Object *ob,
int pntsu_half;
/* half but found up odd value */
- if (lt->pntsu == 1 || lt->dvert == NULL) {
+ if (lt->pntsu == 1 || lt->dvert == nullptr) {
goto cleanup;
}
@@ -2503,7 +2541,7 @@ void ED_vgroup_mirror(Object *ob,
sel_mirr = bp_mirr->f1 & SELECT;
if (sel || sel_mirr) {
- dvert = &lt->dvert[i1];
+ MDeformVert *dvert = &lt->dvert[i1];
dvert_mirr = &lt->dvert[i2];
VGROUP_MIRR_OP;
@@ -2537,7 +2575,8 @@ cleanup:
static void vgroup_delete_active(Object *ob)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
- bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
+ bDeformGroup *dg = static_cast<bDeformGroup *>(
+ BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1));
if (!dg) {
return;
}
@@ -2556,7 +2595,7 @@ static void vgroup_assign_verts(Object *ob, const float weight)
}
if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (me->edit_mesh) {
BMEditMesh *em = me->edit_mesh;
@@ -2576,7 +2615,8 @@ static void vgroup_assign_verts(Object *ob, const float weight)
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
MDeformVert *dv;
MDeformWeight *dw;
- dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); /* can be NULL */
+ dv = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); /* can be nullptr */
dw = BKE_defvert_ensure_index(dv, def_nr);
if (dw) {
dw->weight = weight;
@@ -2585,14 +2625,12 @@ static void vgroup_assign_verts(Object *ob, const float weight)
}
}
else {
- if (!me->dvert) {
- BKE_object_defgroup_data_create(&me->id);
- }
-
- MVert *mv = me->mvert;
- MDeformVert *dv = me->dvert;
+ const Span<MVert> verts = me->verts();
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
+ MDeformVert *dv = dverts.data();
- for (int i = 0; i < me->totvert; i++, mv++, dv++) {
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ const MVert *mv = &verts[i];
if (mv->flag & SELECT) {
MDeformWeight *dw;
dw = BKE_defvert_ensure_index(dv, def_nr);
@@ -2609,7 +2647,7 @@ static void vgroup_assign_verts(Object *ob, const float weight)
BPoint *bp;
int a, tot;
- if (lt->dvert == NULL) {
+ if (lt->dvert == nullptr) {
BKE_object_defgroup_data_create(&lt->id);
}
@@ -2648,8 +2686,8 @@ static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob)
}
/* Data checks. */
- const ID *data = ob->data;
- if (data == NULL || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) {
+ const ID *data = static_cast<const ID *>(ob->data);
+ if (data == nullptr || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) {
CTX_wm_operator_poll_msg_set(C, "Object type \"%s\" does not have editable data");
return false;
}
@@ -2705,8 +2743,8 @@ static bool vertex_group_mesh_with_dvert_poll(bContext *C)
return false;
}
- Mesh *me = ob->data;
- if (me->dvert == NULL) {
+ Mesh *me = static_cast<Mesh *>(ob->data);
+ if (me->deform_verts().is_empty()) {
CTX_wm_operator_poll_msg_set(C, "The active mesh object has no vertex group data");
return false;
}
@@ -2796,7 +2834,7 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C)
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);
+ const bDeformGroup *dg = static_cast<const bDeformGroup *>(BLI_findlink(defbase, def_nr - 1));
if (dg) {
return !(dg->flag & DG_LOCK_WEIGHT);
}
@@ -2900,10 +2938,10 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
/* properties */
- PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups");
+ PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", false, "All", "Remove all vertex groups");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
- ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups");
+ ot->srna, "all_unlocked", false, "All Unlocked", "Remove all unlocked vertex groups");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -2998,8 +3036,9 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
}
else {
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)) {
+ bDeformGroup *dg = static_cast<bDeformGroup *>(
+ BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1));
+ if ((dg == nullptr) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) {
return OPERATOR_CANCELLED;
}
}
@@ -3029,9 +3068,11 @@ void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
/* properties */
- prop = RNA_def_boolean(ot->srna, "use_all_groups", 0, "All Groups", "Remove from all groups");
+ prop = RNA_def_boolean(
+ ot->srna, "use_all_groups", false, "All Groups", "Remove from all groups");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "use_all_verts", 0, "All Vertices", "Clear the active group");
+ prop = RNA_def_boolean(
+ ot->srna, "use_all_verts", false, "All Vertices", "Clear the active group");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -3050,7 +3091,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
}
vgroup_select_verts(ob, 1);
- DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
return OPERATOR_FINISHED;
@@ -3082,7 +3123,7 @@ static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_context(C);
vgroup_select_verts(ob, 0);
- DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
return OPERATOR_FINISHED;
@@ -3149,7 +3190,8 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op)
float offset = RNA_float_get(op->ptr, "offset");
float gain = RNA_float_get(op->ptr, "gain");
- eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
int subset_count, vgroup_tot;
@@ -3236,7 +3278,8 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
- eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
bool changed;
int subset_count, vgroup_tot;
const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
@@ -3296,7 +3339,7 @@ static int vertex_group_fix_exec(bContext *C, wmOperator *op)
float distToBe = RNA_float_get(op->ptr, "dist");
float strength = RNA_float_get(op->ptr, "strength");
float cp = RNA_float_get(op->ptr, "accuracy");
- ModifierData *md = ob->modifiers.first;
+ ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first);
while (md) {
if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
@@ -3385,9 +3428,9 @@ static int vertex_group_lock_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static char *vertex_group_lock_description(struct bContext *UNUSED(C),
- struct wmOperatorType *UNUSED(op),
- struct PointerRNA *params)
+static char *vertex_group_lock_description(bContext *UNUSED(C),
+ wmOperatorType *UNUSED(op),
+ PointerRNA *params)
{
int action = RNA_enum_get(params, "action");
int mask = RNA_enum_get(params, "mask");
@@ -3408,7 +3451,7 @@ static char *vertex_group_lock_description(struct bContext *UNUSED(C),
action_str = TIP_("Invert locks of");
break;
default:
- return NULL;
+ return nullptr;
}
switch (mask) {
@@ -3437,7 +3480,7 @@ static char *vertex_group_lock_description(struct bContext *UNUSED(C),
}
break;
default:
- return NULL;
+ return nullptr;
}
return BLI_sprintfN(TIP_("%s %s vertex groups of the active object"), action_str, target_str);
@@ -3485,7 +3528,8 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op)
bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign");
bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove");
- eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
int subset_count, vgroup_tot;
@@ -3538,7 +3582,8 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
{
const float fac = RNA_float_get(op->ptr, "factor");
const int repeat = RNA_int_get(op->ptr, "repeat");
- const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
const float fac_expand = RNA_float_get(op->ptr, "expand");
uint objects_len;
@@ -3603,7 +3648,8 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op)
{
const float limit = RNA_float_get(op->ptr, "limit");
const bool keep_single = RNA_boolean_get(op->ptr, "keep_single");
- const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
uint objects_len;
Object **objects = object_array_for_wpaint(C, &objects_len);
@@ -3670,7 +3716,8 @@ static int vertex_group_quantize_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
const int steps = RNA_int_get(op->ptr, "steps");
- eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
int subset_count, vgroup_tot;
@@ -3713,7 +3760,8 @@ void OBJECT_OT_vertex_group_quantize(wmOperatorType *ot)
static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
{
const int limit = RNA_int_get(op->ptr, "limit");
- const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ const eVGroupSelect subset_type = static_cast<eVGroupSelect>(
+ RNA_enum_get(op->ptr, "group_select_mode"));
int remove_multi_count = 0;
uint objects_len;
@@ -3824,7 +3872,7 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
RNA_def_boolean(
ot->srna,
"use_topology",
- 0,
+ false,
"Topology Mirror",
"Use topology based mirroring (for when both sides of mesh have matching, unique topology)");
}
@@ -3908,13 +3956,13 @@ static const EnumPropertyItem *vgroup_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_NULL_items;
}
Object *ob = ED_object_context(C);
EnumPropertyItem tmp = {0, "", 0, "", ""};
- EnumPropertyItem *item = NULL;
+ EnumPropertyItem *item = nullptr;
bDeformGroup *def;
int a, totitem = 0;
@@ -3923,7 +3971,7 @@ static const EnumPropertyItem *vgroup_itemf(bContext *C,
}
const ListBase *defbase = BKE_object_defgroup_list(ob);
- for (a = 0, def = defbase->first; def; def = def->next, a++) {
+ for (a = 0, def = static_cast<bDeformGroup *>(defbase->first); def; def = def->next, a++) {
tmp.value = a;
tmp.icon = ICON_GROUP_VERTEX;
tmp.identifier = def->name;
@@ -3974,11 +4022,13 @@ static char *vgroup_init_remap(Object *ob)
{
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_array = static_cast<char *>(
+ MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"));
char *name;
name = name_array;
- for (const bDeformGroup *def = defbase->first; def; def = def->next) {
+ for (const bDeformGroup *def = static_cast<const bDeformGroup *>(defbase->first); def;
+ def = def->next) {
BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
name += MAX_VGROUP_NAME;
}
@@ -3988,20 +4038,21 @@ static char *vgroup_init_remap(Object *ob)
static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
{
- MDeformVert *dvert = NULL;
+ MDeformVert *dvert = nullptr;
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");
+ int *sort_map_update = static_cast<int *>(
+ MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__));
int *sort_map = sort_map_update + 1;
const char *name;
int i;
name = name_array;
- for (def = defbase->first, i = 0; def; def = def->next, i++) {
+ for (def = static_cast<const bDeformGroup *>(defbase->first), i = 0; def; def = def->next, i++) {
sort_map[i] = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
name += MAX_VGROUP_NAME;
@@ -4018,7 +4069,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
BMVert *eve;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ dvert = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
if (dvert->totweight) {
BKE_defvert_remap(dvert, sort_map, defbase_tot);
}
@@ -4036,7 +4087,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
/* Grease pencil stores vertex groups separately for each stroke,
* so remap each stroke's weights separately. */
if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
+ bGPdata *gpd = static_cast<bGPdata *>(ob->data);
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
@@ -4055,7 +4106,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
}
}
else {
- BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot);
+ BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &dvert_tot);
/* Create as necessary. */
if (dvert) {
@@ -4088,8 +4139,8 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
{
- const bDeformGroup *def_a = def_a_ptr;
- const bDeformGroup *def_b = def_b_ptr;
+ const bDeformGroup *def_a = static_cast<const bDeformGroup *>(def_a_ptr);
+ const bDeformGroup *def_b = static_cast<const bDeformGroup *>(def_b_ptr);
return BLI_strcasecmp_natural(def_a->name, def_b->name);
}
@@ -4100,22 +4151,22 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
*/
static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
{
- if (bonebase == NULL) {
+ if (bonebase == nullptr) {
Object *armobj = BKE_modifiers_is_deformed_by_armature(ob);
- if (armobj != NULL) {
- bArmature *armature = armobj->data;
+ if (armobj != nullptr) {
+ bArmature *armature = static_cast<bArmature *>(armobj->data);
bonebase = &armature->bonebase;
}
}
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
- if (bonebase != NULL) {
+ if (bonebase != nullptr) {
Bone *bone;
- for (bone = bonebase->last; bone; bone = bone->prev) {
+ for (bone = static_cast<Bone *>(bonebase->last); bone; bone = bone->prev) {
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, bone->name);
vgroup_sort_bone_hierarchy(ob, &bone->childbase);
- if (dg != NULL) {
+ if (dg != nullptr) {
BLI_remlink(defbase, dg);
BLI_addhead(defbase, dg);
}
@@ -4146,7 +4197,7 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op)
BLI_listbase_sort(defbase, vgroup_sort_name);
break;
case SORT_TYPE_BONEHIERARCHY:
- vgroup_sort_bone_hierarchy(ob, NULL);
+ vgroup_sort_bone_hierarchy(ob, nullptr);
break;
}
@@ -4170,7 +4221,7 @@ void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
static const EnumPropertyItem vgroup_sort_type[] = {
{SORT_TYPE_NAME, "NAME", 0, "Name", ""},
{SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
ot->name = "Sort Vertex Groups";
@@ -4203,7 +4254,8 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
- def = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1);
+ def = static_cast<bDeformGroup *>(
+ BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1));
if (!def) {
return OPERATOR_CANCELLED;
}
@@ -4231,7 +4283,7 @@ void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
static const EnumPropertyItem vgroup_slot_move[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -4264,7 +4316,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
{
MDeformVert *dvert_act;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
BMEditMesh *em = me->edit_mesh;
int i;
@@ -4274,13 +4326,14 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
BMVert *eve, *eve_act;
dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act);
- if (dvert_act == NULL) {
+ if (dvert_act == nullptr) {
return;
}
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
- MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ MDeformVert *dvert_dst = static_cast<MDeformVert *>(
+ BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
@@ -4299,13 +4352,16 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
int v_act;
dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act);
- if (dvert_act == NULL) {
+ if (dvert_act == nullptr) {
return;
}
- dv = me->dvert;
+ const Span<MVert> verts = me->verts();
+ MutableSpan<MDeformVert> dverts = me->deform_verts_for_write();
+
+ dv = dverts.data();
for (i = 0; i < me->totvert; i++, dv++) {
- if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
+ if ((verts[i].flag & SELECT) && (dv != dvert_act)) {
BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr);
@@ -4324,7 +4380,7 @@ 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)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
- bDeformGroup *dg = BLI_findlink(defbase, def_nr);
+ bDeformGroup *dg = static_cast<bDeformGroup *>(BLI_findlink(defbase, def_nr));
if (!dg) {
BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index");
@@ -4381,7 +4437,7 @@ void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot)
"Index of source weight in active vertex group",
-1,
INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
}
/** \} */
@@ -4431,7 +4487,7 @@ void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot)
"Index of source weight in active vertex group",
-1,
INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
}
/** \} */
@@ -4478,7 +4534,7 @@ void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot)
"Index of source weight in active vertex group",
-1,
INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
}
/** \} */
@@ -4491,7 +4547,7 @@ static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *U
{
Object *ob = ED_object_context(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- eVGroupSelect subset_type = ts->vgroupsubset;
+ eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset);
bool changed;
changed = vgroup_normalize_active_vertex(ob, subset_type);
@@ -4530,7 +4586,7 @@ static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- eVGroupSelect subset_type = ts->vgroupsubset;
+ eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset);
vgroup_copy_active_to_sel(ob, subset_type);
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index ee59efbc925..e56d58c2135 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -11,7 +11,6 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/mantaflow/extern
# RNA_prototypes.h
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index e8ceb97ed7a..1ce90849a88 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -21,6 +21,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_dynamicpaint.h"
@@ -233,7 +234,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
ED_mesh_color_add(ob->data, name, true, true, op->reports);
}
else {
- ED_mesh_color_remove_named(ob->data, name);
+ BKE_id_attribute_remove(ob->data, name, NULL);
}
}
/* Vertex Weight Layer */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 0e03feba340..30dab322fbc 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -30,8 +30,10 @@
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -167,7 +169,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
int PE_minmax(
Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd_eval = NULL;
@@ -1449,26 +1451,27 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
vec = edit->emitter_cosnos;
nor = vec + 3;
+ const MVert *verts = BKE_mesh_verts(mesh);
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
-
+ MFace *mfaces = (MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE);
for (i = 0; i < totface; i++, vec += 6, nor += 6) {
- MFace *mface = &mesh->mface[i];
- MVert *mvert;
+ MFace *mface = &mfaces[i];
+ const MVert *mvert;
- mvert = &mesh->mvert[mface->v1];
+ mvert = &verts[mface->v1];
copy_v3_v3(vec, mvert->co);
copy_v3_v3(nor, vert_normals[mface->v1]);
- mvert = &mesh->mvert[mface->v2];
+ mvert = &verts[mface->v2];
add_v3_v3v3(vec, vec, mvert->co);
add_v3_v3(nor, vert_normals[mface->v2]);
- mvert = &mesh->mvert[mface->v3];
+ mvert = &verts[mface->v3];
add_v3_v3v3(vec, vec, mvert->co);
add_v3_v3(nor, vert_normals[mface->v3]);
if (mface->v4) {
- mvert = &mesh->mvert[mface->v4];
+ mvert = &verts[mface->v4];
add_v3_v3v3(vec, vec, mvert->co);
add_v3_v3(nor, vert_normals[mface->v4]);
@@ -1512,7 +1515,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
}
}
- psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, scene->r.cfra, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -1647,11 +1650,11 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
* and flagging with PEK_HIDE will prevent selection. This might get restored once this is
* supported in drawing (but doesn't make much sense for hair anyways). */
if (edit->psys && edit->psys->part->type == PART_EMITTER) {
- PE_hide_keys_time(scene, edit, CFRA);
+ PE_hide_keys_time(scene, edit, scene->r.cfra);
}
/* regenerate path caches */
- psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, scene->r.cfra, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -3390,7 +3393,7 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
if (brush) {
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(255, 255, 255, 128);
@@ -3566,7 +3569,9 @@ static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagg
}
if (newtotpart != psys->totpart) {
- MFace *mtessface = use_dm_final_indices ? psmd_eval->mesh_final->mface : me->mface;
+ MFace *mtessface = use_dm_final_indices ?
+ (MFace *)CustomData_get_layer(&psmd_eval->mesh_final->fdata, CD_MFACE) :
+ (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE);
/* allocate new arrays and copy existing */
new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
@@ -4174,8 +4179,8 @@ static int particle_intersect_mesh(Depsgraph *depsgraph,
}
totface = mesh->totface;
- mface = mesh->mface;
- mvert = mesh->mvert;
+ mface = (MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE);
+ mvert = BKE_mesh_verts_for_write(mesh);
/* lets intersect the faces */
for (i = 0; i < totface; i++, mface++) {
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 54d28b49e0c..d1a2bb31454 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -21,6 +21,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_undo_system.h"
@@ -211,7 +212,7 @@ static bool particle_undosys_poll(struct bContext *C)
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
return (edit != NULL);
@@ -225,7 +226,7 @@ static bool particle_undosys_step_encode(struct bContext *C,
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
- us->object_ref.ptr = OBACT(view_layer);
+ us->object_ref.ptr = BKE_view_layer_active_object_get(view_layer);
PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 6bea6e2c19e..f13b7519cd7 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -26,6 +26,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -703,7 +704,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
PTCacheEditKey *ekey;
BVHTreeFromMesh bvhtree = {NULL};
MFace *mface = NULL, *mf;
- MEdge *medge = NULL, *me;
+ const MEdge *medge = NULL, *me;
MVert *mvert;
Mesh *mesh, *target_mesh;
int numverts;
@@ -749,7 +750,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
BKE_mesh_tessface_ensure(mesh);
numverts = mesh->totvert;
- mvert = mesh->mvert;
+ mvert = BKE_mesh_verts_for_write(mesh);
/* convert to global coordinates */
for (int i = 0; i < numverts; i++) {
@@ -757,11 +758,11 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
}
if (mesh->totface != 0) {
- mface = mesh->mface;
+ mface = CustomData_get_layer(&mesh->fdata, CD_MFACE);
BKE_bvhtree_from_mesh_get(&bvhtree, mesh, BVHTREE_FROM_FACES, 2);
}
else if (mesh->totedge != 0) {
- medge = mesh->medge;
+ medge = BKE_mesh_edges(mesh);
BKE_bvhtree_from_mesh_get(&bvhtree, mesh, BVHTREE_FROM_EDGES, 2);
}
else {
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 96195bdcc2e..1d3cf7c36af 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -256,8 +256,8 @@ static void fluid_bake_sequence(FluidJob *job)
frame = is_first_frame ? fds->cache_frame_start : (*pause_frame);
/* Save orig frame and update scene frame. */
- orig_frame = CFRA;
- CFRA = frame;
+ orig_frame = scene->r.cfra;
+ scene->r.cfra = frame;
/* Loop through selected frames. */
for (; frame <= fds->cache_frame_end; frame++) {
@@ -280,7 +280,7 @@ static void fluid_bake_sequence(FluidJob *job)
*(job->progress) = progress;
}
- CFRA = frame;
+ scene->r.cfra = frame;
/* Update animation system. */
ED_update_for_newframe(job->bmain, job->depsgraph);
@@ -293,7 +293,7 @@ static void fluid_bake_sequence(FluidJob *job)
}
/* Restore frame position that we were on before bake. */
- CFRA = orig_frame;
+ scene->r.cfra = orig_frame;
}
static void fluid_bake_endjob(void *customdata)
@@ -502,6 +502,7 @@ static void fluid_free_startjob(void *customdata, short *stop, short *do_update,
BKE_fluid_cache_free(fds, job->ob, cache_map);
#else
UNUSED_VARS(fds);
+ UNUSED_VARS(cache_map);
#endif
*do_update = true;
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 66ae2d323fd..3cd2a7dbd29 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -16,6 +16,7 @@
#include "BKE_collection.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -88,7 +89,7 @@ bool ED_rigidbody_constraint_add(
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
rbw->constraints = BKE_collection_add(bmain, NULL, "RigidBodyConstraints");
- id_fake_user_set(&rbw->constraints->id);
+ id_us_plus(&rbw->constraints->id);
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
@@ -122,7 +123,7 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
@@ -174,7 +175,7 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
/* apply to active object */
if (ELEM(NULL, ob, ob->rigidbody_constraint)) {
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 4b644ae826f..a91a63201c4 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -17,7 +17,6 @@ set(INC
../../render
../../sequencer
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc
index d907a52543c..e91bffce2c2 100644
--- a/source/blender/editors/render/render_opengl.cc
+++ b/source/blender/editors/render/render_opengl.cc
@@ -278,19 +278,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr)
{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = oglrender->scene;
- ARegion *region = oglrender->region;
- View3D *v3d = oglrender->v3d;
- RegionView3D *rv3d = oglrender->rv3d;
Object *camera = nullptr;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
- const short view_context = (v3d != nullptr);
- bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- float *rectf = nullptr;
- uchar *rect = nullptr;
- const char *viewname = RE_GetActiveRenderView(oglrender->re);
ImBuf *ibuf_result = nullptr;
if (oglrender->is_sequencer) {
@@ -301,7 +292,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
if (ibuf) {
- ImBuf *out = IMB_dupImBuf(ibuf);
+ ibuf_result = IMB_dupImBuf(ibuf);
IMB_freeImBuf(ibuf);
/* OpenGL render is considered to be preview and should be
* as fast as possible. So currently we're making sure sequencer
@@ -310,25 +301,21 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
* TODO(sergey): In the case of output to float container (EXR)
* it actually makes sense to keep float buffer instead.
*/
- if (out->rect_float != nullptr) {
- IMB_rect_from_float(out);
- imb_freerectfloatImBuf(out);
+ if (ibuf_result->rect_float != nullptr) {
+ IMB_rect_from_float(ibuf_result);
+ imb_freerectfloatImBuf(ibuf_result);
}
- BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
- RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id);
- IMB_freeImBuf(out);
+ BLI_assert((sizex == ibuf->x) && (sizey == ibuf->y));
}
else if (gpd) {
/* If there are no strips, Grease Pencil still needs a buffer to draw on */
- ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
- RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id);
- IMB_freeImBuf(out);
+ ibuf_result = IMB_allocImBuf(sizex, sizey, 32, IB_rect);
}
if (gpd) {
int i;
uchar *gp_rect;
- uchar *render_rect = (uchar *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
+ uchar *render_rect = (uchar *)ibuf_result->rect;
DRW_opengl_context_enable();
GPU_offscreen_bind(oglrender->ofs, true);
@@ -359,10 +346,16 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
}
else {
/* shouldn't suddenly give errors mid-render but possible */
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
char err_out[256] = "unknown";
ImBuf *ibuf_view;
+ bool draw_sky = (scene->r.alphamode == R_ADDSKY);
const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
- if (view_context) {
+ const char *viewname = RE_GetActiveRenderView(oglrender->re);
+ View3D *v3d = oglrender->v3d;
+
+ if (v3d != nullptr) {
+ ARegion *region = oglrender->region;
ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
scene,
static_cast<eDrawType>(v3d->shading.type),
@@ -378,7 +371,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
err_out);
/* for stamp only */
- if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ if (oglrender->rv3d->persp == RV3D_CAMOB && v3d->camera) {
camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
}
}
@@ -388,8 +381,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
nullptr,
OB_SOLID,
scene->camera,
- oglrender->sizex,
- oglrender->sizey,
+ sizex,
+ sizey,
IB_rectfloat,
V3D_OFSDRAW_SHOW_ANNOTATION,
alpha_mode,
@@ -401,12 +394,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (ibuf_view) {
ibuf_result = ibuf_view;
- if (ibuf_view->rect_float) {
- rectf = ibuf_view->rect_float;
- }
- else {
- rect = (uchar *)ibuf_view->rect;
- }
}
else {
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
@@ -415,6 +402,14 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (ibuf_result != nullptr) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
+ float *rectf = nullptr;
+ uchar *rect = nullptr;
+ if (ibuf_result->rect_float) {
+ rectf = ibuf_result->rect_float;
+ }
+ else {
+ rect = (uchar *)ibuf_result->rect;
+ }
BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
@@ -494,7 +489,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
for (view_id = 0; view_id < oglrender->views_len; view_id++) {
context.view_id = view_id;
context.gpu_offscreen = oglrender->ofs;
- oglrender->seq_data.ibufs_arr[view_id] = SEQ_render_give_ibuf(&context, CFRA, chanshown);
+ oglrender->seq_data.ibufs_arr[view_id] = SEQ_render_give_ibuf(
+ &context, scene->r.cfra, chanshown);
}
}
@@ -757,8 +753,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
WM_jobs_kill_all_except(wm, CTX_wm_screen(C));
/* create offscreen buffer */
- sizex = (scene->r.size * scene->r.xsch) / 100;
- sizey = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &sizex, &sizey);
/* corrects render size with actual size, not every card supports non-power-of-two dimensions */
DRW_opengl_context_enable(); /* Off-screen creation needs to be done in DRW context. */
@@ -1136,12 +1131,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
RenderResult *rr;
/* go to next frame */
- if (CFRA < oglrender->nfra) {
- CFRA++;
+ if (scene->r.cfra < oglrender->nfra) {
+ scene->r.cfra++;
}
- while (CFRA < oglrender->nfra) {
+ while (scene->r.cfra < oglrender->nfra) {
BKE_scene_graph_update_for_newframe(depsgraph);
- CFRA++;
+ scene->r.cfra++;
}
is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
@@ -1184,7 +1179,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
}
if (oglrender->render_frames == nullptr ||
- BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
+ BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA)) {
/* render into offscreen buffer */
screen_opengl_render_apply(C, oglrender);
}
@@ -1204,7 +1199,7 @@ finally: /* Step the frame and bail early if needed */
oglrender->nfra += scene->r.frame_step;
/* stop at the end or on error */
- if (CFRA >= PEFRA || !ok) {
+ if (scene->r.cfra >= PEFRA || !ok) {
screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return false;
}
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index addcedc4481..5e23458e8bb 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -679,7 +679,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
/* material preview only needs monoscopy (view 0) */
RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexTiled(&state,
fx,
fy,
@@ -805,7 +805,7 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
/* Preview need to be in the current frame to get a thumbnail similar of what
* viewport displays. */
- CFRA = preview_data->cfra;
+ scene->r.cfra = preview_data->cfra;
ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
Depsgraph *depsgraph = DEG_graph_new(
@@ -1771,7 +1771,7 @@ PreviewLoadJob &PreviewLoadJob::ensure_job(wmWindowManager *wm, wmWindow *win)
WM_jobs_start(wm, wm_job);
}
- return *reinterpret_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job));
+ return *static_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job));
}
void PreviewLoadJob::load_jobless(PreviewImage *preview, const eIconSizes icon_size)
@@ -1807,11 +1807,11 @@ void PreviewLoadJob::run_fn(void *customdata,
short *do_update,
float *UNUSED(progress))
{
- PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata);
+ PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
IMB_thumb_locks_acquire();
- while (RequestedPreview *request = reinterpret_cast<RequestedPreview *>(
+ while (RequestedPreview *request = static_cast<RequestedPreview *>(
BLI_thread_queue_pop_timeout(job_data->todo_queue_, 100))) {
if (*stop) {
break;
@@ -1864,7 +1864,7 @@ void PreviewLoadJob::finish_request(RequestedPreview &request)
void PreviewLoadJob::update_fn(void *customdata)
{
- PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata);
+ PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
for (auto request_it = job_data->requested_previews_.begin();
request_it != job_data->requested_previews_.end();) {
@@ -1884,7 +1884,7 @@ void PreviewLoadJob::update_fn(void *customdata)
void PreviewLoadJob::end_fn(void *customdata)
{
- PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata);
+ PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata);
/* Finish any possibly remaining queued previews. */
for (RequestedPreview &request : job_data->requested_previews_) {
@@ -1895,7 +1895,7 @@ void PreviewLoadJob::end_fn(void *customdata)
void PreviewLoadJob::free_fn(void *customdata)
{
- MEM_delete(reinterpret_cast<PreviewLoadJob *>(customdata));
+ MEM_delete(static_cast<PreviewLoadJob *>(customdata));
}
static void icon_preview_free(void *customdata)
diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc
index da2290f7372..f784346ec8f 100644
--- a/source/blender/editors/render/render_shading.cc
+++ b/source/blender/editors/render/render_shading.cc
@@ -934,7 +934,7 @@ static int view_layer_add_exec(bContext *C, wmOperator *op)
WM_window_set_active_view_layer(win, view_layer_new);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1039,7 +1039,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositUpdateRLayers(scene->nodetree);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1091,7 +1091,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositUpdateRLayers(scene->nodetree);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1143,7 +1143,7 @@ static int view_layer_add_lightgroup_exec(bContext *C, wmOperator *op)
ntreeCompositUpdateRLayers(scene->nodetree);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1193,7 +1193,7 @@ static int view_layer_remove_lightgroup_exec(bContext *C, wmOperator *UNUSED(op)
ntreeCompositUpdateRLayers(scene->nodetree);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1257,7 +1257,7 @@ static int view_layer_add_used_lightgroups_exec(bContext *C, wmOperator *UNUSED(
ntreeCompositUpdateRLayers(scene->nodetree);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1301,7 +1301,7 @@ static int view_layer_remove_unused_lightgroups_exec(bContext *C, wmOperator *UN
ntreeCompositUpdateRLayers(scene->nodetree);
}
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -1692,7 +1692,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -1722,7 +1722,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
int dir = RNA_enum_get(op->ptr, "direction");
if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
@@ -1778,7 +1778,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr);
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -1852,7 +1852,7 @@ static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op))
FRS_paste_active_lineset(&view_layer->freestyle_config);
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -1886,7 +1886,7 @@ static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op))
FRS_delete_active_lineset(&view_layer->freestyle_config);
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -1920,7 +1920,7 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
int dir = RNA_enum_get(op->ptr, "direction");
if (FRS_move_active_lineset(&view_layer->freestyle_config, dir)) {
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
diff --git a/source/blender/editors/render/render_update.cc b/source/blender/editors/render/render_update.cc
index 3d26e764211..7cefcf9815e 100644
--- a/source/blender/editors/render/render_update.cc
+++ b/source/blender/editors/render/render_update.cc
@@ -95,20 +95,20 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
CTX_free(C);
}
- else {
- RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
- if (updated) {
- DRWUpdateContext drw_context = {nullptr};
- drw_context.bmain = bmain;
- drw_context.depsgraph = depsgraph;
- drw_context.scene = scene;
- drw_context.view_layer = view_layer;
- drw_context.region = region;
- drw_context.v3d = v3d;
- drw_context.engine_type = engine_type;
- DRW_notify_view_update(&drw_context);
- }
+
+ if (!updated) {
+ continue;
}
+
+ DRWUpdateContext drw_context = {nullptr};
+ drw_context.bmain = bmain;
+ drw_context.depsgraph = depsgraph;
+ drw_context.scene = scene;
+ drw_context.view_layer = view_layer;
+ drw_context.region = region;
+ drw_context.v3d = v3d;
+ drw_context.engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ DRW_notify_view_update(&drw_context);
}
}
diff --git a/source/blender/editors/render/render_view.cc b/source/blender/editors/render/render_view.cc
index a7ff2aad05a..9a16c910205 100644
--- a/source/blender/editors/render/render_view.cc
+++ b/source/blender/editors/render/render_view.cc
@@ -19,6 +19,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BLT_translation.h"
@@ -130,8 +131,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
- int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
- int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
+ int sizex, sizey;
+ BKE_render_resolution(&scene->r, false, &sizex, &sizey);
+
+ sizex += 30 * UI_DPI_FAC;
+ sizey += 60 * UI_DPI_FAC;
/* arbitrary... miniature image window views don't make much sense */
if (sizex < 320) {
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 57a9e6be917..07a93d3907a 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -229,7 +229,7 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep
BKE_view_layer_free(layer);
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_LAYER | NA_REMOVED, scene);
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index f9b1e2b5d4c..119758f3335 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -15,7 +15,6 @@ set(INC
../../makesrna
../../sequencer
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index f58baa0e25c..dc3aaea5e49 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -83,7 +83,7 @@ static void region_draw_emboss(const ARegion *region, const rcti *scirct, int si
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
immBeginAtMost(GPU_PRIM_LINES, 8);
@@ -127,7 +127,7 @@ void ED_region_pixelspace(const ARegion *region)
void ED_region_do_listen(wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *notifier = params->notifier;
+ const wmNotifier *notifier = params->notifier;
/* generic notes first */
switch (notifier->category) {
@@ -238,8 +238,6 @@ static void draw_azone_arrow(float x1, float y1, float x2, float y2, AZEdge edge
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_blend(GPU_BLEND_ALPHA);
- /* NOTE(fclem): There is something strange going on with Mesa and GPU_SHADER_2D_UNIFORM_COLOR
- * that causes a crash on some GPUs (see T76113). Using 3D variant avoid the issue. */
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f);
@@ -563,7 +561,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
GPU_blend(GPU_BLEND_ALPHA);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(BLI_thread_frand(0), BLI_thread_frand(0), BLI_thread_frand(0), 0.1f);
immRectf(pos,
region->drawrct.xmin - region->winrct.xmin,
@@ -593,7 +591,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
UI_GetThemeColor3fv(TH_EDITOR_OUTLINE, color);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
GPU_line_width(1.0f);
imm_draw_box_wire_2d(pos,
@@ -1075,6 +1073,7 @@ static void region_azone_scrollbar_init(ScrArea *area,
{
rcti scroller_vert = (direction == AZ_SCROLL_VERT) ? region->v2d.vert : region->v2d.hor;
AZone *az = MEM_callocN(sizeof(*az), __func__);
+ float hide_width;
BLI_addtail(&area->actionzones, az);
az->type = AZONE_REGION_SCROLL;
@@ -1083,16 +1082,18 @@ static void region_azone_scrollbar_init(ScrArea *area,
if (direction == AZ_SCROLL_VERT) {
az->region->v2d.alpha_vert = 0;
+ hide_width = V2D_SCROLL_HIDE_HEIGHT;
}
else if (direction == AZ_SCROLL_HOR) {
az->region->v2d.alpha_hor = 0;
+ hide_width = V2D_SCROLL_HIDE_WIDTH;
}
BLI_rcti_translate(&scroller_vert, region->winrct.xmin, region->winrct.ymin);
- az->x1 = scroller_vert.xmin - AZONEFADEIN;
- az->y1 = scroller_vert.ymin - AZONEFADEIN;
- az->x2 = scroller_vert.xmax + AZONEFADEIN;
- az->y2 = scroller_vert.ymax + AZONEFADEIN;
+ az->x1 = scroller_vert.xmin - ((direction == AZ_SCROLL_VERT) ? hide_width : 0);
+ az->y1 = scroller_vert.ymin - ((direction == AZ_SCROLL_HOR) ? hide_width : 0);
+ az->x2 = scroller_vert.xmax + ((direction == AZ_SCROLL_VERT) ? hide_width : 0);
+ az->y2 = scroller_vert.ymax + ((direction == AZ_SCROLL_HOR) ? hide_width : 0);
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
@@ -3125,7 +3126,12 @@ void ED_region_panels_draw(const bContext *C, ARegion *region)
UI_view2d_mask_from_win(v2d, &mask);
mask.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH;
}
- UI_view2d_scrollers_draw(v2d, use_mask ? &mask : NULL);
+ bool use_full_hide = false;
+ if (region->overlap) {
+ /* Don't always show scrollbars for transparent regions as it's distracting. */
+ use_full_hide = true;
+ }
+ UI_view2d_scrollers_draw_ex(v2d, use_mask ? &mask : NULL, use_full_hide);
}
void ED_region_panels_ex(const bContext *C, ARegion *region, const char *contexts[])
@@ -3550,7 +3556,7 @@ void ED_region_info_draw_multiline(ARegion *region,
GPU_blend(GPU_BLEND_ALPHA);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(fill_color);
immRecti(pos, rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1);
immUnbindProgram();
@@ -3621,7 +3627,7 @@ void ED_region_grid_draw(ARegion *region, float zoomx, float zoomy, float x0, fl
float gridcolor[4];
UI_GetThemeColor4fv(TH_GRID, gridcolor);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* To fake alpha-blending, color shading is reduced when alpha is nearing 0. */
immUniformThemeColorBlendShade(TH_BACK, TH_GRID, gridcolor[3], 20 * gridcolor[3]);
immRectf(pos, x1, y1, x2, y2);
@@ -3658,7 +3664,7 @@ void ED_region_grid_draw(ARegion *region, float zoomx, float zoomy, float x0, fl
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
immBegin(GPU_PRIM_LINES, 4 * count_fine + 4 * count_large);
float theme_color[3];
@@ -3771,7 +3777,7 @@ void ED_region_cache_draw_background(ARegion *region)
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(128, 128, 255, 64);
immRecti(pos, 0, region_bottom, region->winx, region_bottom + 8 * UI_DPI_FAC);
immUnbindProgram();
@@ -3792,7 +3798,7 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_CFRAME);
immRecti(pos, x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f);
immUnbindProgram();
@@ -3812,7 +3818,7 @@ void ED_region_cache_draw_cached_segments(
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(128, 128, 255, 128);
for (int a = 0; a < num_segments; a++) {
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 8a84f4cf079..4382fd3d1c2 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -77,9 +77,10 @@ void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
* filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR),
* so always use mipmaps when filtering. */
const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
- const int mips = use_mipmap ? 9999 : 1;
+ const int mip_len = use_mipmap ? 9999 : 1;
- GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, mips, gpu_format, NULL);
+ GPUTexture *tex = GPU_texture_create_2d(
+ "immDrawPixels", img_w, img_h, mip_len, gpu_format, NULL);
const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
@@ -514,7 +515,7 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
ibuf, view_settings, display_settings, &cache_handle);
if (display_buffer) {
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexTiled_clipping(&state,
x,
y,
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 11a62123ad7..7bdae1464c0 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -100,6 +100,7 @@ const char *screen_context_dir[] = {
"active_gpencil_frame",
"active_annotation_layer",
"active_operator",
+ "active_action",
"selected_visible_actions",
"selected_editable_actions",
"visible_fcurves",
@@ -242,7 +243,7 @@ static eContextResult screen_ctx_visible_or_editable_bones_(const bContext *C,
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *flipbone = NULL;
@@ -313,7 +314,7 @@ static eContextResult screen_ctx_selected_bones_(const bContext *C,
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *flipbone = NULL;
@@ -523,7 +524,7 @@ static eContextResult screen_ctx_edit_object(const bContext *C, bContextDataResu
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
/* convenience for now, 1 object per scene in editmode */
if (obedit) {
CTX_data_id_pointer_set(result, &obedit->id);
@@ -969,6 +970,7 @@ static eContextResult screen_ctx_active_operator(const bContext *C, bContextData
}
static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
bContextDataResult *result,
+ bool active_only,
bool editable)
{
bAnimContext ac;
@@ -978,11 +980,17 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
SpaceAction *saction = (SpaceAction *)ac.sl;
if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY)) {
- if (saction->action && !(editable && ID_IS_LINKED(saction->action))) {
- CTX_data_id_list_add(result, &saction->action->id);
+ if (active_only) {
+ CTX_data_id_pointer_set(result, (ID *)saction->action);
+ }
+ else {
+ if (saction->action && !(editable && ID_IS_LINKED(saction->action))) {
+ CTX_data_id_list_add(result, &saction->action->id);
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
}
@@ -995,7 +1003,8 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
switch (ac.spacetype) {
case SPACE_GRAPH:
- filter |= ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL;
+ filter |= ANIMFILTER_FCURVESONLY | ANIMFILTER_CURVE_VISIBLE |
+ (active_only ? ANIMFILTER_ACTIVE : ANIMFILTER_SEL);
break;
case SPACE_ACTION:
@@ -1006,7 +1015,7 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- GSet *seen_set = BLI_gset_ptr_new("seen actions");
+ GSet *seen_set = active_only ? NULL : BLI_gset_ptr_new("seen actions");
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
/* In dopesheet check selection status of individual items, skipping
@@ -1019,37 +1028,46 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
bAction *action = ANIM_channel_action_get(ale);
if (action) {
+ if (active_only) {
+ CTX_data_id_pointer_set(result, (ID *)action);
+ break;
+ }
if (editable && ID_IS_LINKED(action)) {
continue;
}
/* Add the action to the output list if not already added. */
- if (!BLI_gset_haskey(seen_set, action)) {
+ if (BLI_gset_add(seen_set, action)) {
CTX_data_id_list_add(result, &action->id);
- BLI_gset_add(seen_set, action);
}
}
}
- BLI_gset_free(seen_set, NULL);
-
ANIM_animdata_freelist(&anim_data);
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ if (!active_only) {
+ BLI_gset_free(seen_set, NULL);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ }
+
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
-
+static eContextResult screen_ctx_active_action(const bContext *C, bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, true, false);
+}
static eContextResult screen_ctx_selected_visible_actions(const bContext *C,
bContextDataResult *result)
{
- return screen_ctx_sel_actions_impl(C, result, false);
+ return screen_ctx_sel_actions_impl(C, result, false, false);
}
static eContextResult screen_ctx_selected_editable_actions(const bContext *C,
bContextDataResult *result)
{
- return screen_ctx_sel_actions_impl(C, result, true);
+ return screen_ctx_sel_actions_impl(C, result, false, true);
}
static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
bContextDataResult *result,
@@ -1060,8 +1078,9 @@ static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS) |
- (ac.spacetype == SPACE_GRAPH ? ANIMFILTER_CURVE_VISIBLE :
- ANIMFILTER_LIST_VISIBLE) |
+ (ac.spacetype == SPACE_GRAPH ?
+ (ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY) :
+ ANIMFILTER_LIST_VISIBLE) |
extra_filter;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1105,7 +1124,7 @@ static eContextResult screen_ctx_active_editable_fcurve(const bContext *C,
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
- ANIMFILTER_CURVE_VISIBLE);
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_CURVE_VISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1131,8 +1150,9 @@ static eContextResult screen_ctx_selected_editable_keyframes(const bContext *C,
/* Use keyframes from editable selected FCurves. */
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FOREDIT |
ANIMFILTER_SEL) |
- (ac.spacetype == SPACE_GRAPH ? ANIMFILTER_CURVE_VISIBLE :
- ANIMFILTER_LIST_VISIBLE);
+ (ac.spacetype == SPACE_GRAPH ?
+ (ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY) :
+ ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1261,6 +1281,7 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("editable_gpencil_layers", screen_ctx_editable_gpencil_layers);
register_context_function("editable_gpencil_strokes", screen_ctx_editable_gpencil_strokes);
register_context_function("active_operator", screen_ctx_active_operator);
+ register_context_function("active_action", screen_ctx_active_action);
register_context_function("selected_visible_actions", screen_ctx_selected_visible_actions);
register_context_function("selected_editable_actions", screen_ctx_selected_editable_actions);
register_context_function("editable_fcurves", screen_ctx_editable_fcurves);
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 6406b0d9d52..065cb3a61a2 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -236,7 +236,7 @@ void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
uint pos_id = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
/* Highlight source (sa1) within combined area. */
@@ -302,7 +302,7 @@ void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float fac)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Split-point. */
GPU_blend(GPU_BLEND_ALPHA);
@@ -380,7 +380,7 @@ static void screen_preview_draw_areas(const bScreen *screen,
const float ofs_h = ofs_between_areas * 0.5f;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(col);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 08c8c863729..67871d08089 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -110,7 +110,7 @@ ScrArea *area_split(const wmWindow *win,
return NULL;
}
- /* NOTE(campbell): regarding (fac > 0.5f) checks below.
+ /* NOTE(@campbellbarton): regarding (fac > 0.5f) checks below.
* normally it shouldn't matter which is used since the copy should match the original
* however with viewport rendering and python console this isn't the case. */
@@ -580,7 +580,7 @@ static void region_cursor_set(wmWindow *win, bool swin_changed)
}
}
-void ED_screen_do_listen(bContext *C, wmNotifier *note)
+void ED_screen_do_listen(bContext *C, const wmNotifier *note)
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
@@ -1212,10 +1212,10 @@ void ED_screen_scene_change(bContext *C,
/* Mode Syncing. */
if (view_layer_old) {
WorkSpace *workspace = CTX_wm_workspace(C);
- Object *obact_new = OBACT(view_layer);
+ Object *obact_new = BKE_view_layer_active_object_get(view_layer);
UNUSED_VARS(obact_new);
eObjectMode object_mode_old = workspace->object_mode;
- Object *obact_old = OBACT(view_layer_old);
+ Object *obact_old = BKE_view_layer_active_object_get(view_layer_old);
UNUSED_VARS(obact_old, object_mode_old);
}
#endif
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 3486ea8b466..3ad3fa7892c 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -284,7 +284,7 @@ short screen_geom_find_area_split_point(const ScrArea *area,
{
const int cur_area_width = screen_geom_area_width(area);
const int cur_area_height = screen_geom_area_height(area);
- const short area_min_x = AREAMINX;
+ const short area_min_x = AREAMINX * U.dpi_fac;
const short area_min_y = ED_area_headersize();
/* area big enough? */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 55721e6380d..5331747beae 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -659,32 +659,6 @@ bool ED_operator_editmball(bContext *C)
return false;
}
-bool ED_operator_mask(bContext *C)
-{
- ScrArea *area = CTX_wm_area(C);
- if (area && area->spacedata.first) {
- switch (area->spacetype) {
- case SPACE_CLIP: {
- SpaceClip *space_clip = area->spacedata.first;
- return ED_space_clip_check_show_maskedit(space_clip);
- }
- case SPACE_SEQ: {
- SpaceSeq *sseq = area->spacedata.first;
- Scene *scene = CTX_data_scene(C);
- return ED_space_sequencer_check_show_maskedit(sseq, scene);
- }
- case SPACE_IMAGE: {
- SpaceImage *sima = area->spacedata.first;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- return ED_space_image_check_show_maskedit(sima, obedit);
- }
- }
- }
-
- return false;
-}
-
bool ED_operator_camera_poll(bContext *C)
{
struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
@@ -749,15 +723,16 @@ typedef struct sActionzoneData {
static bool actionzone_area_poll(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *screen = WM_window_get_active_screen(win);
-
- if (screen && win && win->eventstate) {
- const int *xy = &win->eventstate->xy[0];
+ if (win && win->eventstate) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen) {
+ const int *xy = &win->eventstate->xy[0];
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
- if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
- return true;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
+ if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
+ return true;
+ }
}
}
}
@@ -913,14 +888,16 @@ static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const b
float dist_fac = 0.0f, alpha = 0.0f;
if (az->direction == AZ_SCROLL_HOR) {
- dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / AZONEFADEIN;
+ float hide_width = (az->y2 - az->y1) / 2.0f;
+ dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / hide_width;
CLAMP(dist_fac, 0.0f, 1.0f);
alpha = 1.0f - dist_fac;
v2d->alpha_hor = alpha * 255;
}
else if (az->direction == AZ_SCROLL_VERT) {
- dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / AZONEFADEIN;
+ float hide_width = (az->x2 - az->x1) / 2.0f;
+ dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / hide_width;
CLAMP(dist_fac, 0.0f, 1.0f);
alpha = 1.0f - dist_fac;
@@ -1662,7 +1639,7 @@ static void area_move_set_limits(wmWindow *win,
}
}
else {
- int areamin = AREAMINX;
+ int areamin = AREAMINX * U.dpi_fac;
if (area->v1->vec.x > window_rect.xmin) {
areamin += U.pixelsize;
@@ -2085,7 +2062,7 @@ static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
return false;
}
- if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX) ||
+ if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX * U.dpi_fac) ||
(dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize())) {
/* Must be at least double minimum sizes to split into two. */
return false;
@@ -2975,9 +2952,9 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
int delta = RNA_int_get(op->ptr, "delta");
- CFRA += delta;
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
+ scene->r.cfra += delta;
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
+ scene->r.subframe = 0.0f;
areas_do_frame_follow(C, false);
@@ -3016,7 +2993,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
- /* Don't change CFRA directly if animtimer is running as this can cause
+ /* Don't change scene->r.cfra directly if animtimer is running as this can cause
* first/last frame not to be actually shown (bad since for example physics
* simulations aren't reset properly).
*/
@@ -3034,10 +3011,10 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
}
else {
if (RNA_boolean_get(op->ptr, "end")) {
- CFRA = PEFRA;
+ scene->r.cfra = PEFRA;
}
else {
- CFRA = PSFRA;
+ scene->r.cfra = PSFRA;
}
areas_do_frame_follow(C, true);
@@ -3086,7 +3063,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- float cfra = (float)(CFRA);
+ float cfra = (float)(scene->r.cfra);
/* Initialize binary-tree-list for getting keyframes. */
struct AnimKeylist *keylist = ED_keylist_create();
@@ -3128,9 +3105,9 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
}
while ((ak != NULL) && (done == false)) {
- if (CFRA != (int)ak->cfra) {
+ if (scene->r.cfra != (int)ak->cfra) {
/* this changes the frame, so set the frame and we're done */
- CFRA = (int)ak->cfra;
+ scene->r.cfra = (int)ak->cfra;
done = true;
}
else {
@@ -3189,20 +3166,20 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
static int marker_jump_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- int closest = CFRA;
+ int closest = scene->r.cfra;
const bool next = RNA_boolean_get(op->ptr, "next");
bool found = false;
/* find matching marker in the right direction */
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
if (next) {
- if ((marker->frame > CFRA) && (!found || closest > marker->frame)) {
+ if ((marker->frame > scene->r.cfra) && (!found || closest > marker->frame)) {
closest = marker->frame;
found = true;
}
}
else {
- if ((marker->frame < CFRA) && (!found || closest < marker->frame)) {
+ if ((marker->frame < scene->r.cfra) && (!found || closest < marker->frame)) {
closest = marker->frame;
found = true;
}
@@ -3216,7 +3193,7 @@ static int marker_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- CFRA = closest;
+ scene->r.cfra = closest;
areas_do_frame_follow(C, true);
@@ -4738,11 +4715,11 @@ static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), con
if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
#ifdef PROFILE_AUDIO_SYNCH
- old_frame = CFRA;
+ old_frame = scene->r.cfra;
#endif
}
- /* since we follow drawflags, we can't send notifier but tag regions ourselves */
+ /* Since we follow draw-flags, we can't send notifier but tag regions ourselves. */
if (depsgraph != NULL) {
ED_update_for_newframe(bmain, depsgraph);
}
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 1156452310c..01c208bf48d 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -34,6 +34,7 @@
#include "UI_resources.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
/* -------------------------------------------------------------------- */
@@ -214,7 +215,14 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
wmOperatorType *ot = WM_operatortype_find(umi_op->op_idname, false);
if (ot != NULL) {
IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
- uiItemFullO_ptr(menu->layout, ot, ui_name, ICON_NONE, prop, umi_op->opcontext, 0, NULL);
+ uiItemFullO_ptr(menu->layout,
+ ot,
+ CTX_IFACE_(ot->translation_context, ui_name),
+ ICON_NONE,
+ prop,
+ umi_op->opcontext,
+ 0,
+ NULL);
is_empty = false;
}
else {
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 5464d0a347d..38a9d8ba7ab 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -54,13 +54,12 @@ static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area)
{
int dumprect_size[2];
- wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
/* do redraw so we don't show popups/menus */
WM_redraw_windows(C);
- uint *dumprect = WM_window_pixels_read(wm, win, dumprect_size);
+ uint *dumprect = WM_window_pixels_read_offscreen(C, win, dumprect_size);
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 01417650b3d..9a6bdc98d76 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -54,17 +54,87 @@ WorkSpace *ED_workspace_add(Main *bmain, const char *name)
return BKE_workspace_add(bmain, name);
}
+static void workspace_exit(WorkSpace *workspace, wmWindow *win)
+{
+ /* Scene pinning: Store whatever scene was active when leaving the workspace. It's reactivated
+ * when the workspace gets reactivated as well. */
+ if (workspace->flags & WORKSPACE_USE_PIN_SCENE) {
+ workspace->pin_scene = WM_window_get_active_scene(win);
+ }
+ else {
+ /* The active scene may have been changed. So also always update the unpinned scene to the
+ * latest when leaving a workspace that has no scene pinning. */
+ win->unpinned_scene = WM_window_get_active_scene(win);
+ }
+}
+
+/**
+ * State changes (old workspace to new workspace):
+ * 1) unpinned -> pinned
+ * * Store current scene as the unpinned one (done in #workspace_exit()).
+ * * Change the current scene to the pinned one.
+ * 2) pinned -> pinned
+ * * Change the current scene to the new pinned one.
+ * 3) pinned -> unpinned
+ * * Change current scene back to the unpinned one
+ * 4) unpinned -> unpinned
+ * * Make sure the unpinned scene is active.
+ *
+ * Note that the pin scene must also be updated when leaving a workspace with a pinned scene.
+ * That's done separately via workspace_exit() above.
+ */
+static void workspace_scene_pinning_update(WorkSpace *workspace_new,
+ const WorkSpace *workspace_old,
+ bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *active_scene = WM_window_get_active_scene(win);
+
+ const bool is_new_pinned = (workspace_new->flags & WORKSPACE_USE_PIN_SCENE);
+ const bool is_old_pinned = (workspace_old->flags & WORKSPACE_USE_PIN_SCENE);
+
+ /* State changes 1 and 2. */
+ if (is_new_pinned) {
+ if (workspace_new->pin_scene && (workspace_new->pin_scene != active_scene)) {
+ WM_window_set_active_scene(bmain, C, win, workspace_new->pin_scene);
+ workspace_new->pin_scene = NULL;
+ }
+ }
+ /* State change 3 - Changing from workspace with pinned scene to unpinned scene. */
+ else if (is_old_pinned) {
+ if (win->unpinned_scene) {
+ WM_window_set_active_scene(bmain, C, win, win->unpinned_scene);
+ }
+ else {
+ /* When leaving a workspace where the pinning was just enabled, the unpinned scene wasn't set
+ * yet. */
+ win->unpinned_scene = active_scene;
+ }
+ }
+ else {
+ /* When leaving a workspace where the pinning was just disabled, we still want to restore the
+ * unpinned scene. */
+ if (win->unpinned_scene) {
+ WM_window_set_active_scene(bmain, C, win, win->unpinned_scene);
+ }
+ }
+
+ BLI_assert(WM_window_get_active_scene(win));
+}
+
/**
* Changes the object mode (if needed) to the one set in \a workspace_new.
* Object mode is still stored on object level. In future it should all be workspace level instead.
*/
static void workspace_change_update(WorkSpace *workspace_new,
- const WorkSpace *workspace_old,
+ WorkSpace *workspace_old,
bContext *C,
wmWindowManager *wm)
{
+ workspace_scene_pinning_update(workspace_new, workspace_old, C);
/* needs to be done before changing mode! (to ensure right context) */
- UNUSED_VARS(workspace_old, workspace_new, C, wm);
+ UNUSED_VARS(wm);
#if 0
Object *ob_act = CTX_data_active_object(C) eObjectMode mode_old = workspace_old->object_mode;
eObjectMode mode_new = workspace_new->object_mode;
@@ -113,6 +183,8 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return false;
}
+ workspace_exit(workspace_old, win);
+
screen_change_prepare(screen_old, screen_new, bmain, C, win);
if (screen_new == NULL) {
@@ -143,11 +215,12 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2);
workspace_new->flags = workspace_old->flags;
+ workspace_new->pin_scene = workspace_old->pin_scene;
workspace_new->object_mode = workspace_old->object_mode;
workspace_new->order = workspace_old->order;
BLI_duplicatelist(&workspace_new->owner_ids, &workspace_old->owner_ids);
- /* TODO(campbell): tools */
+ /* TODO(@campbellbarton): tools */
LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, &workspace_old->layouts) {
WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(
@@ -286,6 +359,12 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op)
BLO_LIBLINK_APPEND_RECURSIVE);
if (appended_workspace) {
+ if (BLT_translate_new_dataname()) {
+ /* Translate workspace name */
+ BKE_libblock_rename(
+ bmain, &appended_workspace->id, CTX_DATA_(BLT_I18NCONTEXT_ID_WORKSPACE, idname));
+ }
+
/* Set defaults. */
BLO_update_defaults_workspace(appended_workspace, NULL);
@@ -368,8 +447,14 @@ static void workspace_append_button(uiLayout *layout,
BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate"));
PointerRNA opptr;
- uiItemFullO_ptr(
- layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
+ uiItemFullO_ptr(layout,
+ ot_append,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_WORKSPACE, workspace->id.name + 2),
+ ICON_NONE,
+ NULL,
+ WM_OP_EXEC_DEFAULT,
+ 0,
+ &opptr);
RNA_string_set(&opptr, "idname", id->name + 2);
RNA_string_set(&opptr, "filepath", filepath);
}
@@ -422,7 +507,8 @@ static void workspace_add_menu(bContext *UNUSED(C), uiLayout *layout, void *temp
static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_ADD);
+ uiPopupMenu *pup = UI_popup_menu_begin(
+ C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, op->type->name), ICON_ADD);
uiLayout *layout = UI_popup_menu_layout(pup);
uiItemMenuF(layout, IFACE_("General"), ICON_NONE, workspace_add_menu, NULL);
@@ -434,7 +520,7 @@ static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
char *template = link->data;
char display_name[FILE_MAX];
- BLI_path_to_display_name(display_name, sizeof(display_name), template);
+ BLI_path_to_display_name(display_name, sizeof(display_name), IFACE_(template));
/* Steals ownership of link data string. */
uiItemMenuFN(layout, display_name, ICON_NONE, workspace_add_menu, template);
@@ -512,6 +598,35 @@ static void WORKSPACE_OT_reorder_to_front(wmOperatorType *ot)
ot->exec = workspace_reorder_to_front_exec;
}
+static int workspace_scene_pin_toggle(bContext *C, wmOperator *UNUSED(op))
+{
+ WorkSpace *workspace = workspace_context_get(C);
+
+ /* Trivial. The operator is only needed to display a superimposed extra icon, which
+ * requires an operator. */
+ workspace->flags ^= WORKSPACE_USE_PIN_SCENE;
+
+ WM_event_add_notifier(C, NC_WORKSPACE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_scene_pin_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Pin Scene to Workspace";
+ ot->description =
+ "Remember the last used scene for the current workspace and switch to it whenever this "
+ "workspace is activated again";
+ ot->idname = "WORKSPACE_OT_scene_pin_toggle";
+
+ /* api callbacks */
+ ot->poll = workspace_context_poll;
+ ot->exec = workspace_scene_pin_toggle;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
void ED_operatortypes_workspace(void)
{
WM_operatortype_append(WORKSPACE_OT_duplicate);
@@ -520,6 +635,7 @@ void ED_operatortypes_workspace(void)
WM_operatortype_append(WORKSPACE_OT_append_activate);
WM_operatortype_append(WORKSPACE_OT_reorder_to_back);
WM_operatortype_append(WORKSPACE_OT_reorder_to_front);
+ WM_operatortype_append(WORKSPACE_OT_scene_pin_toggle);
}
/** \} Workspace Operators */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index b1b52d16c6d..f4d3002219d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -21,7 +21,6 @@ set(INC
../../../../intern/atomic
../../../../intern/clog
../../../../intern/eigen
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -32,10 +31,15 @@ set(SRC
curves_sculpt_brush.cc
curves_sculpt_comb.cc
curves_sculpt_delete.cc
+ curves_sculpt_density.cc
curves_sculpt_grow_shrink.cc
curves_sculpt_ops.cc
+ curves_sculpt_pinch.cc
+ curves_sculpt_puff.cc
curves_sculpt_selection.cc
curves_sculpt_selection_paint.cc
+ curves_sculpt_slide.cc
+ curves_sculpt_smooth.cc
curves_sculpt_snake_hook.cc
paint_canvas.cc
paint_cursor.c
@@ -52,8 +56,7 @@ set(SRC
paint_stroke.c
paint_utils.c
paint_vertex.cc
- paint_vertex_color_ops.c
- paint_vertex_color_utils.c
+ paint_vertex_color_ops.cc
paint_vertex_proj.c
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index f013fa05f4c..b5d739ae08e 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -22,9 +22,11 @@
#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -38,10 +40,14 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "GEO_add_curves_on_mesh.hh"
+
#include "WM_api.h"
+#include "DEG_depsgraph_query.h"
+
/**
- * The code below uses a prefix naming convention to indicate the coordinate space:
+ * The code below uses a suffix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
* su: Local space of the surface object.
* wo: World space.
@@ -70,16 +76,6 @@ class AddOperation : public CurvesSculptStrokeOperation {
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
-static void initialize_straight_curve_positions(const float3 &p1,
- const float3 &p2,
- MutableSpan<float3> r_positions)
-{
- const float step = 1.0f / (float)(r_positions.size() - 1);
- for (const int i : r_positions.index_range()) {
- r_positions[i] = math::interpolate(p1, p2, i * step);
- }
-}
-
/**
* Utility class that actually executes the update when the stroke is updated. That's useful
* because it avoids passing a very large number of parameters between functions.
@@ -88,60 +84,28 @@ struct AddOperationExecutor {
AddOperation *self_ = nullptr;
CurvesSculptCommonContext ctx_;
- Object *object_ = nullptr;
- Curves *curves_id_ = nullptr;
- CurvesGeometry *curves_ = nullptr;
+ Object *curves_ob_orig_ = nullptr;
+ Curves *curves_id_orig_ = nullptr;
+ CurvesGeometry *curves_orig_ = nullptr;
- Object *surface_ob_ = nullptr;
- Mesh *surface_ = nullptr;
- Span<MLoopTri> surface_looptris_;
- Span<float3> corner_normals_su_;
- VArray_Span<float2> surface_uv_map_;
+ Object *surface_ob_eval_ = nullptr;
+ Mesh *surface_eval_ = nullptr;
+ Span<MVert> surface_verts_eval_;
+ Span<MLoop> surface_loops_eval_;
+ Span<MLoopTri> surface_looptris_eval_;
+ VArraySpan<float2> surface_uv_map_eval_;
+ BVHTreeFromMesh surface_bvh_eval_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
const BrushCurvesSculptSettings *brush_settings_ = nullptr;
+ int add_amount_;
+ bool use_front_face_;
float brush_radius_re_;
float2 brush_pos_re_;
- bool use_front_face_;
- bool interpolate_length_;
- bool interpolate_shape_;
- bool interpolate_point_count_;
- bool use_interpolation_;
- float new_curve_length_;
- int add_amount_;
- int constant_points_per_curve_;
-
- /** Various matrices to convert between coordinate spaces. */
- float4x4 curves_to_world_mat_;
- float4x4 curves_to_surface_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 world_to_surface_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 surface_to_curves_mat_;
- float4x4 surface_to_curves_normal_mat_;
-
- BVHTreeFromMesh surface_bvh_;
-
- int tot_old_curves_;
- int tot_old_points_;
-
- struct AddedPoints {
- Vector<float3> positions_cu;
- Vector<float3> bary_coords;
- Vector<int> looptri_indices;
- };
-
- struct NeighborInfo {
- /* Curve index of the neighbor. */
- int index;
- /* The weights of all neighbors of a new curve add up to 1. */
- float weight;
- };
- static constexpr int max_neighbors = 5;
- using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+ CurvesSurfaceTransforms transforms_;
AddOperationExecutor(const bContext &C) : ctx_(C)
{
@@ -150,32 +114,40 @@ struct AddOperationExecutor {
void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
self_ = &self;
- object_ = CTX_data_active_object(&C);
+ curves_ob_orig_ = CTX_data_active_object(&C);
- curves_id_ = static_cast<Curves *>(object_->data);
- curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data);
+ curves_orig_ = &CurvesGeometry::wrap(curves_id_orig_->geometry);
- if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) {
+ if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) {
+ report_missing_surface(stroke_extension.reports);
return;
}
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
- surface_ob_ = curves_id_->surface;
- surface_ = static_cast<Mesh *>(surface_ob_->data);
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_;
- surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed();
- curves_to_surface_mat_ = world_to_surface_mat_ * curves_to_world_mat_;
+ Object &surface_ob_orig = *curves_id_orig_->surface;
+ Mesh &surface_orig = *static_cast<Mesh *>(surface_ob_orig.data);
+ if (surface_orig.totpoly == 0) {
+ report_empty_original_surface(stroke_extension.reports);
+ return;
+ }
- if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(surface_);
+ surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, &surface_ob_orig);
+ if (surface_ob_eval_ == nullptr) {
+ return;
}
- corner_normals_su_ = {
- reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
- surface_->totloop};
+ surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_);
+ if (surface_eval_->totpoly == 0) {
+ report_empty_evaluated_surface(stroke_extension.reports);
+ return;
+ }
+ surface_verts_eval_ = surface_eval_->verts();
+ surface_loops_eval_ = surface_eval_->loops();
+ surface_looptris_eval_ = {BKE_mesh_runtime_looptri_ensure(surface_eval_),
+ BKE_mesh_runtime_looptri_len(surface_eval_)};
+ BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
@@ -187,109 +159,120 @@ struct AddOperationExecutor {
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
- constant_points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
- interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
- interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
- interpolate_point_count_ = brush_settings_->flag &
- BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
- use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_;
- new_curve_length_ = brush_settings_->curve_length;
-
- tot_old_curves_ = curves_->curves_num();
- tot_old_points_ = curves_->points_num();
if (add_amount_ == 0) {
return;
}
+ /* Find UV map. */
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id_orig_->surface_uv_map != nullptr) {
+ surface_uv_map = surface_orig.attributes().lookup<float2>(curves_id_orig_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
+ surface_uv_map_eval_ = surface_eval_->attributes().lookup<float2>(
+ curves_id_orig_->surface_uv_map, ATTR_DOMAIN_CORNER);
+ }
+
+ if (surface_uv_map.is_empty()) {
+ report_missing_uv_map_on_original_surface(stroke_extension.reports);
+ return;
+ }
+ if (surface_uv_map_eval_.is_empty()) {
+ report_missing_uv_map_on_evaluated_surface(stroke_extension.reports);
+ return;
+ }
+
const double time = PIL_check_seconds_timer() * 1000000.0;
/* Use a pointer cast to avoid overflow warnings. */
RandomNumberGenerator rng{*(uint32_t *)(&time)};
- BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
- BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
-
- surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
- BKE_mesh_runtime_looptri_len(surface_)};
-
- if (curves_id_->surface_uv_map != nullptr) {
- MeshComponent surface_component;
- surface_component.replace(surface_, GeometryOwnershipType::ReadOnly);
- surface_uv_map_ = surface_component
- .attribute_try_get_for_read(curves_id_->surface_uv_map,
- ATTR_DOMAIN_CORNER)
- .typed<float2>();
- }
-
/* Sample points on the surface using one of multiple strategies. */
- AddedPoints added_points;
+ Vector<float2> sampled_uvs;
if (add_amount_ == 1) {
- this->sample_in_center_with_symmetry(added_points);
+ this->sample_in_center_with_symmetry(sampled_uvs);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- this->sample_projected_with_symmetry(rng, added_points);
+ this->sample_projected_with_symmetry(rng, sampled_uvs);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->sample_spherical_with_symmetry(rng, added_points);
+ this->sample_spherical_with_symmetry(rng, sampled_uvs);
}
else {
BLI_assert_unreachable();
}
- if (added_points.bary_coords.is_empty()) {
+ if (sampled_uvs.is_empty()) {
/* No new points have been added. */
return;
}
- Array<NeighborsVector> neighbors_per_curve;
- if (use_interpolation_) {
- this->ensure_curve_roots_kdtree();
- neighbors_per_curve = this->find_curve_neighbors(added_points);
- }
+ const Span<MLoopTri> surface_looptris_orig = {BKE_mesh_runtime_looptri_ensure(&surface_orig),
+ BKE_mesh_runtime_looptri_len(&surface_orig)};
- /* Resize to add the new curves, building the offsets in the array owned by the curves. */
- const int tot_added_curves = added_points.bary_coords.size();
- curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves);
- if (interpolate_point_count_) {
- this->initialize_curve_offsets_with_interpolation(neighbors_per_curve);
+ /* Find normals. */
+ if (!CustomData_has_layer(&surface_orig.ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(&surface_orig);
}
- else {
- this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_);
+ const Span<float3> corner_normals_su = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig.ldata, CD_NORMAL)),
+ surface_orig.totloop};
+
+ const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
+
+ geometry::AddCurvesOnMeshInputs add_inputs;
+ add_inputs.uvs = sampled_uvs;
+ add_inputs.interpolate_length = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ add_inputs.interpolate_shape = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_inputs.interpolate_point_count = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ add_inputs.fallback_curve_length = brush_settings_->curve_length;
+ add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
+ add_inputs.transforms = &transforms_;
+ add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
+ add_inputs.surface = &surface_orig;
+ add_inputs.corner_normals_su = corner_normals_su;
+
+ if (add_inputs.interpolate_length || add_inputs.interpolate_shape ||
+ add_inputs.interpolate_point_count) {
+ this->ensure_curve_roots_kdtree();
+ add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
}
- /* Resize to add the correct point count calculated as part of building the offsets. */
- curves_->resize(curves_->offsets().last(), curves_->curves_num());
+ const geometry::AddCurvesOnMeshOutputs add_outputs = geometry::add_curves_on_mesh(
+ *curves_orig_, add_inputs);
- this->initialize_attributes(added_points, neighbors_per_curve);
-
- curves_->update_curve_types();
+ if (add_outputs.uv_error) {
+ report_invalid_uv_map(stroke_extension.reports);
+ }
- DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_orig_->id);
ED_region_tag_redraw(ctx_.region);
}
/**
* Sample a single point exactly at the mouse position.
*/
- void sample_in_center_with_symmetry(AddedPoints &r_added_points)
+ void sample_in_center_with_symmetry(Vector<float2> &r_sampled_uvs)
{
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_cu = world_to_curves_mat_ * ray_start_wo;
- const float3 ray_end_cu = world_to_curves_mat_ * ray_end_wo;
+ const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo;
+ const float3 ray_end_cu = transforms_.world_to_curves * ray_end_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
- eCurvesSymmetryType(curves_id_->symmetry));
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- const float4x4 transform = curves_to_surface_mat_ * brush_transform;
- this->sample_in_center(r_added_points, transform * ray_start_cu, transform * ray_end_cu);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+ this->sample_in_center(r_sampled_uvs, transform * ray_start_cu, transform * ray_end_cu);
}
}
- void sample_in_center(AddedPoints &r_added_points,
+ void sample_in_center(Vector<float2> &r_sampled_uvs,
const float3 &ray_start_su,
const float3 &ray_end_su)
{
@@ -298,204 +281,165 @@ struct AddOperationExecutor {
BVHTreeRayHit ray_hit;
ray_hit.dist = FLT_MAX;
ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
+ BLI_bvhtree_ray_cast(surface_bvh_eval_.tree,
ray_start_su,
ray_direction_su,
0.0f,
&ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
+ surface_bvh_eval_.raycast_callback,
+ &surface_bvh_eval_);
if (ray_hit.index == -1) {
return;
}
const int looptri_index = ray_hit.index;
+ const MLoopTri &looptri = surface_looptris_eval_[looptri_index];
const float3 brush_pos_su = ray_hit.co;
- const float3 bary_coords = compute_bary_coord_in_triangle(
- *surface_, surface_looptris_[looptri_index], brush_pos_su);
+ const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
+ surface_verts_eval_, surface_loops_eval_, looptri, brush_pos_su);
- const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su;
-
- r_added_points.positions_cu.append(brush_pos_cu);
- r_added_points.bary_coords.append(bary_coords);
- r_added_points.looptri_indices.append(looptri_index);
+ const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
+ bary_coords, looptri, surface_uv_map_eval_);
+ r_sampled_uvs.append(uv);
}
/**
* Sample points by shooting rays within the brush radius in the 3D view.
*/
- void sample_projected_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ void sample_projected_with_symmetry(RandomNumberGenerator &rng, Vector<float2> &r_sampled_uvs)
{
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
- eCurvesSymmetryType(curves_id_->symmetry));
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->sample_projected(rng, r_added_points, brush_transform);
+ this->sample_projected(rng, r_sampled_uvs, brush_transform);
}
}
void sample_projected(RandomNumberGenerator &rng,
- AddedPoints &r_added_points,
+ Vector<float2> &r_sampled_uvs,
const float4x4 &brush_transform)
{
- const int old_amount = r_added_points.bary_coords.size();
- const int max_iterations = std::max(100'000, add_amount_ * 10);
+ const int old_amount = r_sampled_uvs.size();
+ const int max_iterations = 100;
int current_iteration = 0;
- while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
+ while (r_sampled_uvs.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
-
- const float r = brush_radius_re_ * std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle));
-
- float3 ray_start_wo, ray_end_wo;
- ED_view3d_win_to_segment_clipped(
- ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_cu = brush_transform * (world_to_curves_mat_ * ray_start_wo);
- const float3 ray_end_cu = brush_transform * (world_to_curves_mat_ * ray_end_wo);
-
- const float3 ray_start_su = curves_to_surface_mat_ * ray_start_cu;
- const float3 ray_end_su = curves_to_surface_mat_ * ray_end_cu;
- const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
-
- BVHTreeRayHit ray_hit;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- ray_start_su,
- ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- continue;
- }
-
- if (use_front_face_) {
- const float3 normal_su = ray_hit.no;
- if (math::dot(ray_direction_su, normal_su) >= 0.0f) {
- continue;
- }
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+ Vector<float3> positions_su;
+
+ const int missing_amount = add_amount_ + old_amount - r_sampled_uvs.size();
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
+ rng,
+ *surface_eval_,
+ surface_bvh_eval_,
+ brush_pos_re_,
+ brush_radius_re_,
+ [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
+ float3 start_wo, end_wo;
+ ED_view3d_win_to_segment_clipped(
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
+ const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo);
+ const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo);
+ r_start_su = transforms_.curves_to_surface * start_cu;
+ r_end_su = transforms_.curves_to_surface * end_cu;
+ },
+ use_front_face_,
+ add_amount_,
+ missing_amount,
+ bary_coords,
+ looptri_indices,
+ positions_su);
+
+ for (const int i : IndexRange(new_points)) {
+ const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
+ bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
+ r_sampled_uvs.append(uv);
}
-
- const int looptri_index = ray_hit.index;
- const float3 pos_su = ray_hit.co;
-
- const float3 bary_coords = compute_bary_coord_in_triangle(
- *surface_, surface_looptris_[looptri_index], pos_su);
-
- const float3 pos_cu = surface_to_curves_mat_ * pos_su;
-
- r_added_points.positions_cu.append(pos_cu);
- r_added_points.bary_coords.append(bary_coords);
- r_added_points.looptri_indices.append(looptri_index);
}
}
/**
* Sample points in a 3D sphere around the surface position that the mouse hovers over.
*/
- void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ void sample_spherical_with_symmetry(RandomNumberGenerator &rng, Vector<float2> &r_sampled_uvs)
{
- /* Find ray that starts in the center of the brush. */
- float3 brush_ray_start_wo, brush_ray_end_wo;
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_eval_,
+ brush_pos_re_,
+ brush_radius_re_);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ float3 view_ray_start_wo, view_ray_end_wo;
ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
ctx_.region,
ctx_.v3d,
brush_pos_re_,
- brush_ray_start_wo,
- brush_ray_end_wo,
+ view_ray_start_wo,
+ view_ray_end_wo,
true);
- const float3 brush_ray_start_cu = world_to_curves_mat_ * brush_ray_start_wo;
- const float3 brush_ray_end_cu = world_to_curves_mat_ * brush_ray_end_wo;
- /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
- * in 3D. */
- float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
- ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
- ctx_.region,
- ctx_.v3d,
- brush_pos_re_ + float2(brush_radius_re_, 0),
- brush_radius_ray_start_wo,
- brush_radius_ray_end_wo,
- true);
- const float3 brush_radius_ray_start_cu = world_to_curves_mat_ * brush_radius_ray_start_wo;
- const float3 brush_radius_ray_end_cu = world_to_curves_mat_ * brush_radius_ray_end_wo;
+ const float3 view_ray_start_cu = transforms_.world_to_curves * view_ray_start_wo;
+ const float3 view_ray_end_cu = transforms_.world_to_curves * view_ray_end_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
- eCurvesSymmetryType(curves_id_->symmetry));
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- const float4x4 transform = curves_to_surface_mat_ * brush_transform;
- this->sample_spherical(rng,
- r_added_points,
- transform * brush_ray_start_cu,
- transform * brush_ray_end_cu,
- transform * brush_radius_ray_start_cu,
- transform * brush_radius_ray_end_cu);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+
+ const float3 brush_pos_su = transform * brush_3d->position_cu;
+ const float3 view_direction_su = math::normalize(transform * view_ray_end_cu -
+ transform * view_ray_start_cu);
+ const float brush_radius_su = transform_brush_radius(
+ transform, brush_3d->position_cu, brush_3d->radius_cu);
+
+ this->sample_spherical(rng, r_sampled_uvs, brush_pos_su, brush_radius_su, view_direction_su);
}
}
void sample_spherical(RandomNumberGenerator &rng,
- AddedPoints &r_added_points,
- const float3 &brush_ray_start_su,
- const float3 &brush_ray_end_su,
- const float3 &brush_radius_ray_start_su,
- const float3 &brush_radius_ray_end_su)
+ Vector<float2> &r_sampled_uvs,
+ const float3 &brush_pos_su,
+ const float brush_radius_su,
+ const float3 &view_direction_su)
{
- const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
-
- BVHTreeRayHit ray_hit;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- brush_ray_start_su,
- brush_ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- return;
- }
-
- /* Compute brush radius. */
- const float3 brush_pos_su = ray_hit.co;
- const float brush_radius_su = dist_to_line_v3(
- brush_pos_su, brush_radius_ray_start_su, brush_radius_ray_end_su);
const float brush_radius_sq_su = pow2f(brush_radius_su);
/* Find surface triangles within brush radius. */
- Vector<int> looptri_indices;
+ Vector<int> selected_looptri_indices;
if (use_front_face_) {
BLI_bvhtree_range_query_cpp(
- *surface_bvh_.tree,
+ *surface_bvh_eval_.tree,
brush_pos_su,
brush_radius_su,
[&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
- const MLoopTri &looptri = surface_looptris_[index];
- const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
- const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
- const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
+ const MLoopTri &looptri = surface_looptris_eval_[index];
+ const float3 v0_su = surface_verts_eval_[surface_loops_eval_[looptri.tri[0]].v].co;
+ const float3 v1_su = surface_verts_eval_[surface_loops_eval_[looptri.tri[1]].v].co;
+ const float3 v2_su = surface_verts_eval_[surface_loops_eval_[looptri.tri[2]].v].co;
float3 normal_su;
normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
- if (math::dot(normal_su, brush_ray_direction_su) >= 0.0f) {
+ if (math::dot(normal_su, view_direction_su) >= 0.0f) {
return;
}
- looptri_indices.append(index);
+ selected_looptri_indices.append(index);
});
}
else {
BLI_bvhtree_range_query_cpp(
- *surface_bvh_.tree,
+ *surface_bvh_eval_.tree,
brush_pos_su,
brush_radius_su,
[&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
- looptri_indices.append(index);
+ selected_looptri_indices.append(index);
});
}
@@ -505,420 +449,54 @@ struct AddOperationExecutor {
const float brush_plane_area_su = M_PI * brush_radius_sq_su;
const float approximate_density_su = add_amount_ / brush_plane_area_su;
- /* Used for switching between two triangle sampling strategies. */
- const float area_threshold = brush_plane_area_su;
-
/* Usually one or two iterations should be enough. */
const int max_iterations = 5;
int current_iteration = 0;
- const int old_amount = r_added_points.bary_coords.size();
- while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
+ const int old_amount = r_sampled_uvs.size();
+ while (r_sampled_uvs.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
-
- for (const int looptri_index : looptri_indices) {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
-
- const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
- const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
- const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
-
- const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su);
-
- if (looptri_area_su < area_threshold) {
- /* The triangle is small compared to the brush radius. Sample by generating random
- * barycentric coordinates. */
- const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su);
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float3 bary_coord = rng.get_barycentric_coordinates();
- const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su);
- const float distance_to_brush_sq_su = math::distance_squared(point_pos_su,
- brush_pos_su);
- if (distance_to_brush_sq_su > brush_radius_sq_su) {
- continue;
- }
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
- else {
- /* The triangle is large compared to the brush radius. Sample by generating random points
- * on the triangle plane within the brush radius. */
- float3 normal_su;
- normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
-
- float3 brush_pos_proj_su = brush_pos_su;
- project_v3_plane(brush_pos_proj_su, normal_su, v0_su);
-
- const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su,
- brush_pos_su);
- const float brush_radius_factor_sq = 1.0f -
- std::min(1.0f,
- proj_distance_sq_su / brush_radius_sq_su);
- const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq;
- const float radius_proj_su = std::sqrt(radius_proj_sq_su);
- const float circle_area_su = M_PI * radius_proj_su;
-
- const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su);
-
- const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su;
- const float3 axis_2_su = math::normalize(math::cross(
- axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) *
- radius_proj_su;
-
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float r = std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float x = r * std::cos(angle);
- const float y = r * std::sin(angle);
- const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y;
- if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) {
- /* Sampled point is not in the triangle. */
- continue;
- }
-
- float3 bary_coord;
- interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su);
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+ Vector<float3> positions_su;
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
+ rng,
+ *surface_eval_,
+ selected_looptri_indices,
+ brush_pos_su,
+ brush_radius_su,
+ approximate_density_su,
+ bary_coords,
+ looptri_indices,
+ positions_su);
+ for (const int i : IndexRange(new_points)) {
+ const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
+ bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
+ r_sampled_uvs.append(uv);
}
}
/* Remove samples when there are too many. */
- while (r_added_points.bary_coords.size() > old_amount + add_amount_) {
+ while (r_sampled_uvs.size() > old_amount + add_amount_) {
const int index_to_remove = rng.get_int32(add_amount_) + old_amount;
- r_added_points.bary_coords.remove_and_reorder(index_to_remove);
- r_added_points.looptri_indices.remove_and_reorder(index_to_remove);
- r_added_points.positions_cu.remove_and_reorder(index_to_remove);
+ r_sampled_uvs.remove_and_reorder(index_to_remove);
}
}
void ensure_curve_roots_kdtree()
{
if (self_->curve_roots_kdtree_ == nullptr) {
- self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_->curves_num());
- for (const int curve_i : curves_->curves_range()) {
- const int root_point_i = curves_->offsets()[curve_i];
- const float3 &root_pos_cu = curves_->positions()[root_point_i];
+ self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_orig_->curves_num());
+ for (const int curve_i : curves_orig_->curves_range()) {
+ const int root_point_i = curves_orig_->offsets()[curve_i];
+ const float3 &root_pos_cu = curves_orig_->positions()[root_point_i];
BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu);
}
BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
}
}
-
- void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve)
- {
- MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
-
- attribute_math::DefaultMixer<int> mixer{new_offsets};
- threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) {
- for (const int i : curves_range) {
- if (neighbors_per_curve[i].is_empty()) {
- mixer.mix_in(i, constant_points_per_curve_, 1.0f);
- }
- else {
- for (const NeighborInfo &neighbor : neighbors_per_curve[i]) {
- const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size();
- mixer.mix_in(i, neighbor_points_num, neighbor.weight);
- }
- }
- }
- });
- mixer.finalize();
-
- bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_);
- }
-
- void initialize_curve_offsets_without_interpolation(const int points_per_curve)
- {
- MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
- int offset = tot_old_points_;
- for (const int i : new_offsets.index_range()) {
- new_offsets[i] = offset;
- offset += points_per_curve;
- }
- }
-
- void initialize_attributes(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve)
- {
- Array<float> new_lengths_cu(added_points.bary_coords.size());
- if (interpolate_length_) {
- this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
- }
- else {
- new_lengths_cu.fill(new_curve_length_);
- }
-
- Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points);
- if (!surface_uv_map_.is_empty()) {
- this->initialize_surface_attachment(added_points);
- }
-
- this->fill_new_selection();
-
- if (interpolate_shape_) {
- this->initialize_position_with_interpolation(
- added_points, neighbors_per_curve, new_normals_su, new_lengths_cu);
- }
- else {
- this->initialize_position_without_interpolation(
- added_points, new_lengths_cu, new_normals_su);
- }
- }
-
- /**
- * Select newly created points or curves in new curves if necessary.
- */
- void fill_new_selection()
- {
- switch (curves_id_->selection_domain) {
- case ATTR_DOMAIN_CURVE: {
- const VArray<float> selection = curves_->selection_curve_float();
- if (selection.is_single() && selection.get_internal_single() >= 1.0f) {
- return;
- }
- curves_->selection_curve_float_for_write().drop_front(tot_old_curves_).fill(1.0f);
- break;
- }
- case ATTR_DOMAIN_POINT: {
- const VArray<float> selection = curves_->selection_point_float();
- if (selection.is_single() && selection.get_internal_single() >= 1.0f) {
- return;
- }
- curves_->selection_point_float_for_write().drop_front(tot_old_points_).fill(1.0f);
- break;
- }
- default:
- BLI_assert_unreachable();
- }
- }
-
- Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points)
- {
- const int tot_added_curves = added_points.bary_coords.size();
- Array<NeighborsVector> neighbors_per_curve(tot_added_curves);
- threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
- for (const int i : range) {
- const float3 root_cu = added_points.positions_cu[i];
- std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
- const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
- self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors);
- float tot_weight = 0.0f;
- for (const int neighbor_i : IndexRange(found_neighbors)) {
- KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
- const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
- tot_weight += weight;
- neighbors_per_curve[i].append({nearest.index, weight});
- }
- /* Normalize weights. */
- for (NeighborInfo &neighbor : neighbors_per_curve[i]) {
- neighbor.weight /= tot_weight;
- }
- }
- });
- return neighbors_per_curve;
- }
-
- void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve,
- MutableSpan<float> r_lengths)
- {
- const Span<float3> positions_cu = curves_->positions();
-
- threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) {
- for (const int added_curve_i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i];
- float length_sum = 0.0f;
- for (const NeighborInfo &neighbor : neighbors) {
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index);
- float neighbor_length = 0.0f;
- for (const int segment_i : neighbor_points.drop_back(1)) {
- const float3 &p1 = positions_cu[segment_i];
- const float3 &p2 = positions_cu[segment_i + 1];
- neighbor_length += math::distance(p1, p2);
- }
- length_sum += neighbor.weight * neighbor_length;
- }
- const float length = neighbors.is_empty() ? new_curve_length_ : length_sum;
- r_lengths[added_curve_i] = length;
- }
- });
- }
-
- float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord)
- {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
- const int l0 = looptri.tri[0];
- const int l1 = looptri.tri[1];
- const int l2 = looptri.tri[2];
-
- const float3 &l0_normal_su = corner_normals_su_[l0];
- const float3 &l1_normal_su = corner_normals_su_[l1];
- const float3 &l2_normal_su = corner_normals_su_[l2];
-
- const float3 normal_su = math::normalize(
- attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su));
- return normal_su;
- }
-
- Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points)
- {
- Array<float3> normals_su(added_points.bary_coords.size());
- threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const int looptri_index = added_points.looptri_indices[i];
- const float3 &bary_coord = added_points.bary_coords[i];
- normals_su[i] = compute_surface_point_normal(
- surface_looptris_[looptri_index], bary_coord, corner_normals_su_);
- }
- });
- return normals_su;
- }
-
- void initialize_surface_attachment(const AddedPoints &added_points)
- {
- MutableSpan<float2> surface_uv_coords = curves_->surface_uv_coords_for_write();
- threading::parallel_for(
- added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int curve_i = tot_old_curves_ + i;
- const MLoopTri &looptri = surface_looptris_[added_points.looptri_indices[i]];
- const float2 &uv0 = surface_uv_map_[looptri.tri[0]];
- const float2 &uv1 = surface_uv_map_[looptri.tri[1]];
- const float2 &uv2 = surface_uv_map_[looptri.tri[2]];
- const float3 &bary_coords = added_points.bary_coords[i];
- const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
- surface_uv_coords[curve_i] = uv;
- }
- });
- }
-
- /**
- * Initialize new curves so that they are just a straight line in the normal direction.
- */
- void initialize_position_without_interpolation(const AddedPoints &added_points,
- const Span<float> lengths_cu,
- const MutableSpan<float3> normals_su)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
- const float3 &root_cu = added_points.positions_cu[i];
- const float length = lengths_cu[i];
- const float3 &normal_su = normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
- const float3 tip_cu = root_cu + length * normal_cu;
-
- initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
- }
- });
- }
-
- /**
- * Use neighboring curves to determine the shape.
- */
- void initialize_position_with_interpolation(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve,
- const Span<float3> new_normals_su,
- const Span<float> new_lengths_cu)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
- const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
-
- const float length_cu = new_lengths_cu[i];
- const float3 &normal_su = new_normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
-
- const float3 &root_cu = added_points.positions_cu[i];
-
- if (neighbors.is_empty()) {
- /* If there are no neighbors, just make a straight line. */
- const float3 tip_cu = root_cu + length_cu * normal_cu;
- initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
- continue;
- }
-
- positions_cu.slice(points).fill(root_cu);
-
- for (const NeighborInfo &neighbor : neighbors) {
- const int neighbor_curve_i = neighbor.index;
- const float3 &neighbor_first_pos_cu =
- positions_cu[curves_->offsets()[neighbor_curve_i]];
- const float3 neighbor_first_pos_su = curves_to_surface_mat_ * neighbor_first_pos_cu;
-
- BVHTreeNearest nearest;
- nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(surface_bvh_.tree,
- neighbor_first_pos_su,
- &nearest,
- surface_bvh_.nearest_callback,
- &surface_bvh_);
- const int neighbor_looptri_index = nearest.index;
- const MLoopTri &neighbor_looptri = surface_looptris_[neighbor_looptri_index];
-
- const float3 neighbor_bary_coord = compute_bary_coord_in_triangle(
- *surface_, neighbor_looptri, nearest.co);
-
- const float3 neighbor_normal_su = compute_surface_point_normal(
- surface_looptris_[neighbor_looptri_index],
- neighbor_bary_coord,
- corner_normals_su_);
- const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ *
- neighbor_normal_su);
-
- /* The rotation matrix used to transform relative coordinates of the neighbor curve
- * to the new curve. */
- float normal_rotation_cu[3][3];
- rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
-
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i);
- const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
-
- /* Use a temporary #PolySpline, because that's the easiest way to resample an
- * existing curve right now. Resampling is necessary if the length of the new curve
- * does not match the length of the neighbors or the number of handle points is
- * different. */
- PolySpline neighbor_spline;
- neighbor_spline.resize(neighbor_points.size());
- neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
- neighbor_spline.mark_cache_invalid();
-
- const float neighbor_length_cu = neighbor_spline.length();
- const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
-
- const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
- for (const int j : IndexRange(points.size())) {
- const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
- j * resample_factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- neighbor_spline.sample_with_index_factors<float3>(
- neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
- const float3 relative_coord = p - neighbor_root_cu;
- float3 rotated_relative_coord = relative_coord;
- mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
- positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
- }
- }
- }
- });
- }
};
void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
@@ -927,17 +505,8 @@ void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &
executor.execute(*this, C, stroke_extension);
}
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(const bContext &C,
- ReportList *reports)
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation()
{
- const Object &ob_active = *CTX_data_active_object(&C);
- BLI_assert(ob_active.type == OB_CURVES);
- const Curves &curves_id = *static_cast<Curves *>(ob_active.data);
- if (curves_id.surface == nullptr || curves_id.surface->type != OB_MESH) {
- BKE_report(reports, RPT_WARNING, "Can not use Add brush when there is no surface mesh");
- return {};
- }
-
return std::make_unique<AddOperation>();
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 7e583773512..95261f29914 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -8,8 +8,9 @@
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
-
-#include "DNA_meshdata_types.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
#include "ED_view3d.h"
@@ -22,6 +23,10 @@
#include "BLI_length_parameterize.hh"
#include "BLI_task.hh"
+#include "DEG_depsgraph_query.h"
+
+#include "BLT_translation.h"
+
/**
* The code below uses a prefix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
@@ -50,7 +55,8 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
const float brush_radius_re,
const ARegion &region,
const RegionView3D &rv3d,
- const Object &object)
+ const Object &object,
+ const Span<float3> positions)
{
/* This value might have to be adjusted based on user feedback. */
const float brush_inner_radius_re = std::min<float>(brush_radius_re, (float)UI_UNIT_X / 3.0f);
@@ -90,8 +96,6 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
}
};
- const Span<float3> positions = curves.positions();
-
BrushPositionCandidate best_candidate = threading::parallel_reduce(
curves.curves_range(),
128,
@@ -177,20 +181,21 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
{
const Curves &curves_id = *static_cast<Curves *>(curves_object.data);
const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- const Object *surface_object = curves_id.surface;
+ Object *surface_object = curves_id.surface;
+ Object *surface_object_eval = DEG_get_evaluated_object(&depsgraph, surface_object);
float3 center_ray_start_wo, center_ray_end_wo;
ED_view3d_win_to_segment_clipped(
&depsgraph, &region, &v3d, brush_pos_re, center_ray_start_wo, center_ray_end_wo, true);
/* Shorten ray when the surface object is hit. */
- if (surface_object != nullptr) {
+ if (surface_object_eval != nullptr) {
const float4x4 surface_to_world_mat = surface_object->obmat;
const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
- Mesh &surface = *static_cast<Mesh *>(surface_object->data);
+ Mesh *surface_eval = BKE_object_get_evaluated_mesh(surface_object_eval);
BVHTreeFromMesh surface_bvh;
- BKE_bvhtree_from_mesh_get(&surface_bvh, &surface, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&surface_bvh, surface_eval, BVHTREE_FROM_LOOPTRI, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
const float3 center_ray_start_su = world_to_surface_mat * center_ray_start_wo;
@@ -224,6 +229,9 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
const float3 center_ray_start_cu = world_to_curves_mat * center_ray_start_wo;
const float3 center_ray_end_cu = world_to_curves_mat * center_ray_end_wo;
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(depsgraph, curves_object);
+
const std::optional<float3> brush_position_optional_cu = find_curves_brush_position(
curves,
center_ray_start_cu,
@@ -231,7 +239,8 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
brush_radius_re,
region,
rv3d,
- curves_object);
+ curves_object,
+ deformation.positions);
if (!brush_position_optional_cu.has_value()) {
/* Nothing found. */
return std::nullopt;
@@ -256,6 +265,55 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
return brush_3d;
}
+std::optional<CurvesBrush3D> sample_curves_surface_3d_brush(
+ const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const CurvesSurfaceTransforms &transforms,
+ const BVHTreeFromMesh &surface_bvh,
+ const float2 &brush_pos_re,
+ const float brush_radius_re)
+{
+ float3 brush_ray_start_wo, brush_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ &depsgraph, &region, &v3d, brush_pos_re, brush_ray_start_wo, brush_ray_end_wo, true);
+ const float3 brush_ray_start_su = transforms.world_to_surface * brush_ray_start_wo;
+ const float3 brush_ray_end_su = transforms.world_to_surface * brush_ray_end_wo;
+
+ const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh.tree,
+ brush_ray_start_su,
+ brush_ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh.raycast_callback,
+ const_cast<void *>(static_cast<const void *>(&surface_bvh)));
+ if (ray_hit.index == -1) {
+ return std::nullopt;
+ }
+
+ float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(&depsgraph,
+ &region,
+ &v3d,
+ brush_pos_re + float2(brush_radius_re, 0),
+ brush_radius_ray_start_wo,
+ brush_radius_ray_end_wo,
+ true);
+ const float3 brush_radius_ray_start_cu = transforms.world_to_curves * brush_radius_ray_start_wo;
+ const float3 brush_radius_ray_end_cu = transforms.world_to_curves * brush_radius_ray_end_wo;
+
+ const float3 brush_pos_su = ray_hit.co;
+ const float3 brush_pos_cu = transforms.surface_to_curves * brush_pos_su;
+ const float brush_radius_cu = dist_to_line_v3(
+ brush_pos_cu, brush_radius_ray_start_cu, brush_radius_ray_end_cu);
+ return CurvesBrush3D{brush_pos_cu, brush_radius_cu};
+}
+
Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
{
Vector<float4x4> matrices;
@@ -284,11 +342,21 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr
return matrices;
}
+float transform_brush_radius(const float4x4 &transform,
+ const float3 &brush_position,
+ const float old_radius)
+{
+ const float3 offset_position = brush_position + float3(old_radius, 0.0f, 0.0f);
+ const float3 new_position = transform * brush_position;
+ const float3 new_offset_position = transform * offset_position;
+ return math::distance(new_position, new_offset_position);
+}
+
void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position)
{
/* Find the accumulated length of each point in the original curve,
* treating it as a poly curve for performance reasons and simplicity. */
- Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false));
+ Array<float> orig_lengths(length_parameterize::segments_num(positions.size(), false));
length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
const float orig_total_length = orig_lengths.last();
@@ -306,11 +374,10 @@ void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &n
Array<int> indices(positions.size() - 1);
Array<float> factors(positions.size() - 1);
- length_parameterize::create_samples_from_sorted_lengths(
- orig_lengths, new_lengths, false, indices, factors);
+ length_parameterize::sample_at_lengths(orig_lengths, new_lengths, indices, factors);
Array<float3> new_positions(positions.size() - 1);
- length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
+ length_parameterize::interpolate<float3>(positions, indices, factors, new_positions);
positions.drop_back(1).copy_from(new_positions);
positions.last() = new_last_position;
}
@@ -324,33 +391,36 @@ CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C)
this->rv3d = CTX_wm_region_view3d(&C);
}
-float3 compute_surface_point_normal(const MLoopTri &looptri,
- const float3 &bary_coord,
- const Span<float3> corner_normals)
+void report_empty_original_surface(ReportList *reports)
{
- const int l0 = looptri.tri[0];
- const int l1 = looptri.tri[1];
- const int l2 = looptri.tri[2];
+ BKE_report(reports, RPT_WARNING, TIP_("Original surface mesh is empty"));
+}
- const float3 &l0_normal = corner_normals[l0];
- const float3 &l1_normal = corner_normals[l1];
- const float3 &l2_normal = corner_normals[l2];
+void report_empty_evaluated_surface(ReportList *reports)
+{
+ BKE_report(reports, RPT_WARNING, TIP_("Evaluated surface mesh is empty"));
+}
- const float3 normal = math::normalize(
- attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal));
- return normal;
+void report_missing_surface(ReportList *reports)
+{
+ BKE_report(reports, RPT_WARNING, TIP_("Missing surface mesh"));
+}
+
+void report_missing_uv_map_on_original_surface(ReportList *reports)
+{
+ BKE_report(
+ reports, RPT_WARNING, TIP_("Missing UV map for attaching curves on original surface"));
+}
+
+void report_missing_uv_map_on_evaluated_surface(ReportList *reports)
+{
+ BKE_report(
+ reports, RPT_WARNING, TIP_("Missing UV map for attaching curves on evaluated surface"));
}
-float3 compute_bary_coord_in_triangle(const Mesh &mesh,
- const MLoopTri &looptri,
- const float3 &position)
+void report_invalid_uv_map(ReportList *reports)
{
- const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
- const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
- const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
- return bary_coords;
+ BKE_report(reports, RPT_WARNING, TIP_("Invalid UV map: UV islands must not overlap"));
}
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index ae0a512c5ee..52f2ddc6550 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -13,12 +13,15 @@
#include "PIL_time.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "BKE_attribute_math.hh"
#include "BKE_brush.h"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
+#include "BKE_crazyspace.hh"
#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
@@ -88,9 +91,9 @@ struct CombOperationExecutor {
eBrushFalloffShape falloff_shape_;
- Object *object_ = nullptr;
- Curves *curves_id_ = nullptr;
- CurvesGeometry *curves_ = nullptr;
+ Object *curves_ob_orig_ = nullptr;
+ Curves *curves_id_orig_ = nullptr;
+ CurvesGeometry *curves_orig_ = nullptr;
VArray<float> point_factors_;
Vector<int64_t> selected_curve_indices_;
@@ -100,8 +103,7 @@ struct CombOperationExecutor {
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
CombOperationExecutor(const bContext &C) : ctx_(C)
{
@@ -113,7 +115,12 @@ struct CombOperationExecutor {
BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; });
- object_ = CTX_data_active_object(&C);
+ curves_ob_orig_ = CTX_data_active_object(&C);
+ curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data);
+ curves_orig_ = &CurvesGeometry::wrap(curves_id_orig_->geometry);
+ if (curves_orig_->curves_num() == 0) {
+ return;
+ }
curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
@@ -121,19 +128,12 @@ struct CombOperationExecutor {
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
-
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
- curves_id_ = static_cast<Curves *>(object_->data);
- curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
- if (curves_->curves_num() == 0) {
- return;
- }
+ transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
- point_factors_ = get_point_selection(*curves_id_);
- curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+ point_factors_ = get_point_selection(*curves_id_orig_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_orig_, selected_curve_indices_);
brush_pos_prev_re_ = self_->brush_pos_last_re_;
brush_pos_re_ = stroke_extension.mouse_position;
@@ -162,9 +162,9 @@ struct CombOperationExecutor {
this->restore_segment_lengths(changed_curves);
- curves_->tag_positions_changed();
- DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ curves_orig_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_orig_->id);
ED_region_tag_redraw(ctx_.region);
}
@@ -174,7 +174,7 @@ struct CombOperationExecutor {
void comb_projected_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
- eCurvesSymmetryType(curves_id_->symmetry));
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
this->comb_projected(r_changed_curves, brush_transform);
}
@@ -185,10 +185,12 @@ struct CombOperationExecutor {
{
const float4x4 brush_transform_inv = brush_transform.inverted();
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ MutableSpan<float3> positions_cu_orig = curves_orig_->positions_for_write();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
float4x4 projection;
- ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
@@ -197,16 +199,18 @@ struct CombOperationExecutor {
Vector<int> &local_changed_curves = r_changed_curves.local();
for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false;
- const IndexRange points = curves_->points_for_curve(curve_i);
+ const IndexRange points = curves_orig_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
- const float3 old_pos_cu = brush_transform_inv * positions_cu[point_i];
+ const float3 old_pos_cu = deformation.positions[point_i];
+ const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
/* Find the position of the point in screen space. */
- float2 old_pos_re;
- ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
+ float2 old_symm_pos_re;
+ ED_view3d_project_float_v2_m4(
+ ctx_.region, old_symm_pos_cu, old_symm_pos_re, projection.values);
const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2(
- old_pos_re, brush_pos_prev_re_, brush_pos_re_);
+ old_symm_pos_re, brush_pos_prev_re_, brush_pos_re_);
if (distance_to_brush_sq_re > brush_radius_sq_re) {
/* Ignore the point because it's too far away. */
continue;
@@ -221,16 +225,20 @@ struct CombOperationExecutor {
/* Offset the old point position in screen space and transform it back into 3D space.
*/
- const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
- float3 new_position_wo;
+ const float2 new_symm_pos_re = old_symm_pos_re + brush_pos_diff_re_ * weight;
+ float3 new_symm_pos_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * old_pos_cu,
- new_position_re,
- new_position_wo);
- const float3 new_position_cu = brush_transform *
- (world_to_curves_mat_ * new_position_wo);
- positions_cu[point_i] = new_position_cu;
+ transforms_.curves_to_world * old_symm_pos_cu,
+ new_symm_pos_re,
+ new_symm_pos_wo);
+ const float3 new_pos_cu = brush_transform *
+ (transforms_.world_to_curves * new_symm_pos_wo);
+
+ const float3 translation_eval = new_pos_cu - old_pos_cu;
+ const float3 translation_orig = deformation.translation_from_deformed_to_original(
+ point_i, translation_eval);
+ positions_cu_orig[point_i] += translation_orig;
curve_changed = true;
}
@@ -247,26 +255,26 @@ struct CombOperationExecutor {
void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values);
float3 brush_start_wo, brush_end_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
- eCurvesSymmetryType(curves_id_->symmetry));
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
this->comb_spherical(r_changed_curves,
brush_transform * brush_start_cu,
@@ -280,17 +288,20 @@ struct CombOperationExecutor {
const float3 &brush_end_cu,
const float brush_radius_cu)
{
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ MutableSpan<float3> positions_cu = curves_orig_->positions_for_write();
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
+
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false;
- const IndexRange points = curves_->points_for_curve(curve_i);
+ const IndexRange points = curves_orig_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
- const float3 pos_old_cu = positions_cu[point_i];
+ const float3 pos_old_cu = deformation.positions[point_i];
/* Compute distance to the brush. */
const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3(
@@ -308,8 +319,12 @@ struct CombOperationExecutor {
/* Combine the falloff and brush strength. */
const float weight = brush_strength_ * radius_falloff * point_factors_[point_i];
+ const float3 translation_eval_cu = weight * brush_diff_cu;
+ const float3 translation_orig_cu = deformation.translation_from_deformed_to_original(
+ point_i, translation_eval_cu);
+
/* Update the point position. */
- positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu;
+ positions_cu[point_i] += translation_orig_cu;
curve_changed = true;
}
if (curve_changed) {
@@ -328,7 +343,7 @@ struct CombOperationExecutor {
*ctx_.region,
*ctx_.v3d,
*ctx_.rv3d,
- *object_,
+ *curves_ob_orig_,
brush_pos_re_,
brush_radius_base_re_);
if (brush_3d.has_value()) {
@@ -342,11 +357,11 @@ struct CombOperationExecutor {
*/
void initialize_segment_lengths()
{
- const Span<float3> positions_cu = curves_->positions();
- self_->segment_lengths_cu_.reinitialize(curves_->points_num());
- threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) {
+ const Span<float3> positions_cu = curves_orig_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_orig_->points_num());
+ threading::parallel_for(curves_orig_->curves_range(), 128, [&](const IndexRange range) {
for (const int curve_i : range) {
- const IndexRange points = curves_->points_for_curve(curve_i);
+ const IndexRange points = curves_orig_->points_for_curve(curve_i);
for (const int point_i : points.drop_back(1)) {
const float3 &p1_cu = positions_cu[point_i];
const float3 &p2_cu = positions_cu[point_i + 1];
@@ -363,12 +378,12 @@ struct CombOperationExecutor {
void restore_segment_lengths(EnumerableThreadSpecific<Vector<int>> &changed_curves)
{
const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ MutableSpan<float3> positions_cu = curves_orig_->positions_for_write();
threading::parallel_for_each(changed_curves, [&](const Vector<int> &changed_curves) {
threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
for (const int curve_i : changed_curves.as_span().slice(range)) {
- const IndexRange points = curves_->points_for_curve(curve_i);
+ const IndexRange points = curves_orig_->points_for_curve(curve_i);
for (const int segment_i : points.drop_back(1)) {
const float3 &p1_cu = positions_cu[segment_i];
float3 &p2_cu = positions_cu[segment_i + 1];
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 6f12d539aa2..a44499ce133 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -51,6 +51,12 @@ using blender::bke::CurvesGeometry;
class DeleteOperation : public CurvesSculptStrokeOperation {
private:
CurvesBrush3D brush_3d_;
+ /**
+ * Need to store those in case the brush is evaluated more than once before the curves are
+ * evaluated again. This can happen when the mouse is moved quickly and the brush spacing is
+ * small.
+ */
+ Vector<float3> deformed_positions_;
friend struct DeleteOperationExecutor;
@@ -76,8 +82,7 @@ struct DeleteOperationExecutor {
float2 brush_pos_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
DeleteOperationExecutor(const bContext &C) : ctx_(C)
{
@@ -101,8 +106,7 @@ struct DeleteOperationExecutor {
brush_pos_re_ = stroke_extension.mouse_position;
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
@@ -111,6 +115,9 @@ struct DeleteOperationExecutor {
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
this->initialize_spherical_brush_reference_point();
}
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+ self_->deformed_positions_ = deformation.positions;
}
Array<bool> curves_to_delete(curves_->curves_num(), false);
@@ -125,12 +132,22 @@ struct DeleteOperationExecutor {
}
Vector<int64_t> indices;
- const IndexMask mask = index_mask_ops::find_indices_based_on_predicate(
+ const IndexMask mask_to_delete = index_mask_ops::find_indices_based_on_predicate(
curves_->curves_range(), 4096, indices, [&](const int curve_i) {
return curves_to_delete[curve_i];
});
- curves_->remove_curves(mask);
+ /* Remove deleted curves from the stored deformed positions. */
+ const Vector<IndexRange> ranges_to_keep = mask_to_delete.extract_ranges_invert(
+ curves_->curves_range());
+ Vector<float3> new_deformed_positions;
+ for (const IndexRange curves_range : ranges_to_keep) {
+ new_deformed_positions.extend(
+ self_->deformed_positions_.as_span().slice(curves_->points_for_curves(curves_range)));
+ }
+ self_->deformed_positions_ = std::move(new_deformed_positions);
+
+ curves_->remove_curves(mask_to_delete);
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
@@ -153,8 +170,6 @@ struct DeleteOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
- Span<float3> positions_cu = curves_->positions();
-
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
@@ -162,7 +177,7 @@ struct DeleteOperationExecutor {
for (const int curve_i : curve_selection_.slice(range)) {
const IndexRange points = curves_->points_for_curve(curve_i);
if (points.size() == 1) {
- const float3 pos_cu = brush_transform_inv * positions_cu[points.first()];
+ const float3 pos_cu = brush_transform_inv * self_->deformed_positions_[points.first()];
float2 pos_re;
ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
@@ -173,8 +188,8 @@ struct DeleteOperationExecutor {
}
for (const int segment_i : points.drop_back(1)) {
- const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i];
- const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
+ const float3 pos1_cu = brush_transform_inv * self_->deformed_positions_[segment_i];
+ const float3 pos2_cu = brush_transform_inv * self_->deformed_positions_[segment_i + 1];
float2 pos1_re, pos2_re;
ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
@@ -199,10 +214,10 @@ struct DeleteOperationExecutor {
float3 brush_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -214,8 +229,6 @@ struct DeleteOperationExecutor {
void delete_spherical(const float3 &brush_cu, MutableSpan<bool> curves_to_delete)
{
- Span<float3> positions_cu = curves_->positions();
-
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
@@ -224,7 +237,7 @@ struct DeleteOperationExecutor {
const IndexRange points = curves_->points_for_curve(curve_i);
if (points.size() == 1) {
- const float3 &pos_cu = positions_cu[points.first()];
+ const float3 &pos_cu = self_->deformed_positions_[points.first()];
const float distance_sq_cu = math::distance_squared(pos_cu, brush_cu);
if (distance_sq_cu < brush_radius_sq_cu) {
curves_to_delete[curve_i] = true;
@@ -233,8 +246,8 @@ struct DeleteOperationExecutor {
}
for (const int segment_i : points.drop_back(1)) {
- const float3 &pos1_cu = positions_cu[segment_i];
- const float3 &pos2_cu = positions_cu[segment_i + 1];
+ const float3 &pos1_cu = self_->deformed_positions_[segment_i];
+ const float3 &pos2_cu = self_->deformed_positions_[segment_i + 1];
const float distance_sq_cu = dist_squared_to_line_segment_v3(brush_cu, pos1_cu, pos2_cu);
if (distance_sq_cu > brush_radius_sq_cu) {
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
new file mode 100644
index 00000000000..c33ee5e0727
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
@@ -0,0 +1,922 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <numeric>
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BLI_index_mask_ops.hh"
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
+#include "BLI_task.hh"
+
+#include "PIL_time.h"
+
+#include "GEO_add_curves_on_mesh.hh"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+
+#include "WM_api.h"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+class DensityAddOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Used when some data should be interpolated from existing curves. */
+ KDTree_3d *original_curve_roots_kdtree_ = nullptr;
+ /** Contains curve roots of all curves that existed before the brush started. */
+ KDTree_3d *deformed_curve_roots_kdtree_ = nullptr;
+ /** Root positions of curves that have been added in the current brush stroke. */
+ Vector<float3> new_deformed_root_positions_;
+ int original_curve_num_ = 0;
+
+ friend struct DensityAddOperationExecutor;
+
+ public:
+ ~DensityAddOperation() override
+ {
+ if (original_curve_roots_kdtree_ != nullptr) {
+ BLI_kdtree_3d_free(original_curve_roots_kdtree_);
+ }
+ if (deformed_curve_roots_kdtree_ != nullptr) {
+ BLI_kdtree_3d_free(deformed_curve_roots_kdtree_);
+ }
+ }
+
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+struct DensityAddOperationExecutor {
+ DensityAddOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *curves_ob_orig_ = nullptr;
+ Curves *curves_id_orig_ = nullptr;
+ CurvesGeometry *curves_orig_ = nullptr;
+
+ Object *surface_ob_orig_ = nullptr;
+ Mesh *surface_orig_ = nullptr;
+
+ Object *surface_ob_eval_ = nullptr;
+ Mesh *surface_eval_ = nullptr;
+ Span<MLoopTri> surface_looptris_eval_;
+ VArraySpan<float2> surface_uv_map_eval_;
+ BVHTreeFromMesh surface_bvh_eval_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ const BrushCurvesSculptSettings *brush_settings_ = nullptr;
+
+ float brush_strength_;
+ float brush_radius_re_;
+ float2 brush_pos_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ DensityAddOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(DensityAddOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+ curves_ob_orig_ = CTX_data_active_object(&C);
+ curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data);
+ curves_orig_ = &CurvesGeometry::wrap(curves_id_orig_->geometry);
+
+ if (stroke_extension.is_first) {
+ self_->original_curve_num_ = curves_orig_->curves_num();
+ }
+
+ if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) {
+ report_missing_surface(stroke_extension.reports);
+ return;
+ }
+
+ surface_ob_orig_ = curves_id_orig_->surface;
+ surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
+ if (surface_orig_->totpoly == 0) {
+ report_empty_original_surface(stroke_extension.reports);
+ return;
+ }
+
+ surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
+ if (surface_ob_eval_ == nullptr) {
+ return;
+ }
+ surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_);
+ if (surface_eval_->totpoly == 0) {
+ report_empty_evaluated_surface(stroke_extension.reports);
+ return;
+ }
+
+ BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
+ surface_looptris_eval_ = {BKE_mesh_runtime_looptri_ensure(surface_eval_),
+ BKE_mesh_runtime_looptri_len(surface_eval_)};
+ /* Find UV map. */
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id_orig_->surface_uv_map != nullptr) {
+ surface_uv_map = surface_orig_->attributes()
+ .lookup<float2>(curves_id_orig_->surface_uv_map, ATTR_DOMAIN_CORNER);
+ surface_uv_map_eval_ = surface_eval_->attributes()
+ .lookup<float2>(curves_id_orig_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
+ }
+ if (surface_uv_map.is_empty()) {
+ report_missing_uv_map_on_original_surface(stroke_extension.reports);
+ return;
+ }
+ if (surface_uv_map_eval_.is_empty()) {
+ report_missing_uv_map_on_evaluated_surface(stroke_extension.reports);
+ return;
+ }
+
+ transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_settings_ = brush_->curves_sculpt_settings;
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ Vector<float3> new_positions_cu;
+ Vector<float2> new_uvs;
+ const double time = PIL_check_seconds_timer() * 1000000.0;
+ RandomNumberGenerator rng{*(uint32_t *)(&time)};
+
+ /* Find potential new curve root points. */
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->sample_projected_with_symmetry(rng, new_uvs, new_positions_cu);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->sample_spherical_with_symmetry(rng, new_uvs, new_positions_cu);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ for (float3 &pos : new_positions_cu) {
+ pos = transforms_.surface_to_curves * pos;
+ }
+
+ if (stroke_extension.is_first) {
+ this->prepare_curve_roots_kdtrees();
+ }
+
+ const int already_added_curves = self_->new_deformed_root_positions_.size();
+ KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves +
+ new_positions_cu.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(new_roots_kdtree); });
+
+ /* Used to tag all curves that are too close to existing curves or too close to other new
+ * curves. */
+ Array<bool> new_curve_skipped(new_positions_cu.size(), false);
+ threading::parallel_invoke(
+ 512 < already_added_curves + new_positions_cu.size(),
+ /* Build kdtree from root points created by the current stroke. */
+ [&]() {
+ for (const int i : IndexRange(already_added_curves)) {
+ BLI_kdtree_3d_insert(new_roots_kdtree, -1, self_->new_deformed_root_positions_[i]);
+ }
+ for (const int new_i : new_positions_cu.index_range()) {
+ const float3 &root_pos_cu = new_positions_cu[new_i];
+ BLI_kdtree_3d_insert(new_roots_kdtree, new_i, root_pos_cu);
+ }
+ BLI_kdtree_3d_balance(new_roots_kdtree);
+ },
+ /* Check which new root points are close to roots that existed before the current stroke
+ * started. */
+ [&]() {
+ threading::parallel_for(
+ new_positions_cu.index_range(), 128, [&](const IndexRange range) {
+ for (const int new_i : range) {
+ const float3 &new_root_pos_cu = new_positions_cu[new_i];
+ KDTreeNearest_3d nearest;
+ nearest.dist = FLT_MAX;
+ BLI_kdtree_3d_find_nearest(
+ self_->deformed_curve_roots_kdtree_, new_root_pos_cu, &nearest);
+ if (nearest.dist < brush_settings_->minimum_distance) {
+ new_curve_skipped[new_i] = true;
+ }
+ }
+ });
+ });
+
+ /* Find new points that are too close too other new points. */
+ for (const int new_i : new_positions_cu.index_range()) {
+ if (new_curve_skipped[new_i]) {
+ continue;
+ }
+ const float3 &root_pos_cu = new_positions_cu[new_i];
+ BLI_kdtree_3d_range_search_cb_cpp(
+ new_roots_kdtree,
+ root_pos_cu,
+ brush_settings_->minimum_distance,
+ [&](const int other_new_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ if (other_new_i == -1) {
+ new_curve_skipped[new_i] = true;
+ return false;
+ }
+ if (new_i == other_new_i) {
+ return true;
+ }
+ new_curve_skipped[other_new_i] = true;
+ return true;
+ });
+ }
+
+ /* Remove points that are too close to others. */
+ for (int64_t i = new_positions_cu.size() - 1; i >= 0; i--) {
+ if (new_curve_skipped[i]) {
+ new_positions_cu.remove_and_reorder(i);
+ new_uvs.remove_and_reorder(i);
+ }
+ }
+ self_->new_deformed_root_positions_.extend(new_positions_cu);
+
+ /* Find normals. */
+ if (!CustomData_has_layer(&surface_orig_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_orig_);
+ }
+ const Span<float3> corner_normals_su = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig_->ldata, CD_NORMAL)),
+ surface_orig_->totloop};
+
+ const Span<MLoopTri> surface_looptris_orig = {BKE_mesh_runtime_looptri_ensure(surface_orig_),
+ BKE_mesh_runtime_looptri_len(surface_orig_)};
+ const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
+
+ geometry::AddCurvesOnMeshInputs add_inputs;
+ add_inputs.uvs = new_uvs;
+ add_inputs.interpolate_length = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ add_inputs.interpolate_shape = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_inputs.interpolate_point_count = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ add_inputs.fallback_curve_length = brush_settings_->curve_length;
+ add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
+ add_inputs.transforms = &transforms_;
+ add_inputs.surface = surface_orig_;
+ add_inputs.corner_normals_su = corner_normals_su;
+ add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
+ add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_;
+
+ const geometry::AddCurvesOnMeshOutputs add_outputs = geometry::add_curves_on_mesh(
+ *curves_orig_, add_inputs);
+
+ if (add_outputs.uv_error) {
+ report_invalid_uv_map(stroke_extension.reports);
+ }
+
+ DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_orig_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void prepare_curve_roots_kdtrees()
+ {
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
+ const Span<int> curve_offsets = curves_orig_->offsets();
+ const Span<float3> original_positions = curves_orig_->positions();
+ const Span<float3> deformed_positions = deformation.positions;
+ BLI_assert(original_positions.size() == deformed_positions.size());
+
+ auto roots_kdtree_from_positions = [&](const Span<float3> positions) {
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(curves_orig_->curves_num());
+ for (const int curve_i : curves_orig_->curves_range()) {
+ const int root_point_i = curve_offsets[curve_i];
+ BLI_kdtree_3d_insert(kdtree, curve_i, positions[root_point_i]);
+ }
+ BLI_kdtree_3d_balance(kdtree);
+ return kdtree;
+ };
+
+ threading::parallel_invoke(
+ 1024 < original_positions.size() + deformed_positions.size(),
+ [&]() {
+ self_->original_curve_roots_kdtree_ = roots_kdtree_from_positions(original_positions);
+ },
+ [&]() {
+ self_->deformed_curve_roots_kdtree_ = roots_kdtree_from_positions(deformed_positions);
+ });
+ }
+
+ void sample_projected_with_symmetry(RandomNumberGenerator &rng,
+ Vector<float2> &r_uvs,
+ Vector<float3> &r_positions_su)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values);
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform *
+ transforms_.world_to_curves;
+ Vector<float3> positions_su;
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
+ rng,
+ *surface_eval_,
+ surface_bvh_eval_,
+ brush_pos_re_,
+ brush_radius_re_,
+ [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
+ float3 start_wo, end_wo;
+ ED_view3d_win_to_segment_clipped(
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
+ r_start_su = transform * start_wo;
+ r_end_su = transform * end_wo;
+ },
+ true,
+ brush_settings_->density_add_attempts,
+ brush_settings_->density_add_attempts,
+ bary_coords,
+ looptri_indices,
+ positions_su);
+
+ /* Remove some sampled points randomly based on the brush falloff and strength. */
+ for (int i = new_points - 1; i >= 0; i--) {
+ const float3 pos_su = positions_su[i];
+ const float3 pos_cu = brush_transform_inv * transforms_.surface_to_curves * pos_su;
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_re = math::distance(brush_pos_re_, pos_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re_);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() > weight) {
+ bary_coords.remove_and_reorder(i);
+ looptri_indices.remove_and_reorder(i);
+ positions_su.remove_and_reorder(i);
+ }
+ }
+
+ for (const int i : bary_coords.index_range()) {
+ const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
+ bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
+ r_uvs.append(uv);
+ }
+ r_positions_su.extend(positions_su);
+ }
+ }
+
+ void sample_spherical_with_symmetry(RandomNumberGenerator &rng,
+ Vector<float2> &r_uvs,
+ Vector<float3> &r_positions_su)
+ {
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_eval_,
+ brush_pos_re_,
+ brush_radius_re_);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float3 brush_pos_cu = brush_transform * brush_3d->position_cu;
+ const float3 brush_pos_su = transforms_.curves_to_surface * brush_pos_cu;
+ const float brush_radius_su = transform_brush_radius(
+ transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu);
+ const float brush_radius_sq_su = pow2f(brush_radius_su);
+
+ Vector<int> selected_looptri_indices;
+ BLI_bvhtree_range_query_cpp(
+ *surface_bvh_eval_.tree,
+ brush_pos_su,
+ brush_radius_su,
+ [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
+ selected_looptri_indices.append(index);
+ });
+
+ const float brush_plane_area_su = M_PI * brush_radius_sq_su;
+ const float approximate_density_su = brush_settings_->density_add_attempts /
+ brush_plane_area_su;
+
+ Vector<float3> positions_su;
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
+ rng,
+ *surface_eval_,
+ selected_looptri_indices,
+ brush_pos_su,
+ brush_radius_su,
+ approximate_density_su,
+ bary_coords,
+ looptri_indices,
+ positions_su);
+
+ /* Remove some sampled points randomly based on the brush falloff and strength. */
+ for (int i = new_points - 1; i >= 0; i--) {
+ const float3 pos_su = positions_su[i];
+ const float3 pos_cu = transforms_.surface_to_curves * pos_su;
+ const float dist_to_brush_cu = math::distance(pos_cu, brush_pos_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_3d->radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() > weight) {
+ bary_coords.remove_and_reorder(i);
+ looptri_indices.remove_and_reorder(i);
+ positions_su.remove_and_reorder(i);
+ }
+ }
+
+ for (const int i : bary_coords.index_range()) {
+ const float2 uv = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
+ bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
+ r_uvs.append(uv);
+ }
+ r_positions_su.extend(positions_su);
+ }
+ }
+};
+
+void DensityAddOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ DensityAddOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+class DensitySubtractOperation : public CurvesSculptStrokeOperation {
+ private:
+ friend struct DensitySubtractOperationExecutor;
+
+ /**
+ * Deformed root positions of curves that still exist. This has to be stored in case the brush is
+ * executed more than once before the curves are evaluated again. This can happen when the mouse
+ * is moved quickly and the brush spacing is small.
+ */
+ Vector<float3> deformed_root_positions_;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct DensitySubtractOperationExecutor {
+ DensitySubtractOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ Object *surface_ob_orig_ = nullptr;
+ Mesh *surface_orig_ = nullptr;
+
+ Object *surface_ob_eval_ = nullptr;
+ Mesh *surface_eval_ = nullptr;
+ BVHTreeFromMesh surface_bvh_eval_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+ float2 brush_pos_re_;
+
+ float minimum_distance_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ KDTree_3d *root_points_kdtree_;
+
+ DensitySubtractOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(DensitySubtractOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ surface_ob_orig_ = curves_id_->surface;
+ if (surface_ob_orig_ == nullptr) {
+ return;
+ }
+ surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
+
+ surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
+ if (surface_ob_eval_ == nullptr) {
+ return;
+ }
+ surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_);
+
+ BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ minimum_distance_ = brush_->curves_sculpt_settings->minimum_distance;
+
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ if (stroke_extension.is_first) {
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+ for (const int curve_i : curves_->curves_range()) {
+ const int first_point_i = curves_->offsets()[curve_i];
+ self_->deformed_root_positions_.append(deformation.positions[first_point_i]);
+ }
+ }
+
+ root_points_kdtree_ = BLI_kdtree_3d_new(curve_selection_.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(root_points_kdtree_); });
+ for (const int curve_i : curve_selection_) {
+ const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
+ BLI_kdtree_3d_insert(root_points_kdtree_, curve_i, pos_cu);
+ }
+ BLI_kdtree_3d_balance(root_points_kdtree_);
+
+ /* Find all curves that should be deleted. */
+ Array<bool> curves_to_delete(curves_->curves_num(), false);
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->reduce_density_projected_with_symmetry(curves_to_delete);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->reduce_density_spherical_with_symmetry(curves_to_delete);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ Vector<int64_t> indices;
+ const IndexMask mask_to_delete = index_mask_ops::find_indices_based_on_predicate(
+ curves_->curves_range(), 4096, indices, [&](const int curve_i) {
+ return curves_to_delete[curve_i];
+ });
+
+ /* Remove deleted curves from the stored deformed root positions. */
+ const Vector<IndexRange> ranges_to_keep = mask_to_delete.extract_ranges_invert(
+ curves_->curves_range());
+ BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size());
+ Vector<float3> new_deformed_positions;
+ for (const IndexRange range : ranges_to_keep) {
+ new_deformed_positions.extend(self_->deformed_root_positions_.as_span().slice(range));
+ }
+ self_->deformed_root_positions_ = std::move(new_deformed_positions);
+
+ curves_->remove_curves(mask_to_delete);
+ BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size());
+
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void reduce_density_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->reduce_density_projected(brush_transform, curves_to_delete);
+ }
+ }
+
+ void reduce_density_projected(const float4x4 &brush_transform,
+ MutableSpan<bool> curves_to_delete)
+ {
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ /* Randomly select the curves that are allowed to be removed, based on the brush radius and
+ * strength. */
+ Array<bool> allow_remove_curve(curves_->curves_num(), false);
+ threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
+ RandomNumberGenerator rng((int)(PIL_check_seconds_timer() * 1000000.0));
+
+ for (const int curve_i : range) {
+ if (curves_to_delete[curve_i]) {
+ allow_remove_curve[curve_i] = true;
+ continue;
+ }
+ const float3 pos_cu = brush_transform * self_->deformed_root_positions_[curve_i];
+
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() < weight) {
+ allow_remove_curve[curve_i] = true;
+ }
+ }
+ });
+
+ /* Detect curves that are too close to other existing curves. */
+ for (const int curve_i : curve_selection_) {
+ if (curves_to_delete[curve_i]) {
+ continue;
+ }
+ if (!allow_remove_curve[curve_i]) {
+ continue;
+ }
+ const float3 orig_pos_cu = self_->deformed_root_positions_[curve_i];
+ const float3 pos_cu = brush_transform * orig_pos_cu;
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ BLI_kdtree_3d_range_search_cb_cpp(
+ root_points_kdtree_,
+ orig_pos_cu,
+ minimum_distance_,
+ [&](const int other_curve_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ if (other_curve_i == curve_i) {
+ return true;
+ }
+ if (allow_remove_curve[other_curve_i]) {
+ curves_to_delete[other_curve_i] = true;
+ }
+ return true;
+ });
+ }
+ }
+
+ void reduce_density_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
+ {
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_eval_,
+ brush_pos_re_,
+ brush_radius_re);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float3 brush_pos_cu = brush_transform * brush_3d->position_cu;
+ this->reduce_density_spherical(brush_pos_cu, brush_3d->radius_cu, curves_to_delete);
+ }
+ }
+
+ void reduce_density_spherical(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<bool> curves_to_delete)
+ {
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ /* Randomly select the curves that are allowed to be removed, based on the brush radius and
+ * strength. */
+ Array<bool> allow_remove_curve(curves_->curves_num(), false);
+ threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
+ RandomNumberGenerator rng((int)(PIL_check_seconds_timer() * 1000000.0));
+
+ for (const int curve_i : range) {
+ if (curves_to_delete[curve_i]) {
+ allow_remove_curve[curve_i] = true;
+ continue;
+ }
+ const float3 pos_cu = self_->deformed_root_positions_[curve_i];
+
+ const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() < weight) {
+ allow_remove_curve[curve_i] = true;
+ }
+ }
+ });
+
+ /* Detect curves that are too close to other existing curves. */
+ for (const int curve_i : curve_selection_) {
+ if (curves_to_delete[curve_i]) {
+ continue;
+ }
+ if (!allow_remove_curve[curve_i]) {
+ continue;
+ }
+ const float3 &pos_cu = self_->deformed_root_positions_[curve_i];
+ const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ BLI_kdtree_3d_range_search_cb_cpp(
+ root_points_kdtree_,
+ pos_cu,
+ minimum_distance_,
+ [&](const int other_curve_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ if (other_curve_i == curve_i) {
+ return true;
+ }
+ if (allow_remove_curve[other_curve_i]) {
+ curves_to_delete[other_curve_i] = true;
+ }
+ return true;
+ });
+ }
+ }
+};
+
+void DensitySubtractOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ DensitySubtractOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+/**
+ * Detects whether the brush should be in Add or Subtract mode.
+ */
+static bool use_add_density_mode(const BrushStrokeMode brush_mode,
+ const bContext &C,
+ const StrokeExtension &stroke_start)
+{
+ const Scene &scene = *CTX_data_scene(&C);
+ const Brush &brush = *BKE_paint_brush_for_read(&scene.toolsettings->curves_sculpt->paint);
+ const Depsgraph &depsgraph = *CTX_data_depsgraph_on_load(&C);
+ const ARegion &region = *CTX_wm_region(&C);
+ const View3D &v3d = *CTX_wm_view3d(&C);
+
+ const eBrushCurvesSculptDensityMode density_mode = static_cast<eBrushCurvesSculptDensityMode>(
+ brush.curves_sculpt_settings->density_mode);
+ const bool use_invert = brush_mode == BRUSH_STROKE_INVERT;
+
+ if (density_mode == BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD) {
+ return !use_invert;
+ }
+ if (density_mode == BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE) {
+ return use_invert;
+ }
+
+ const Object &curves_ob_orig = *CTX_data_active_object(&C);
+ const Curves &curves_id_orig = *static_cast<Curves *>(curves_ob_orig.data);
+ Object *surface_ob_orig = curves_id_orig.surface;
+ if (surface_ob_orig == nullptr) {
+ return true;
+ }
+ Object *surface_ob_eval = DEG_get_evaluated_object(&depsgraph, surface_ob_orig);
+ if (surface_ob_eval == nullptr) {
+ return true;
+ }
+ const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id_orig.geometry);
+ if (curves.curves_num() <= 1) {
+ return true;
+ }
+ const Mesh *surface_mesh_eval = BKE_object_get_evaluated_mesh(surface_ob_eval);
+ if (surface_mesh_eval == nullptr) {
+ return true;
+ }
+
+ const CurvesSurfaceTransforms transforms(curves_ob_orig, curves_id_orig.surface);
+ BVHTreeFromMesh surface_bvh_eval;
+ BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_mesh_eval, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); });
+
+ const float2 brush_pos_re = stroke_start.mouse_position;
+ /* Reduce radius so that only an inner circle is used to determine the existing density. */
+ const float brush_radius_re = BKE_brush_size_get(&scene, &brush) * 0.5f;
+
+ /* Find the surface point under the brush. */
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(
+ depsgraph, region, v3d, transforms, surface_bvh_eval, brush_pos_re, brush_radius_re);
+ if (!brush_3d.has_value()) {
+ return true;
+ }
+
+ const float3 brush_pos_cu = brush_3d->position_cu;
+ const float brush_radius_cu = brush_3d->radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(depsgraph, curves_ob_orig);
+ const Span<int> offsets = curves.offsets();
+
+ /* Compute distance from brush to curve roots. */
+ Array<std::pair<float, int>> distances_sq_to_brush(curves.curves_num());
+ threading::EnumerableThreadSpecific<int> valid_curve_count_by_thread;
+ threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
+ int &valid_curve_count = valid_curve_count_by_thread.local();
+ for (const int curve_i : range) {
+ const int root_point_i = offsets[curve_i];
+ const float3 &root_pos_cu = deformation.positions[root_point_i];
+ const float dist_sq_cu = math::distance_squared(root_pos_cu, brush_pos_cu);
+ if (dist_sq_cu < brush_radius_sq_cu) {
+ distances_sq_to_brush[curve_i] = {math::distance_squared(root_pos_cu, brush_pos_cu),
+ curve_i};
+ valid_curve_count++;
+ }
+ else {
+ distances_sq_to_brush[curve_i] = {FLT_MAX, -1};
+ }
+ }
+ });
+ const int valid_curve_count = std::accumulate(
+ valid_curve_count_by_thread.begin(), valid_curve_count_by_thread.end(), 0);
+
+ /* Find a couple of curves that are closest to the brush center. */
+ const int check_curve_count = std::min<int>(8, valid_curve_count);
+ std::partial_sort(distances_sq_to_brush.begin(),
+ distances_sq_to_brush.begin() + check_curve_count,
+ distances_sq_to_brush.end());
+
+ /* Compute the minimum pair-wise distance between the curve roots that are close to the brush
+ * center. */
+ float min_dist_sq_cu = FLT_MAX;
+ for (const int i : IndexRange(check_curve_count)) {
+ const float3 &pos_i = deformation.positions[offsets[distances_sq_to_brush[i].second]];
+ for (int j = i + 1; j < check_curve_count; j++) {
+ const float3 &pos_j = deformation.positions[offsets[distances_sq_to_brush[j].second]];
+ const float dist_sq_cu = math::distance_squared(pos_i, pos_j);
+ math::min_inplace(min_dist_sq_cu, dist_sq_cu);
+ }
+ }
+
+ const float min_dist_cu = std::sqrt(min_dist_sq_cu);
+ if (min_dist_cu > brush.curves_sculpt_settings->minimum_distance) {
+ return true;
+ }
+
+ return false;
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation(
+ const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
+{
+ if (use_add_density_mode(brush_mode, C, stroke_start)) {
+ return std::make_unique<DensityAddOperation>();
+ }
+ return std::make_unique<DensitySubtractOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index 3420659520b..0ca22004540 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -4,8 +4,7 @@
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_float4x4.hh"
-#include "BLI_kdtree.h"
-#include "BLI_rand.hh"
+#include "BLI_length_parameterize.hh"
#include "BLI_vector.hh"
#include "PIL_time.h"
@@ -14,19 +13,13 @@
#include "BKE_attribute_math.hh"
#include "BKE_brush.h"
-#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
#include "DNA_curves_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -70,6 +63,24 @@ class ShrinkCurvesEffect : public CurvesEffect {
private:
const Brush &brush_;
+ /** Storage of per-curve parameterization data to avoid reallocation. */
+ struct ParameterizationBuffers {
+ Array<float3> old_positions;
+ Array<float> old_lengths;
+ Array<float> sample_lengths;
+ Array<int> indices;
+ Array<float> factors;
+
+ void reinitialize(const int points_num)
+ {
+ this->old_positions.reinitialize(points_num);
+ this->old_lengths.reinitialize(length_parameterize::segments_num(points_num, false));
+ this->sample_lengths.reinitialize(points_num);
+ this->indices.reinitialize(points_num);
+ this->factors.reinitialize(points_num);
+ }
+ };
+
public:
ShrinkCurvesEffect(const Brush &brush) : brush_(brush)
{
@@ -81,46 +92,42 @@ class ShrinkCurvesEffect : public CurvesEffect {
{
MutableSpan<float3> positions_cu = curves.positions_for_write();
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
+ ParameterizationBuffers data;
for (const int influence_i : range) {
const int curve_i = curve_indices[influence_i];
const float move_distance_cu = move_distances_cu[influence_i];
- const IndexRange curve_points = curves.points_for_curve(curve_i);
- this->shrink_curve(positions_cu, curve_points, move_distance_cu);
+ const IndexRange points = curves.points_for_curve(curve_i);
+ this->shrink_curve(positions_cu.slice(points), move_distance_cu, data);
}
});
}
+ private:
void shrink_curve(MutableSpan<float3> positions,
- const IndexRange curve_points,
- const float shrink_length) const
+ const float shrink_length,
+ ParameterizationBuffers &data) const
{
- PolySpline spline;
- spline.resize(curve_points.size());
- MutableSpan<float3> spline_positions = spline.positions();
- spline_positions.copy_from(positions.slice(curve_points));
- spline.mark_cache_invalid();
+ namespace lp = length_parameterize;
+ data.reinitialize(positions.size());
+
+ /* Copy the old positions to facilitate mixing from neighbors for the resulting curve. */
+ data.old_positions.as_mutable_span().copy_from(positions);
+
+ lp::accumulate_lengths<float3>(data.old_positions, false, data.old_lengths);
+
const float min_length = brush_.curves_sculpt_settings->minimum_length;
- const float old_length = spline.length();
+ const float old_length = data.old_lengths.last();
const float new_length = std::max(min_length, old_length - shrink_length);
const float length_factor = std::clamp(new_length / old_length, 0.0f, 1.0f);
- Vector<float> old_point_lengths;
- old_point_lengths.append(0.0f);
- for (const int i : spline_positions.index_range().drop_back(1)) {
- const float3 &p1 = spline_positions[i];
- const float3 &p2 = spline_positions[i + 1];
- const float length = math::distance(p1, p2);
- old_point_lengths.append(old_point_lengths.last() + length);
+ data.sample_lengths.first() = 0.0f;
+ for (const int i : data.old_lengths.index_range()) {
+ data.sample_lengths[i + 1] = data.old_lengths[i] * length_factor;
}
- for (const int i : spline_positions.index_range()) {
- const float eval_length = old_point_lengths[i] * length_factor;
- const Spline::LookupResult lookup = spline.lookup_evaluated_length(eval_length);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- spline.sample_with_index_factors<float3>(spline_positions, {&index_factor, 1}, {&p, 1});
- positions[curve_points[i]] = p;
- }
+ lp::sample_at_lengths(data.old_lengths, data.sample_lengths, data.indices, data.factors);
+
+ lp::interpolate<float3>(data.old_positions, data.indices, data.factors, positions);
}
};
@@ -137,21 +144,20 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
for (const int influence_i : range) {
const int curve_i = curve_indices[influence_i];
const float move_distance_cu = move_distances_cu[influence_i];
- const IndexRange curve_points = curves.points_for_curve(curve_i);
+ const IndexRange points = curves.points_for_curve(curve_i);
- if (curve_points.size() <= 1) {
+ if (points.size() <= 1) {
continue;
}
- const float3 old_last_pos_cu = positions_cu[curve_points.last()];
+ const float3 old_last_pos_cu = positions_cu[points.last()];
/* Use some point within the curve rather than the end point to smooth out some random
* variation. */
- const float3 direction_reference_point =
- positions_cu[curve_points[curve_points.size() / 2]];
+ const float3 direction_reference_point = positions_cu[points[points.size() / 2]];
const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point);
const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu;
- move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(points), new_last_pos_cu);
}
});
}
@@ -247,8 +253,7 @@ struct CurvesEffectOperationExecutor {
eBrushFalloffShape falloff_shape_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
float2 brush_pos_start_re_;
float2 brush_pos_end_re_;
@@ -290,8 +295,7 @@ struct CurvesEffectOperationExecutor {
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
brush_pos_start_re_ = self.last_mouse_position_;
brush_pos_end_re_ = stroke_extension.mouse_position;
@@ -337,7 +341,8 @@ struct CurvesEffectOperationExecutor {
void gather_influences_projected(
threading::EnumerableThreadSpecific<Influences> &influences_for_thread)
{
- const Span<float3> positions_cu = curves_->positions();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
float4x4 projection;
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
@@ -345,7 +350,7 @@ struct CurvesEffectOperationExecutor {
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
Vector<float4x4> symmetry_brush_transforms_inv;
- for (const float4x4 brush_transform : symmetry_brush_transforms) {
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
symmetry_brush_transforms_inv.append(brush_transform.inverted());
}
@@ -363,8 +368,8 @@ struct CurvesEffectOperationExecutor {
float max_move_distance_cu = 0.0f;
for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
for (const int segment_i : points.drop_back(1)) {
- const float3 p1_cu = brush_transform_inv * positions_cu[segment_i];
- const float3 p2_cu = brush_transform_inv * positions_cu[segment_i + 1];
+ const float3 p1_cu = brush_transform_inv * deformation.positions[segment_i];
+ const float3 p2_cu = brush_transform_inv * deformation.positions[segment_i + 1];
float2 p1_re, p2_re;
ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values);
@@ -398,16 +403,16 @@ struct CurvesEffectOperationExecutor {
float3 brush_start_pos_wo, brush_end_pos_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * closest_on_segment_cu,
+ transforms_.curves_to_world * closest_on_segment_cu,
brush_pos_start_re_,
brush_start_pos_wo);
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * closest_on_segment_cu,
+ transforms_.curves_to_world * closest_on_segment_cu,
brush_pos_end_re_,
brush_end_pos_wo);
- const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo;
- const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo;
+ const float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo;
+ const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo;
const float move_distance_cu = weight *
math::distance(brush_start_pos_cu, brush_end_pos_cu);
@@ -425,21 +430,22 @@ struct CurvesEffectOperationExecutor {
void gather_influences_spherical(
threading::EnumerableThreadSpecific<Influences> &influences_for_thread)
{
- const Span<float3> positions_cu = curves_->positions();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
float3 brush_pos_start_wo, brush_pos_end_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_start_re_,
brush_pos_start_wo);
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_end_re_,
brush_pos_end_wo);
- const float3 brush_pos_start_cu = world_to_curves_mat_ * brush_pos_start_wo;
- const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo;
+ const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo;
+ const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo;
const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -463,8 +469,8 @@ struct CurvesEffectOperationExecutor {
const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu;
for (const int segment_i : points.drop_back(1)) {
- const float3 &p1_cu = positions_cu[segment_i];
- const float3 &p2_cu = positions_cu[segment_i + 1];
+ const float3 &p1_cu = deformation.positions[segment_i];
+ const float3 &p2_cu = deformation.positions[segment_i + 1];
float3 closest_on_segment_cu;
float3 closest_on_brush_cu;
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 5c926b1a740..5c8c0cedc6f 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -12,8 +12,11 @@
#include "BLI_virtual_array.hh"
#include "BKE_attribute.h"
+#include "BKE_crazyspace.hh"
#include "BKE_curves.hh"
+#include "ED_curves_sculpt.h"
+
struct ARegion;
struct RegionView3D;
struct Depsgraph;
@@ -21,15 +24,19 @@ struct View3D;
struct Object;
struct Brush;
struct Scene;
+struct BVHTreeFromMesh;
+struct ReportList;
namespace blender::ed::sculpt_paint {
using bke::CurvesGeometry;
+using bke::CurvesSurfaceTransforms;
struct StrokeExtension {
bool is_first;
float2 mouse_position;
float pressure;
+ ReportList *reports = nullptr;
};
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension);
@@ -51,8 +58,7 @@ class CurvesSculptStrokeOperation {
virtual void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) = 0;
};
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(const bContext &C,
- ReportList *reports);
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation();
@@ -60,6 +66,13 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation(
const BrushStrokeMode brush_mode, const bContext &C);
std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation(
const BrushStrokeMode brush_mode, const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode,
+ const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation(
+ const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start);
+std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation();
struct CurvesBrush3D {
float3 position_cu;
@@ -89,31 +102,37 @@ VArray<float> get_curves_selection(const Curves &curves_id);
*/
VArray<float> get_point_selection(const Curves &curves_id);
-/**
- * Find curves that have any point selected (a selection factor greater than zero),
- * or curves that have their own selection factor greater than zero.
- */
-IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
-
void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position);
-float3 compute_surface_point_normal(const MLoopTri &looptri,
- const float3 &bary_coord,
- const Span<float3> corner_normals);
-
-float3 compute_bary_coord_in_triangle(const Mesh &mesh,
- const MLoopTri &looptri,
- const float3 &position);
-
class CurvesSculptCommonContext {
public:
const Depsgraph *depsgraph = nullptr;
const Scene *scene = nullptr;
ARegion *region = nullptr;
const View3D *v3d = nullptr;
- const RegionView3D *rv3d = nullptr;
+ RegionView3D *rv3d = nullptr;
CurvesSculptCommonContext(const bContext &C);
};
+std::optional<CurvesBrush3D> sample_curves_surface_3d_brush(
+ const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const CurvesSurfaceTransforms &transforms,
+ const BVHTreeFromMesh &surface_bvh,
+ const float2 &brush_pos_re,
+ const float brush_radius_re);
+
+float transform_brush_radius(const float4x4 &transform,
+ const float3 &brush_position,
+ const float old_radius);
+
+void report_empty_original_surface(ReportList *reports);
+void report_empty_evaluated_surface(ReportList *reports);
+void report_missing_surface(ReportList *reports);
+void report_missing_uv_map_on_original_surface(ReportList *reports);
+void report_missing_uv_map_on_evaluated_surface(ReportList *reports);
+void report_invalid_uv_map(ReportList *reports);
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 5d6ffa67005..6e1ac24e21b 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -1,49 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector_set.hh"
-#include "BKE_attribute_math.hh"
#include "BKE_brush.h"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
-#include "BKE_geometry_set.hh"
-#include "BKE_lib_id.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_toolsystem.h"
+#include "ED_curves.h"
#include "ED_curves_sculpt.h"
#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_view3d.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "DNA_brush_types.h"
#include "DNA_curves_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_screen_types.h"
#include "RNA_access.h"
-
-#include "BLI_index_mask_ops.hh"
-#include "BLI_kdtree.h"
-#include "BLI_math_vector.hh"
-#include "BLI_rand.hh"
-
-#include "PIL_time.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "curves_sculpt_intern.h"
#include "curves_sculpt_intern.hh"
#include "paint_intern.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
/* -------------------------------------------------------------------- */
/** \name Poll Functions
* \{ */
@@ -105,8 +109,8 @@ float brush_strength_get(const Scene &scene,
return BKE_brush_alpha_get(&scene, &brush) * brush_strength_factor(brush, stroke_extension);
}
-static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext &C,
- wmOperator &op)
+static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(
+ bContext &C, wmOperator &op, const StrokeExtension &stroke_start)
{
const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
@@ -121,11 +125,21 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
case CURVES_SCULPT_TOOL_SNAKE_HOOK:
return new_snake_hook_operation();
case CURVES_SCULPT_TOOL_ADD:
- return new_add_operation(C, op.reports);
+ return new_add_operation();
case CURVES_SCULPT_TOOL_GROW_SHRINK:
return new_grow_shrink_operation(mode, C);
case CURVES_SCULPT_TOOL_SELECTION_PAINT:
return new_selection_paint_operation(mode, C);
+ case CURVES_SCULPT_TOOL_PINCH:
+ return new_pinch_operation(mode, C);
+ case CURVES_SCULPT_TOOL_SMOOTH:
+ return new_smooth_operation();
+ case CURVES_SCULPT_TOOL_PUFF:
+ return new_puff_operation();
+ case CURVES_SCULPT_TOOL_DENSITY:
+ return new_density_operation(mode, C, stroke_start);
+ case CURVES_SCULPT_TOOL_SLIDE:
+ return new_slide_operation();
}
BLI_assert_unreachable();
return {};
@@ -136,7 +150,10 @@ struct SculptCurvesBrushStrokeData {
PaintStroke *stroke;
};
-static bool stroke_get_location(bContext *C, float out[3], const float mouse[2])
+static bool stroke_get_location(bContext *C,
+ float out[3],
+ const float mouse[2],
+ bool UNUSED(force_original))
{
out[0] = mouse[0];
out[1] = mouse[1];
@@ -162,10 +179,11 @@ static void stroke_update_step(bContext *C,
StrokeExtension stroke_extension;
RNA_float_get_array(stroke_element, "mouse", stroke_extension.mouse_position);
stroke_extension.pressure = RNA_float_get(stroke_element, "pressure");
+ stroke_extension.reports = op->reports;
if (!op_data->operation) {
stroke_extension.is_first = true;
- op_data->operation = start_brush_operation(*C, *op);
+ op_data->operation = start_brush_operation(*C, *op, stroke_extension);
}
else {
stroke_extension.is_first = false;
@@ -251,21 +269,11 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot)
/** \name * CURVES_OT_sculptmode_toggle
* \{ */
-static bool curves_sculptmode_toggle_poll(bContext *C)
-{
- const Object *ob = CTX_data_active_object(C);
- if (ob == nullptr) {
- return false;
- }
- if (ob->type != OB_CURVES) {
- return false;
- }
- return true;
-}
-
static void curves_sculptmode_enter(bContext *C)
{
Scene *scene = CTX_data_scene(C);
+ wmMsgBus *mbus = CTX_wm_message_bus(C);
+
Object *ob = CTX_data_active_object(C);
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->curves_sculpt);
CurvesSculpt *curves_sculpt = scene->toolsettings->curves_sculpt;
@@ -274,8 +282,9 @@ static void curves_sculptmode_enter(bContext *C)
ED_paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
- /* Update for mode change. */
+ /* Necessary to change the object mode on the evaluated object. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
}
@@ -288,6 +297,8 @@ static void curves_sculptmode_exit(bContext *C)
static int curves_sculptmode_toggle_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
+ wmMsgBus *mbus = CTX_wm_message_bus(C);
+
const bool is_mode_set = ob->mode == OB_MODE_SCULPT_CURVES;
if (is_mode_set) {
@@ -304,6 +315,10 @@ static int curves_sculptmode_toggle_exec(bContext *C, wmOperator *op)
}
WM_toolsystem_update_from_context_view3d(C);
+
+ /* Necessary to change the object mode on the evaluated object. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
return OPERATOR_FINISHED;
}
@@ -315,13 +330,937 @@ static void CURVES_OT_sculptmode_toggle(wmOperatorType *ot)
ot->description = "Enter/Exit sculpt mode for curves";
ot->exec = curves_sculptmode_toggle_exec;
- ot->poll = curves_sculptmode_toggle_poll;
+ ot->poll = curves::curves_poll;
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
/** \} */
+namespace select_random {
+
+static int select_random_exec(bContext *C, wmOperator *op)
+{
+ VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
+
+ const int seed = RNA_int_get(op->ptr, "seed");
+ RandomNumberGenerator rng{static_cast<uint32_t>(seed)};
+
+ const bool partial = RNA_boolean_get(op->ptr, "partial");
+ const bool constant_per_curve = RNA_boolean_get(op->ptr, "constant_per_curve");
+ const float probability = RNA_float_get(op->ptr, "probability");
+ const float min_value = RNA_float_get(op->ptr, "min");
+ const auto next_partial_random_value = [&]() {
+ return rng.get_float() * (1.0f - min_value) + min_value;
+ };
+ const auto next_bool_random_value = [&]() { return rng.get_float() <= probability; };
+
+ for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ const bool was_anything_selected = curves::has_anything_selected(*curves_id);
+ switch (curves_id->selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ MutableSpan<float> selection = curves.selection_point_float_for_write();
+ if (!was_anything_selected) {
+ selection.fill(1.0f);
+ }
+ if (partial) {
+ if (constant_per_curve) {
+ for (const int curve_i : curves.curves_range()) {
+ const float random_value = next_partial_random_value();
+ const IndexRange points = curves.points_for_curve(curve_i);
+ for (const int point_i : points) {
+ selection[point_i] *= random_value;
+ }
+ }
+ }
+ else {
+ for (const int point_i : selection.index_range()) {
+ const float random_value = next_partial_random_value();
+ selection[point_i] *= random_value;
+ }
+ }
+ }
+ else {
+ if (constant_per_curve) {
+ for (const int curve_i : curves.curves_range()) {
+ const bool random_value = next_bool_random_value();
+ const IndexRange points = curves.points_for_curve(curve_i);
+ if (!random_value) {
+ selection.slice(points).fill(0.0f);
+ }
+ }
+ }
+ else {
+ for (const int point_i : selection.index_range()) {
+ const bool random_value = next_bool_random_value();
+ if (!random_value) {
+ selection[point_i] = 0.0f;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ MutableSpan<float> selection = curves.selection_curve_float_for_write();
+ if (!was_anything_selected) {
+ selection.fill(1.0f);
+ }
+ if (partial) {
+ for (const int curve_i : curves.curves_range()) {
+ const float random_value = next_partial_random_value();
+ selection[curve_i] *= random_value;
+ }
+ }
+ else {
+ for (const int curve_i : curves.curves_range()) {
+ const bool random_value = next_bool_random_value();
+ if (!random_value) {
+ selection[curve_i] = 0.0f;
+ }
+ }
+ }
+ break;
+ }
+ }
+ MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
+ curves.selection_point_float_for_write() :
+ curves.selection_curve_float_for_write();
+ const bool was_any_selected = std::any_of(
+ selection.begin(), selection.end(), [](const float v) { return v > 0.0f; });
+ if (was_any_selected) {
+ for (float &v : selection) {
+ v *= rng.get_float();
+ }
+ }
+ else {
+ for (float &v : selection) {
+ v = rng.get_float();
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+ return OPERATOR_FINISHED;
+}
+
+static void select_random_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+
+ uiItemR(layout, op->ptr, "seed", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "constant_per_curve", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "partial", 0, nullptr, ICON_NONE);
+
+ if (RNA_boolean_get(op->ptr, "partial")) {
+ uiItemR(layout, op->ptr, "min", UI_ITEM_R_SLIDER, "Min", ICON_NONE);
+ }
+ else {
+ uiItemR(layout, op->ptr, "probability", UI_ITEM_R_SLIDER, "Probability", ICON_NONE);
+ }
+}
+
+} // namespace select_random
+
+static void SCULPT_CURVES_OT_select_random(wmOperatorType *ot)
+{
+ ot->name = "Select Random";
+ ot->idname = __func__;
+ ot->description = "Randomizes existing selection or create new random selection";
+
+ ot->exec = select_random::select_random_exec;
+ ot->poll = curves::editable_curves_poll;
+ ot->ui = select_random::select_random_ui;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna,
+ "seed",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Seed",
+ "Source of randomness",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_boolean(
+ ot->srna, "partial", false, "Partial", "Allow points or curves to be selected partially");
+ RNA_def_float(ot->srna,
+ "probability",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Probability",
+ "Chance of every point or curve being included in the selection",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "min",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Min",
+ "Minimum value for the random selection",
+ 0.0f,
+ 1.0f);
+ RNA_def_boolean(ot->srna,
+ "constant_per_curve",
+ true,
+ "Constant per Curve",
+ "The generated random number is the same for every control point of a curve");
+}
+
+namespace select_end {
+static bool select_end_poll(bContext *C)
+{
+ if (!curves::editable_curves_poll(C)) {
+ return false;
+ }
+ const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
+ if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
+ CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
+ return false;
+ }
+ return true;
+}
+
+static int select_end_exec(bContext *C, wmOperator *op)
+{
+ VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
+ const bool end_points = RNA_boolean_get(op->ptr, "end_points");
+ const int amount = RNA_int_get(op->ptr, "amount");
+
+ for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ const bool was_anything_selected = curves::has_anything_selected(*curves_id);
+ MutableSpan<float> selection = curves.selection_point_float_for_write();
+ if (!was_anything_selected) {
+ selection.fill(1.0f);
+ }
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ if (end_points) {
+ selection.slice(points.drop_back(amount)).fill(0.0f);
+ }
+ else {
+ selection.slice(points.drop_front(amount)).fill(0.0f);
+ }
+ }
+ });
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ return OPERATOR_FINISHED;
+}
+} // namespace select_end
+
+static void SCULPT_CURVES_OT_select_end(wmOperatorType *ot)
+{
+ ot->name = "Select End";
+ ot->idname = __func__;
+ ot->description = "Select end points of curves";
+
+ ot->exec = select_end::select_end_exec;
+ ot->poll = select_end::select_end_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "end_points",
+ true,
+ "End Points",
+ "Select points at the end of the curve as opposed to the beginning");
+ RNA_def_int(
+ ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX);
+}
+
+namespace select_grow {
+
+struct GrowOperatorDataPerCurve : NonCopyable, NonMovable {
+ Curves *curves_id;
+ Vector<int> selected_point_indices;
+ Vector<int> unselected_point_indices;
+ Array<float> distances_to_selected;
+ Array<float> distances_to_unselected;
+
+ Array<float> original_selection;
+ float pixel_to_distance_factor;
+};
+
+struct GrowOperatorData {
+ int initial_mouse_x;
+ Vector<std::unique_ptr<GrowOperatorDataPerCurve>> per_curve;
+};
+
+static void update_points_selection(const GrowOperatorDataPerCurve &data,
+ const float distance,
+ MutableSpan<float> points_selection)
+{
+ if (distance > 0.0f) {
+ threading::parallel_for(
+ data.unselected_point_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = data.unselected_point_indices[i];
+ const float distance_to_selected = data.distances_to_selected[i];
+ const float selection = distance_to_selected <= distance ? 1.0f : 0.0f;
+ points_selection[point_i] = selection;
+ }
+ });
+ threading::parallel_for(
+ data.selected_point_indices.index_range(), 512, [&](const IndexRange range) {
+ for (const int point_i : data.selected_point_indices.as_span().slice(range)) {
+ points_selection[point_i] = 1.0f;
+ }
+ });
+ }
+ else {
+ threading::parallel_for(
+ data.selected_point_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = data.selected_point_indices[i];
+ const float distance_to_unselected = data.distances_to_unselected[i];
+ const float selection = distance_to_unselected <= -distance ? 0.0f : 1.0f;
+ points_selection[point_i] = selection;
+ }
+ });
+ threading::parallel_for(
+ data.unselected_point_indices.index_range(), 512, [&](const IndexRange range) {
+ for (const int point_i : data.unselected_point_indices.as_span().slice(range)) {
+ points_selection[point_i] = 0.0f;
+ }
+ });
+ }
+}
+
+static int select_grow_update(bContext *C, wmOperator *op, const float mouse_diff_x)
+{
+ GrowOperatorData &op_data = *static_cast<GrowOperatorData *>(op->customdata);
+
+ for (std::unique_ptr<GrowOperatorDataPerCurve> &curve_op_data : op_data.per_curve) {
+ Curves &curves_id = *curve_op_data->curves_id;
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ const float distance = curve_op_data->pixel_to_distance_factor * mouse_diff_x;
+
+ /* Grow or shrink selection based on precomputed distances. */
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ MutableSpan<float> points_selection = curves.selection_point_float_for_write();
+ update_points_selection(*curve_op_data, distance, points_selection);
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ Array<float> new_points_selection(curves.points_num());
+ update_points_selection(*curve_op_data, distance, new_points_selection);
+ /* Propagate grown point selection to the curve selection. */
+ MutableSpan<float> curves_selection = curves.selection_curve_float_for_write();
+ for (const int curve_i : curves.curves_range()) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const Span<float> points_selection = new_points_selection.as_span().slice(points);
+ const float max_selection = *std::max_element(points_selection.begin(),
+ points_selection.end());
+ curves_selection[curve_i] = max_selection;
+ }
+ break;
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void select_grow_invoke_per_curve(Curves &curves_id,
+ Object &curves_ob,
+ const ARegion &region,
+ const View3D &v3d,
+ const RegionView3D &rv3d,
+ GrowOperatorDataPerCurve &curve_op_data)
+{
+ curve_op_data.curves_id = &curves_id;
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ const Span<float3> positions = curves.positions();
+
+ /* Find indices of selected and unselected points. */
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ const VArray<float> points_selection = curves.selection_point_float();
+ curve_op_data.original_selection.reinitialize(points_selection.size());
+ points_selection.materialize(curve_op_data.original_selection);
+ for (const int point_i : points_selection.index_range()) {
+ const float point_selection = points_selection[point_i];
+ if (point_selection > 0.0f) {
+ curve_op_data.selected_point_indices.append(point_i);
+ }
+ else {
+ curve_op_data.unselected_point_indices.append(point_i);
+ }
+ }
+
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ const VArray<float> curves_selection = curves.selection_curve_float();
+ curve_op_data.original_selection.reinitialize(curves_selection.size());
+ curves_selection.materialize(curve_op_data.original_selection);
+ for (const int curve_i : curves_selection.index_range()) {
+ const float curve_selection = curves_selection[curve_i];
+ const IndexRange points = curves.points_for_curve(curve_i);
+ if (curve_selection > 0.0f) {
+ for (const int point_i : points) {
+ curve_op_data.selected_point_indices.append(point_i);
+ }
+ }
+ else {
+ for (const int point_i : points) {
+ curve_op_data.unselected_point_indices.append(point_i);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ threading::parallel_invoke(
+ 1024 < curve_op_data.selected_point_indices.size() +
+ curve_op_data.unselected_point_indices.size(),
+ [&]() {
+ /* Build KD-tree for the selected points. */
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(curve_op_data.selected_point_indices.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
+ for (const int point_i : curve_op_data.selected_point_indices) {
+ const float3 &position = positions[point_i];
+ BLI_kdtree_3d_insert(kdtree, point_i, position);
+ }
+ BLI_kdtree_3d_balance(kdtree);
+
+ /* For each unselected point, compute the distance to the closest selected point. */
+ curve_op_data.distances_to_selected.reinitialize(
+ curve_op_data.unselected_point_indices.size());
+ threading::parallel_for(curve_op_data.unselected_point_indices.index_range(),
+ 256,
+ [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = curve_op_data.unselected_point_indices[i];
+ const float3 &position = positions[point_i];
+ KDTreeNearest_3d nearest;
+ BLI_kdtree_3d_find_nearest(kdtree, position, &nearest);
+ curve_op_data.distances_to_selected[i] = nearest.dist;
+ }
+ });
+ },
+ [&]() {
+ /* Build KD-tree for the unselected points. */
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(curve_op_data.unselected_point_indices.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
+ for (const int point_i : curve_op_data.unselected_point_indices) {
+ const float3 &position = positions[point_i];
+ BLI_kdtree_3d_insert(kdtree, point_i, position);
+ }
+ BLI_kdtree_3d_balance(kdtree);
+
+ /* For each selected point, compute the distance to the closest unselected point. */
+ curve_op_data.distances_to_unselected.reinitialize(
+ curve_op_data.selected_point_indices.size());
+ threading::parallel_for(
+ curve_op_data.selected_point_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = curve_op_data.selected_point_indices[i];
+ const float3 &position = positions[point_i];
+ KDTreeNearest_3d nearest;
+ BLI_kdtree_3d_find_nearest(kdtree, position, &nearest);
+ curve_op_data.distances_to_unselected[i] = nearest.dist;
+ }
+ });
+ });
+
+ float4x4 curves_to_world_mat = curves_ob.obmat;
+ float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(&rv3d, &curves_ob, projection.values);
+
+ /* Compute how mouse movements in screen space are converted into grow/shrink distances in
+ * object space. */
+ curve_op_data.pixel_to_distance_factor = threading::parallel_reduce(
+ curve_op_data.selected_point_indices.index_range(),
+ 256,
+ FLT_MAX,
+ [&](const IndexRange range, float pixel_to_distance_factor) {
+ for (const int i : range) {
+ const int point_i = curve_op_data.selected_point_indices[i];
+ const float3 &pos_cu = positions[point_i];
+
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(&region, pos_cu, pos_re, projection.values);
+ if (pos_re.x < 0 || pos_re.y < 0 || pos_re.x > region.winx || pos_re.y > region.winy) {
+ continue;
+ }
+ /* Compute how far this point moves in curve space when it moves one unit in screen
+ * space. */
+ const float2 pos_offset_re = pos_re + float2(1, 0);
+ float3 pos_offset_wo;
+ ED_view3d_win_to_3d(
+ &v3d, &region, curves_to_world_mat * pos_cu, pos_offset_re, pos_offset_wo);
+ const float3 pos_offset_cu = world_to_curves_mat * pos_offset_wo;
+ const float dist_cu = math::distance(pos_cu, pos_offset_cu);
+ const float dist_re = math::distance(pos_re, pos_offset_re);
+ const float factor = dist_cu / dist_re;
+ math::min_inplace(pixel_to_distance_factor, factor);
+ }
+ return pixel_to_distance_factor;
+ },
+ [](const float a, const float b) { return std::min(a, b); });
+}
+
+static int select_grow_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *active_ob = CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ GrowOperatorData *op_data = MEM_new<GrowOperatorData>(__func__);
+ op->customdata = op_data;
+
+ op_data->initial_mouse_x = event->xy[0];
+
+ Curves &curves_id = *static_cast<Curves *>(active_ob->data);
+ auto curve_op_data = std::make_unique<GrowOperatorDataPerCurve>();
+ select_grow_invoke_per_curve(curves_id, *active_ob, *region, *v3d, *rv3d, *curve_op_data);
+ op_data->per_curve.append(std::move(curve_op_data));
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int select_grow_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ GrowOperatorData &op_data = *static_cast<GrowOperatorData *>(op->customdata);
+ const int mouse_x = event->xy[0];
+ const int mouse_diff_x = mouse_x - op_data.initial_mouse_x;
+ switch (event->type) {
+ case MOUSEMOVE: {
+ select_grow_update(C, op, mouse_diff_x);
+ break;
+ }
+ case LEFTMOUSE: {
+ MEM_delete(&op_data);
+ return OPERATOR_FINISHED;
+ }
+ case EVT_ESCKEY:
+ case RIGHTMOUSE: {
+ /* Undo operator by resetting the selection to the original value. */
+ for (std::unique_ptr<GrowOperatorDataPerCurve> &curve_op_data : op_data.per_curve) {
+ Curves &curves_id = *curve_op_data->curves_id;
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ MutableSpan<float> points_selection = curves.selection_point_float_for_write();
+ points_selection.copy_from(curve_op_data->original_selection);
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ MutableSpan<float> curves_seletion = curves.selection_curve_float_for_write();
+ curves_seletion.copy_from(curve_op_data->original_selection);
+ break;
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
+ }
+ MEM_delete(&op_data);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+} // namespace select_grow
+
+static void SCULPT_CURVES_OT_select_grow(wmOperatorType *ot)
+{
+ ot->name = "Select Grow";
+ ot->idname = __func__;
+ ot->description = "Select curves which are close to curves that are selected already";
+
+ ot->invoke = select_grow::select_grow_invoke;
+ ot->modal = select_grow::select_grow_modal;
+ ot->poll = curves::editable_curves_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+ prop = RNA_def_float(ot->srna,
+ "distance",
+ 0.1f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Distance",
+ "By how much to grow the selection",
+ -10.0f,
+ 10.f);
+ RNA_def_property_subtype(prop, PROP_DISTANCE);
+}
+
+namespace min_distance_edit {
+
+static bool min_distance_edit_poll(bContext *C)
+{
+ if (!curves::curves_with_surface_poll(C)) {
+ return false;
+ }
+ Scene *scene = CTX_data_scene(C);
+ const Brush *brush = BKE_paint_brush_for_read(&scene->toolsettings->curves_sculpt->paint);
+ if (brush == nullptr) {
+ return false;
+ }
+ if (brush->curves_sculpt_tool != CURVES_SCULPT_TOOL_DENSITY) {
+ return false;
+ }
+ return true;
+}
+
+struct MinDistanceEditData {
+ /** Brush whose minimum distance is modified. */
+ Brush *brush;
+ float4x4 curves_to_world_mat;
+
+ /** Where the preview is drawn. */
+ float3 pos_cu;
+ float3 normal_cu;
+
+ int2 initial_mouse;
+ float initial_minimum_distance;
+
+ /** The operator uses a new cursor, but the existing cursors should be restored afterwards. */
+ ListBase orig_paintcursors;
+ void *cursor;
+
+ /** Store the viewport region in case the operator was called from the header. */
+ ARegion *region;
+ RegionView3D *rv3d;
+};
+
+static int calculate_points_per_side(bContext *C, MinDistanceEditData &op_data)
+{
+ Scene *scene = CTX_data_scene(C);
+ ARegion *region = op_data.region;
+
+ const float min_distance = op_data.brush->curves_sculpt_settings->minimum_distance;
+ const float brush_radius = BKE_brush_size_get(scene, op_data.brush);
+
+ float3 tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 0, 1});
+ if (math::is_zero(tangent_x_cu)) {
+ tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 1, 0});
+ }
+ tangent_x_cu = math::normalize(tangent_x_cu);
+ const float3 tangent_y_cu = math::normalize(math::cross(op_data.normal_cu, tangent_x_cu));
+
+ /* Sample a few points to get a good estimate of how large the grid has to be. */
+ Vector<float3> points_wo;
+ points_wo.append(op_data.pos_cu + min_distance * tangent_x_cu);
+ points_wo.append(op_data.pos_cu + min_distance * tangent_y_cu);
+ points_wo.append(op_data.pos_cu - min_distance * tangent_x_cu);
+ points_wo.append(op_data.pos_cu - min_distance * tangent_y_cu);
+
+ Vector<float2> points_re;
+ for (const float3 &pos_wo : points_wo) {
+ float2 pos_re;
+ ED_view3d_project_v2(region, pos_wo, pos_re);
+ points_re.append(pos_re);
+ }
+
+ float2 origin_re;
+ ED_view3d_project_v2(region, op_data.pos_cu, origin_re);
+
+ int needed_points = 0;
+ for (const float2 &pos_re : points_re) {
+ const float distance = math::length(pos_re - origin_re);
+ const int needed_points_iter = (brush_radius * 2.0f) / distance;
+
+ if (needed_points_iter > needed_points) {
+ needed_points = needed_points_iter;
+ }
+ }
+
+ /* Limit to a hard-coded number since it only adds noise at some point. */
+ return std::min(300, needed_points);
+}
+
+static void min_distance_edit_draw(bContext *C, int UNUSED(x), int UNUSED(y), void *customdata)
+{
+ Scene *scene = CTX_data_scene(C);
+ MinDistanceEditData &op_data = *static_cast<MinDistanceEditData *>(customdata);
+
+ const float min_distance = op_data.brush->curves_sculpt_settings->minimum_distance;
+
+ float3 tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 0, 1});
+ if (math::is_zero(tangent_x_cu)) {
+ tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 1, 0});
+ }
+ tangent_x_cu = math::normalize(tangent_x_cu);
+ const float3 tangent_y_cu = math::normalize(math::cross(op_data.normal_cu, tangent_x_cu));
+
+ const int points_per_side = calculate_points_per_side(C, op_data);
+ const int points_per_axis_num = 2 * points_per_side + 1;
+
+ Vector<float3> points_wo;
+ for (const int x_i : IndexRange(points_per_axis_num)) {
+ for (const int y_i : IndexRange(points_per_axis_num)) {
+ const float x_iter = min_distance * (x_i - (points_per_axis_num - 1) / 2.0f);
+ const float y_iter = min_distance * (y_i - (points_per_axis_num - 1) / 2.0f);
+
+ const float3 point_pos_cu = op_data.pos_cu + op_data.normal_cu * 0.0001f +
+ x_iter * tangent_x_cu + y_iter * tangent_y_cu;
+ const float3 point_pos_wo = op_data.curves_to_world_mat * point_pos_cu;
+ points_wo.append(point_pos_wo);
+ }
+ }
+
+ float4 circle_col = float4(op_data.brush->add_col);
+ float circle_alpha = op_data.brush->cursor_overlay_alpha;
+ float brush_radius_re = BKE_brush_size_get(scene, op_data.brush);
+
+ /* Draw the grid. */
+ GPU_matrix_push();
+ GPU_matrix_push_projection();
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ ARegion *region = op_data.region;
+ RegionView3D *rv3d = op_data.rv3d;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* It does the same as: `view3d_operator_needs_opengl(C);`. */
+ wmViewport(&region->winrct);
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
+ GPUVertFormat *format3d = immVertexFormat();
+
+ const uint pos3d = GPU_vertformat_attr_add(format3d, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ const uint col3d = GPU_vertformat_attr_add(format3d, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+
+ GPU_point_size(3.0f);
+ immBegin(GPU_PRIM_POINTS, points_wo.size());
+
+ float3 brush_origin_wo = op_data.curves_to_world_mat * op_data.pos_cu;
+ float2 brush_origin_re;
+ ED_view3d_project_v2(region, brush_origin_wo, brush_origin_re);
+
+ /* Smooth alpha transition until the brush edge. */
+ const int alpha_border_re = 20;
+ const float dist_to_inner_border_re = brush_radius_re - alpha_border_re;
+
+ for (const float3 &pos_wo : points_wo) {
+ float2 pos_re;
+ ED_view3d_project_v2(region, pos_wo, pos_re);
+
+ const float dist_to_point_re = math::distance(pos_re, brush_origin_re);
+ const float alpha = 1.0f - ((dist_to_point_re - dist_to_inner_border_re) / alpha_border_re);
+
+ immAttr4f(col3d, 0.9f, 0.9f, 0.9f, alpha);
+ immVertex3fv(pos3d, pos_wo);
+ }
+ immEnd();
+ immUnbindProgram();
+
+ /* Reset the drawing settings. */
+ GPU_point_size(1.0f);
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ int4 scissor;
+ GPU_scissor_get(scissor);
+ wmWindowViewport(win);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+
+ /* Draw the brush circle. */
+ GPU_matrix_translate_2f((float)op_data.initial_mouse.x, (float)op_data.initial_mouse.y);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos2d = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor3fvAlpha(circle_col, circle_alpha);
+ imm_draw_circle_wire_2d(pos2d, 0.0f, 0.0f, brush_radius_re, 80);
+
+ immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+static int min_distance_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+
+ Object &curves_ob_orig = *CTX_data_active_object(C);
+ Curves &curves_id_orig = *static_cast<Curves *>(curves_ob_orig.data);
+ Object &surface_ob_orig = *curves_id_orig.surface;
+ Object *surface_ob_eval = DEG_get_evaluated_object(depsgraph, &surface_ob_orig);
+ if (surface_ob_eval == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+ Mesh *surface_me_eval = BKE_object_get_evaluated_mesh(surface_ob_eval);
+ if (surface_me_eval == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BVHTreeFromMesh surface_bvh_eval;
+ BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_me_eval, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); });
+
+ const int2 mouse_pos_int_re{event->mval};
+ const float2 mouse_pos_re{mouse_pos_int_re};
+
+ float3 ray_start_wo, ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph, region, v3d, mouse_pos_re, ray_start_wo, ray_end_wo, true);
+
+ const CurvesSurfaceTransforms transforms{curves_ob_orig, &surface_ob_orig};
+
+ const float3 ray_start_su = transforms.world_to_surface * ray_start_wo;
+ const float3 ray_end_su = transforms.world_to_surface * ray_end_wo;
+ const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh_eval.tree,
+ ray_start_su,
+ ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh_eval.raycast_callback,
+ &surface_bvh_eval);
+ if (ray_hit.index == -1) {
+ WM_report(RPT_ERROR, "Cursor must be over the surface mesh");
+ return OPERATOR_CANCELLED;
+ }
+
+ const float3 hit_pos_su = ray_hit.co;
+ const float3 hit_normal_su = ray_hit.no;
+
+ const float3 hit_pos_cu = transforms.surface_to_curves * hit_pos_su;
+ const float3 hit_normal_cu = math::normalize(transforms.surface_to_curves_normal *
+ hit_normal_su);
+
+ MinDistanceEditData *op_data = MEM_new<MinDistanceEditData>(__func__);
+ op_data->curves_to_world_mat = transforms.curves_to_world;
+ op_data->normal_cu = hit_normal_cu;
+ op_data->pos_cu = hit_pos_cu;
+ op_data->initial_mouse = event->xy;
+ op_data->brush = BKE_paint_brush(&scene->toolsettings->curves_sculpt->paint);
+ op_data->initial_minimum_distance = op_data->brush->curves_sculpt_settings->minimum_distance;
+
+ if (op_data->initial_minimum_distance <= 0.0f) {
+ op_data->initial_minimum_distance = 0.01f;
+ }
+
+ op->customdata = op_data;
+
+ /* Temporarily disable other paint cursors. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ op_data->orig_paintcursors = wm->paintcursors;
+ BLI_listbase_clear(&wm->paintcursors);
+
+ /* Add minimum distance paint cursor. */
+ op_data->cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, min_distance_edit_draw, op_data);
+
+ op_data->region = CTX_wm_region(C);
+ op_data->rv3d = CTX_wm_region_view3d(C);
+
+ WM_event_add_modal_handler(C, op);
+ ED_region_tag_redraw(region);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int min_distance_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ MinDistanceEditData &op_data = *static_cast<MinDistanceEditData *>(op->customdata);
+
+ auto finish = [&]() {
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* Remove own cursor. */
+ WM_paint_cursor_end(static_cast<wmPaintCursor *>(op_data.cursor));
+ /* Restore original paint cursors. */
+ wm->paintcursors = op_data.orig_paintcursors;
+
+ ED_region_tag_redraw(region);
+ MEM_freeN(&op_data);
+ };
+
+ switch (event->type) {
+ case MOUSEMOVE: {
+ const int2 mouse_pos_int_re{event->xy};
+ const float2 mouse_pos_re{mouse_pos_int_re};
+
+ const float mouse_diff_x = mouse_pos_int_re.x - op_data.initial_mouse.x;
+ const float factor = powf(2, mouse_diff_x / UI_UNIT_X / 10.0f);
+ op_data.brush->curves_sculpt_settings->minimum_distance = op_data.initial_minimum_distance *
+ factor;
+
+ ED_region_tag_redraw(region);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr);
+ break;
+ }
+ case LEFTMOUSE: {
+ if (event->val == KM_PRESS) {
+ finish();
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
+ case RIGHTMOUSE:
+ case EVT_ESCKEY: {
+ op_data.brush->curves_sculpt_settings->minimum_distance = op_data.initial_minimum_distance;
+ finish();
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+} // namespace min_distance_edit
+
+static void SCULPT_CURVES_OT_min_distance_edit(wmOperatorType *ot)
+{
+ ot->name = "Edit Minimum Distance";
+ ot->idname = __func__;
+ ot->description = "Change the minimum distance used by the density brush";
+
+ ot->poll = min_distance_edit::min_distance_edit_poll;
+ ot->invoke = min_distance_edit::min_distance_edit_invoke;
+ ot->modal = min_distance_edit::min_distance_edit_modal;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
+}
+
} // namespace blender::ed::sculpt_paint
/* -------------------------------------------------------------------- */
@@ -333,6 +1272,10 @@ void ED_operatortypes_sculpt_curves()
using namespace blender::ed::sculpt_paint;
WM_operatortype_append(SCULPT_CURVES_OT_brush_stroke);
WM_operatortype_append(CURVES_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_random);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_end);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_grow);
+ WM_operatortype_append(SCULPT_CURVES_OT_min_distance_edit);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc b/source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc
new file mode 100644
index 00000000000..3e43b1a6361
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc
@@ -0,0 +1,325 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_paint.h"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * `cu`: Local space of the curves object that is being edited.
+ * `su`: Local space of the surface object.
+ * `wo`: World space.
+ * `re`: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+class PinchOperation : public CurvesSculptStrokeOperation {
+ private:
+ bool invert_pinch_;
+ Array<float> segment_lengths_cu_;
+
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ friend struct PinchOperationExecutor;
+
+ public:
+ PinchOperation(const bool invert_pinch) : invert_pinch_(invert_pinch)
+ {
+ }
+
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+struct PinchOperationExecutor {
+ PinchOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+
+ float invert_factor_;
+
+ float2 brush_pos_re_;
+
+ PinchOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(PinchOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_);
+
+ invert_factor_ = self_->invert_pinch_ ? -1.0f : 1.0f;
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ brush_pos_re_ = stroke_extension.mouse_position;
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ if (stroke_extension.is_first) {
+ this->initialize_segment_lengths();
+
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ self_->brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ }
+ }
+
+ Array<bool> changed_curves(curves_->curves_num(), false);
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->pinch_projected_with_symmetry(changed_curves);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->pinch_spherical_with_symmetry(changed_curves);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ this->restore_segment_lengths(changed_curves);
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void pinch_projected_with_symmetry(MutableSpan<bool> r_changed_curves)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->pinch_projected(brush_transform, r_changed_curves);
+ }
+ }
+
+ void pinch_projected(const float4x4 &brush_transform, MutableSpan<bool> r_changed_curves)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 old_pos_cu = deformation.positions[point_i];
+ const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
+ float2 old_symm_pos_re;
+ ED_view3d_project_float_v2_m4(
+ ctx_.region, old_symm_pos_cu, old_symm_pos_re, projection.values);
+
+ const float dist_to_brush_sq_re = math::distance_squared(old_symm_pos_re, brush_pos_re_);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float t = safe_divide(dist_to_brush_re, brush_radius_base_re_);
+ const float radius_falloff = t * BKE_brush_curve_strength(brush_, t, 1.0f);
+ const float weight = invert_factor_ * 0.1f * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+
+ const float2 new_symm_pos_re = math::interpolate(old_symm_pos_re, brush_pos_re_, weight);
+
+ float3 new_symm_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_symm_pos_cu,
+ new_symm_pos_re,
+ new_symm_pos_wo);
+
+ const float3 new_pos_cu = brush_transform * transforms_.world_to_curves *
+ new_symm_pos_wo;
+ const float3 translation_eval = new_pos_cu - old_pos_cu;
+ const float3 translation_orig = deformation.translation_from_deformed_to_original(
+ point_i, translation_eval);
+ positions_cu[point_i] += translation_orig;
+ r_changed_curves[curve_i] = true;
+ }
+ }
+ });
+ }
+
+ void pinch_spherical_with_symmetry(MutableSpan<bool> r_changed_curves)
+ {
+ float3 brush_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_pos_wo);
+ const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->pinch_spherical(brush_transform * brush_pos_cu, brush_radius_cu, r_changed_curves);
+ }
+ }
+
+ void pinch_spherical(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<bool> r_changed_curves)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 old_pos_cu = deformation.positions[point_i];
+
+ const float dist_to_brush_sq_cu = math::distance_squared(old_pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float t = safe_divide(dist_to_brush_cu, brush_radius_cu);
+ const float radius_falloff = t * BKE_brush_curve_strength(brush_, t, 1.0f);
+ const float weight = invert_factor_ * 0.1f * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+
+ const float3 new_pos_cu = math::interpolate(old_pos_cu, brush_pos_cu, weight);
+ const float3 translation_eval = new_pos_cu - old_pos_cu;
+ const float3 translation_orig = deformation.translation_from_deformed_to_original(
+ point_i, translation_eval);
+ positions_cu[point_i] += translation_orig;
+
+ r_changed_curves[curve_i] = true;
+ }
+ }
+ });
+ }
+
+ void initialize_segment_lengths()
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_->points_num());
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[point_i];
+ const float3 &p2_cu = positions_cu[point_i + 1];
+ const float length_cu = math::distance(p1_cu, p2_cu);
+ self_->segment_lengths_cu_[point_i] = length_cu;
+ }
+ }
+ });
+ }
+
+ void restore_segment_lengths(const Span<bool> changed_curves)
+ {
+ const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ if (!changed_curves[curve_i]) {
+ continue;
+ }
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int segment_i : IndexRange(points.size() - 1)) {
+ const float3 &p1_cu = positions_cu[points[segment_i]];
+ float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ const float3 direction = math::normalize(p2_cu - p1_cu);
+ const float expected_length_cu = expected_lengths_cu[points[segment_i]];
+ p2_cu = p1_cu + direction * expected_length_cu;
+ }
+ }
+ });
+ }
+};
+
+void PinchOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
+{
+ PinchOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode,
+ const bContext &C)
+{
+ const Scene &scene = *CTX_data_scene(&C);
+ const Brush &brush = *BKE_paint_brush_for_read(&scene.toolsettings->curves_sculpt->paint);
+
+ const bool invert_pinch = (brush_mode == BRUSH_STROKE_INVERT) !=
+ ((brush.flag & BRUSH_DIR_IN) != 0);
+ return std::make_unique<PinchOperation>(invert_pinch);
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc b/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc
new file mode 100644
index 00000000000..ec69aae372c
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc
@@ -0,0 +1,385 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_crazyspace.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "WM_api.h"
+
+#include "BLI_length_parameterize.hh"
+
+#include "GEO_add_curves_on_mesh.hh"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+class PuffOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ /** Length of each segment indexed by the index of the first point in the segment. */
+ Array<float> segment_lengths_cu_;
+
+ friend struct PuffOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct PuffOperationExecutor {
+ PuffOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+ float2 brush_pos_re_;
+
+ eBrushFalloffShape falloff_shape_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ Object *surface_ob_ = nullptr;
+ Mesh *surface_ = nullptr;
+ Span<MVert> surface_verts_;
+ Span<MLoop> surface_loops_;
+ Span<MLoopTri> surface_looptris_;
+ Span<float3> corner_normals_su_;
+ BVHTreeFromMesh surface_bvh_;
+
+ PuffOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(PuffOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ UNUSED_VARS(C, stroke_extension);
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+ if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
+
+ surface_ob_ = curves_id_->surface;
+ surface_ = static_cast<Mesh *>(surface_ob_->data);
+
+ transforms_ = CurvesSurfaceTransforms(*object_, surface_ob_);
+
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
+ }
+ corner_normals_su_ = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
+
+ surface_verts_ = surface_->verts();
+ surface_loops_ = surface_->loops();
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
+
+ if (stroke_extension.is_first) {
+ this->initialize_segment_lengths();
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ }
+ }
+
+ Array<float> curve_weights(curve_selection_.size(), 0.0f);
+
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->find_curve_weights_projected_with_symmetry(curve_weights);
+ }
+ else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->find_curves_weights_spherical_with_symmetry(curve_weights);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ this->puff(curve_weights);
+ this->restore_segment_lengths();
+
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void find_curve_weights_projected_with_symmetry(MutableSpan<float> r_curve_weights)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->find_curve_weights_projected(brush_transform, r_curve_weights);
+ }
+ }
+
+ void find_curve_weights_projected(const float4x4 &brush_transform,
+ MutableSpan<float> r_curve_weights)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_selection_i : range) {
+ const int curve_i = curve_selection_[curve_selection_i];
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ const float3 first_pos_cu = brush_transform_inv * deformation.positions[points[0]];
+ float2 prev_pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, prev_pos_re, projection.values);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 pos_cu = brush_transform_inv * deformation.positions[point_i];
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ BLI_SCOPED_DEFER([&]() { prev_pos_re = pos_re; });
+
+ const float dist_to_brush_sq_re = dist_squared_to_line_segment_v2(
+ brush_pos_re_, prev_pos_re, pos_re);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ const float weight = radius_falloff;
+ math::max_inplace(r_curve_weights[curve_selection_i], weight);
+ }
+ }
+ });
+ }
+
+ void find_curves_weights_spherical_with_symmetry(MutableSpan<float> r_curve_weights)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_pos_wo);
+ const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->find_curves_weights_spherical(
+ brush_transform * brush_pos_cu, brush_radius_cu, r_curve_weights);
+ }
+ }
+
+ void find_curves_weights_spherical(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<float> r_curve_weights)
+ {
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_selection_i : range) {
+ const int curve_i = curve_selection_[curve_selection_i];
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 &prev_pos_cu = deformation.positions[point_i - 1];
+ const float3 &pos_cu = deformation.positions[point_i];
+ const float dist_to_brush_sq_cu = dist_squared_to_line_segment_v3(
+ brush_pos_cu, prev_pos_cu, pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ const float weight = radius_falloff;
+ math::max_inplace(r_curve_weights[curve_selection_i], weight);
+ }
+ }
+ });
+ }
+
+ void puff(const Span<float> curve_weights)
+ {
+ BLI_assert(curve_weights.size() == curve_selection_.size());
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ Vector<float> accumulated_lengths_cu;
+ for (const int curve_selection_i : range) {
+ const int curve_i = curve_selection_[curve_selection_i];
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ const int first_point_i = points[0];
+ const float3 first_pos_cu = positions_cu[first_point_i];
+ const float3 first_pos_su = transforms_.curves_to_surface * first_pos_cu;
+
+ /* Find the nearest position on the surface. The curve will be aligned to the normal of
+ * that point. */
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh_.tree,
+ first_pos_su,
+ &nearest,
+ surface_bvh_.nearest_callback,
+ &surface_bvh_);
+
+ const MLoopTri &looptri = surface_looptris_[nearest.index];
+ const float3 closest_pos_su = nearest.co;
+ const float3 &v0_su = surface_verts_[surface_loops_[looptri.tri[0]].v].co;
+ const float3 &v1_su = surface_verts_[surface_loops_[looptri.tri[1]].v].co;
+ const float3 &v2_su = surface_verts_[surface_loops_[looptri.tri[2]].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, v0_su, v1_su, v2_su, closest_pos_su);
+ const float3 normal_su = geometry::compute_surface_point_normal(
+ looptri, bary_coords, corner_normals_su_);
+ const float3 normal_cu = math::normalize(transforms_.surface_to_curves_normal * normal_su);
+
+ accumulated_lengths_cu.reinitialize(points.size() - 1);
+ length_parameterize::accumulate_lengths<float3>(
+ positions_cu.slice(points), false, accumulated_lengths_cu);
+
+ /* Align curve to the surface normal while making sure that the curve does not fold up much
+ * in the process (e.g. when the curve was pointing in the opposite direction before). */
+ for (const int i : IndexRange(points.size()).drop_front(1)) {
+ const int point_i = points[i];
+ const float3 old_pos_cu = positions_cu[point_i];
+
+ /* Compute final position of the point. */
+ const float length_param_cu = accumulated_lengths_cu[i - 1];
+ const float3 goal_pos_cu = first_pos_cu + length_param_cu * normal_cu;
+
+ const float weight = 0.01f * brush_strength_ * point_factors_[point_i] *
+ curve_weights[curve_selection_i];
+ float3 new_pos_cu = math::interpolate(old_pos_cu, goal_pos_cu, weight);
+
+ /* Make sure the point does not move closer to the root point than it was initially. This
+ * makes the curve kind of "rotate up". */
+ const float old_dist_to_root_cu = math::distance(old_pos_cu, first_pos_cu);
+ const float new_dist_to_root_cu = math::distance(new_pos_cu, first_pos_cu);
+ if (new_dist_to_root_cu < old_dist_to_root_cu) {
+ const float3 offset = math::normalize(new_pos_cu - first_pos_cu);
+ new_pos_cu += (old_dist_to_root_cu - new_dist_to_root_cu) * offset;
+ }
+
+ positions_cu[point_i] = new_pos_cu;
+ }
+ }
+ });
+ }
+
+ void initialize_segment_lengths()
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_->points_num());
+ threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[point_i];
+ const float3 &p2_cu = positions_cu[point_i + 1];
+ const float length_cu = math::distance(p1_cu, p2_cu);
+ self_->segment_lengths_cu_[point_i] = length_cu;
+ }
+ }
+ });
+ }
+
+ void restore_segment_lengths()
+ {
+ const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[segment_i];
+ float3 &p2_cu = positions_cu[segment_i + 1];
+ const float3 direction = math::normalize(p2_cu - p1_cu);
+ const float expected_length_cu = expected_lengths_cu[segment_i];
+ p2_cu = p1_cu + direction * expected_length_cu;
+ }
+ }
+ });
+ }
+};
+
+void PuffOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
+{
+ PuffOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation()
+{
+ return std::make_unique<PuffOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
index f620fed5761..a955a074df2 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
@@ -6,6 +6,8 @@
#include "curves_sculpt_intern.hh"
+#include "ED_curves_sculpt.h"
+
namespace blender::ed::sculpt_paint {
static VArray<float> get_curves_selection(const CurvesGeometry &curves, const eAttrDomain domain)
@@ -62,13 +64,14 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
case ATTR_DOMAIN_POINT: {
const VArray<float> selection = curves.selection_point_float();
if (selection.is_single()) {
- return selection.get_internal_single() == 0.0f ? IndexMask(0) :
+ return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.curves_num());
}
+ const Span<float> point_selection_span = selection.get_internal_span();
return index_mask_ops::find_indices_based_on_predicate(
curves.curves_range(), 512, r_indices, [&](const int curve_i) {
for (const int i : curves.points_for_curve(curve_i)) {
- if (selection[i] > 0.0f) {
+ if (point_selection_span[i] > 0.0f) {
return true;
}
}
@@ -78,7 +81,7 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
case ATTR_DOMAIN_CURVE: {
const VArray<float> selection = curves.selection_curve_float();
if (selection.is_single()) {
- return selection.get_internal_single() == 0.0f ? IndexMask(0) :
+ return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.curves_num());
}
return index_mask_ops::find_indices_based_on_predicate(
@@ -102,4 +105,49 @@ IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_i
r_indices);
}
+static IndexMask retrieve_selected_points(const CurvesGeometry &curves,
+ const eAttrDomain domain,
+ Vector<int64_t> &r_indices)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT: {
+ const VArray<float> selection = curves.selection_point_float();
+ if (selection.is_single()) {
+ return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
+ IndexMask(curves.points_num());
+ }
+ return index_mask_ops::find_indices_based_on_predicate(
+ curves.points_range(), 2048, r_indices, [&](const int i) {
+ return selection[i] > 0.0f;
+ });
+ }
+ case ATTR_DOMAIN_CURVE: {
+ const VArray<float> selection = curves.selection_curve_float();
+ if (selection.is_single()) {
+ return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
+ IndexMask(curves.points_num());
+ }
+ const VArray<float> point_selection = curves.adapt_domain(
+ selection, ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ return index_mask_ops::find_indices_based_on_predicate(
+ curves.points_range(), 2048, r_indices, [&](const int i) {
+ return point_selection[i] > 0.0f;
+ });
+ }
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+IndexMask retrieve_selected_points(const Curves &curves_id, Vector<int64_t> &r_indices)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return CurvesGeometry::wrap(curves_id.geometry).points_range();
+ }
+ return retrieve_selected_points(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain),
+ r_indices);
+}
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
index 69615a3bfb4..cc5a5e7ae8a 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
@@ -66,8 +66,7 @@ struct SelectionPaintOperationExecutor {
float2 brush_pos_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
SelectionPaintOperationExecutor(const bContext &C) : ctx_(C)
{
@@ -105,8 +104,7 @@ struct SelectionPaintOperationExecutor {
}
}
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
@@ -142,6 +140,7 @@ struct SelectionPaintOperationExecutor {
* selection is handled as a generic attribute for now. */
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ctx_.rv3d->rflag &= ~RV3D_PAINTING;
ED_region_tag_redraw(ctx_.region);
}
@@ -162,14 +161,15 @@ struct SelectionPaintOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
- Span<float3> positions_cu = curves_->positions();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) {
for (const int point_i : point_range) {
- const float3 pos_cu = brush_transform_inv * positions_cu[point_i];
+ const float3 pos_cu = brush_transform_inv * deformation.positions[point_i];
/* Find the position of the point in screen space. */
float2 pos_re;
@@ -201,10 +201,10 @@ struct SelectionPaintOperationExecutor {
float3 brush_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -216,14 +216,15 @@ struct SelectionPaintOperationExecutor {
void paint_point_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu)
{
- Span<float3> positions_cu = curves_->positions();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) {
for (const int i : point_range) {
- const float3 pos_old_cu = positions_cu[i];
+ const float3 pos_old_cu = deformation.positions[i];
/* Compute distance to the brush. */
const float distance_to_brush_sq_cu = math::distance_squared(pos_old_cu, brush_cu);
@@ -257,9 +258,11 @@ struct SelectionPaintOperationExecutor {
void paint_curve_selection_projected(const float4x4 &brush_transform,
MutableSpan<float> selection)
{
- const Span<float3> positions_cu = curves_->positions();
const float4x4 brush_transform_inv = brush_transform.inverted();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
float4x4 projection;
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
@@ -275,8 +278,8 @@ struct SelectionPaintOperationExecutor {
[&](const IndexRange segment_range, const float init) {
float max_weight = init;
for (const int segment_i : segment_range) {
- const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i];
- const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
+ const float3 pos1_cu = brush_transform_inv * deformation.positions[segment_i];
+ const float3 pos2_cu = brush_transform_inv * deformation.positions[segment_i + 1];
float2 pos1_re;
float2 pos2_re;
@@ -309,10 +312,10 @@ struct SelectionPaintOperationExecutor {
float3 brush_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -324,7 +327,8 @@ struct SelectionPaintOperationExecutor {
void paint_curve_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu)
{
- const Span<float3> positions_cu = curves_->positions();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
@@ -338,8 +342,8 @@ struct SelectionPaintOperationExecutor {
[&](const IndexRange segment_range, const float init) {
float max_weight = init;
for (const int segment_i : segment_range) {
- const float3 &pos1_cu = positions_cu[segment_i];
- const float3 &pos2_cu = positions_cu[segment_i + 1];
+ const float3 &pos1_cu = deformation.positions[segment_i];
+ const float3 &pos2_cu = deformation.positions[segment_i + 1];
const float distance_sq_cu = dist_squared_to_line_segment_v3(
brush_cu, pos1_cu, pos2_cu);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
new file mode 100644
index 00000000000..1108f5c72a9
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
@@ -0,0 +1,498 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float3x3.hh"
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GEO_add_curves_on_mesh.hh"
+#include "GEO_reverse_uv_sampler.hh"
+
+#include "BLT_translation.h"
+
+namespace blender::ed::sculpt_paint {
+
+using geometry::ReverseUVSampler;
+
+struct SlideCurveInfo {
+ /** Index of the curve to slide. */
+ int curve_i;
+ /** A weight based on the initial distance to the brush. */
+ float radius_falloff;
+ /**
+ * Normal of the surface where the curve was attached. This is used to rotate the curve if it is
+ * moved to a place with a different normal.
+ */
+ float3 initial_normal_cu;
+};
+
+struct SlideInfo {
+ /** The transform used for the curves below (e.g. for symmetry). */
+ float4x4 brush_transform;
+ Vector<SlideCurveInfo> curves_to_slide;
+};
+
+class SlideOperation : public CurvesSculptStrokeOperation {
+ private:
+ float2 initial_brush_pos_re_;
+ /** Information about which curves to slide. This is initialized when the brush starts. */
+ Vector<SlideInfo> slide_info_;
+ /** Positions of all curve points at the start of sliding. */
+ Array<float3> initial_positions_cu_;
+ /** Deformed positions of all curve points at the start of sliding. */
+ Array<float3> initial_deformed_positions_cu_;
+
+ friend struct SlideOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct SlideOperationExecutor {
+ SlideOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+
+ Object *curves_ob_orig_ = nullptr;
+ Curves *curves_id_orig_ = nullptr;
+ CurvesGeometry *curves_orig_ = nullptr;
+
+ Object *surface_ob_orig_ = nullptr;
+ Mesh *surface_orig_ = nullptr;
+ Span<MLoopTri> surface_looptris_orig_;
+ VArraySpan<float2> surface_uv_map_orig_;
+ Span<float3> corner_normals_orig_su_;
+
+ Object *surface_ob_eval_ = nullptr;
+ Mesh *surface_eval_ = nullptr;
+ Span<MVert> surface_verts_eval_;
+ Span<MLoop> surface_loops_eval_;
+ Span<MLoopTri> surface_looptris_eval_;
+ VArraySpan<float2> surface_uv_map_eval_;
+ BVHTreeFromMesh surface_bvh_eval_;
+
+ VArray<float> curve_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ float2 brush_pos_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ std::atomic<bool> found_invalid_uv_mapping_{false};
+
+ SlideOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SlideOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ UNUSED_VARS(C, stroke_extension);
+ self_ = &self;
+
+ curves_ob_orig_ = CTX_data_active_object(&C);
+ curves_id_orig_ = static_cast<Curves *>(curves_ob_orig_->data);
+ curves_orig_ = &CurvesGeometry::wrap(curves_id_orig_->geometry);
+ if (curves_id_orig_->surface == nullptr || curves_id_orig_->surface->type != OB_MESH) {
+ report_missing_surface(stroke_extension.reports);
+ return;
+ }
+ if (curves_orig_->curves_num() == 0) {
+ return;
+ }
+ if (curves_id_orig_->surface_uv_map == nullptr) {
+ report_missing_uv_map_on_original_surface(stroke_extension.reports);
+ return;
+ }
+ if (curves_orig_->surface_uv_coords().is_empty()) {
+ BKE_report(stroke_extension.reports,
+ RPT_WARNING,
+ TIP_("Curves do not have surface attachment information"));
+ return;
+ }
+ const StringRefNull uv_map_name = curves_id_orig_->surface_uv_map;
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+
+ curve_factors_ = get_curves_selection(*curves_id_orig_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_orig_, selected_curve_indices_);
+
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ transforms_ = CurvesSurfaceTransforms(*curves_ob_orig_, curves_id_orig_->surface);
+
+ surface_ob_orig_ = curves_id_orig_->surface;
+ surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data);
+ if (surface_orig_->totpoly == 0) {
+ report_empty_original_surface(stroke_extension.reports);
+ return;
+ }
+ surface_looptris_orig_ = {BKE_mesh_runtime_looptri_ensure(surface_orig_),
+ BKE_mesh_runtime_looptri_len(surface_orig_)};
+ surface_uv_map_orig_ = surface_orig_->attributes().lookup<float2>(uv_map_name,
+ ATTR_DOMAIN_CORNER);
+ if (surface_uv_map_orig_.is_empty()) {
+ report_missing_uv_map_on_original_surface(stroke_extension.reports);
+ return;
+ }
+ if (!CustomData_has_layer(&surface_orig_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_orig_);
+ }
+ corner_normals_orig_su_ = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_orig_->ldata, CD_NORMAL)),
+ surface_orig_->totloop};
+
+ surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
+ if (surface_ob_eval_ == nullptr) {
+ return;
+ }
+ surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_);
+ if (surface_eval_ == nullptr) {
+ return;
+ }
+ if (surface_eval_->totpoly == 0) {
+ report_empty_evaluated_surface(stroke_extension.reports);
+ return;
+ }
+ surface_looptris_eval_ = {BKE_mesh_runtime_looptri_ensure(surface_eval_),
+ BKE_mesh_runtime_looptri_len(surface_eval_)};
+ surface_verts_eval_ = surface_eval_->verts();
+ surface_loops_eval_ = surface_eval_->loops();
+ surface_uv_map_eval_ = surface_eval_->attributes().lookup<float2>(uv_map_name,
+ ATTR_DOMAIN_CORNER);
+ if (surface_uv_map_eval_.is_empty()) {
+ report_missing_uv_map_on_evaluated_surface(stroke_extension.reports);
+ return;
+ }
+ BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
+
+ if (stroke_extension.is_first) {
+ self_->initial_brush_pos_re_ = brush_pos_re_;
+ /* Remember original and deformed positions of all points. Otherwise this information is lost
+ * when sliding starts, but it's still used. */
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
+ self_->initial_positions_cu_ = curves_orig_->positions();
+ self_->initial_deformed_positions_cu_ = deformation.positions;
+
+ /* First find all curves to slide. When the mouse moves, only those curves will be moved. */
+ this->find_curves_to_slide_with_symmetry();
+ return;
+ }
+ this->slide_with_symmetry();
+
+ if (found_invalid_uv_mapping_) {
+ BKE_report(
+ stroke_extension.reports, RPT_WARNING, TIP_("UV map or surface attachment is invalid"));
+ }
+
+ curves_orig_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_orig_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_orig_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void find_curves_to_slide_with_symmetry()
+ {
+ const Vector<float4x4> brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_orig_->symmetry));
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_eval_,
+ brush_pos_re_,
+ brush_radius_re);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+ const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_, surface_looptris_orig_};
+ for (const float4x4 &brush_transform : brush_transforms) {
+ self_->slide_info_.append_as();
+ SlideInfo &slide_info = self_->slide_info_.last();
+ slide_info.brush_transform = brush_transform;
+ this->find_curves_to_slide(brush_transform * brush_3d->position_cu,
+ brush_3d->radius_cu,
+ reverse_uv_sampler_orig,
+ slide_info.curves_to_slide);
+ }
+ }
+
+ void find_curves_to_slide(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ const ReverseUVSampler &reverse_uv_sampler_orig,
+ Vector<SlideCurveInfo> &r_curves_to_slide)
+ {
+ const Span<float2> surface_uv_coords = curves_orig_->surface_uv_coords();
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ const Span<int> offsets = curves_orig_->offsets();
+ for (const int curve_i : curve_selection_) {
+ const int first_point_i = offsets[curve_i];
+ const float3 old_pos_cu = self_->initial_deformed_positions_cu_[first_point_i];
+ const float dist_to_brush_sq_cu = math::distance_squared(old_pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ /* Root point is too far away from curve center. */
+ continue;
+ }
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+
+ const float2 uv = surface_uv_coords[curve_i];
+ ReverseUVSampler::Result result = reverse_uv_sampler_orig.sample(uv);
+ if (result.type != ReverseUVSampler::ResultType::Ok) {
+ /* The curve does not have a valid surface attachment. */
+ found_invalid_uv_mapping_.store(true);
+ continue;
+ }
+ /* Compute the normal at the initial surface position. */
+ const float3 normal_cu = math::normalize(
+ transforms_.surface_to_curves_normal *
+ geometry::compute_surface_point_normal(
+ *result.looptri, result.bary_weights, corner_normals_orig_su_));
+
+ r_curves_to_slide.append({curve_i, radius_falloff, normal_cu});
+ }
+ }
+
+ void slide_with_symmetry()
+ {
+ const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_, surface_looptris_orig_};
+ for (const SlideInfo &slide_info : self_->slide_info_) {
+ this->slide(slide_info.curves_to_slide, reverse_uv_sampler_orig, slide_info.brush_transform);
+ }
+ }
+
+ void slide(const Span<SlideCurveInfo> slide_curves,
+ const ReverseUVSampler &reverse_uv_sampler_orig,
+ const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ const Span<MVert> verts_orig_su = surface_orig_->verts();
+ const Span<MLoop> loops_orig = surface_orig_->loops();
+
+ MutableSpan<float3> positions_orig_cu = curves_orig_->positions_for_write();
+ MutableSpan<float2> surface_uv_coords = curves_orig_->surface_uv_coords_for_write();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values);
+
+ const float2 brush_pos_diff_re = brush_pos_re_ - self_->initial_brush_pos_re_;
+
+ /* The brush transformation has to be applied in curves space. */
+ const float4x4 world_to_surface_with_symmetry_mat = transforms_.curves_to_surface *
+ brush_transform *
+ transforms_.world_to_curves;
+
+ threading::parallel_for(slide_curves.index_range(), 256, [&](const IndexRange range) {
+ for (const SlideCurveInfo &slide_curve_info : slide_curves.slice(range)) {
+ const int curve_i = slide_curve_info.curve_i;
+ const IndexRange points = curves_orig_->points_for_curve(curve_i);
+ const int first_point_i = points[0];
+
+ const float3 old_first_pos_eval_cu = self_->initial_deformed_positions_cu_[first_point_i];
+ const float3 old_first_symm_pos_eval_cu = brush_transform_inv * old_first_pos_eval_cu;
+ const float3 old_first_pos_eval_su = transforms_.curves_to_surface * old_first_pos_eval_cu;
+
+ float2 old_first_symm_pos_eval_re;
+ ED_view3d_project_float_v2_m4(ctx_.region,
+ old_first_symm_pos_eval_cu,
+ old_first_symm_pos_eval_re,
+ projection.values);
+
+ const float radius_falloff = slide_curve_info.radius_falloff;
+ const float curve_weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
+ const float2 new_first_symm_pos_eval_re = old_first_symm_pos_eval_re +
+ curve_weight * brush_pos_diff_re;
+
+ /* Compute the ray that will be used to find the new position on the surface. */
+ float3 ray_start_wo, ray_end_wo;
+ ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
+ ctx_.region,
+ ctx_.v3d,
+ new_first_symm_pos_eval_re,
+ ray_start_wo,
+ ray_end_wo,
+ true);
+ const float3 ray_start_su = world_to_surface_with_symmetry_mat * ray_start_wo;
+ const float3 ray_end_su = world_to_surface_with_symmetry_mat * ray_end_wo;
+ const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
+
+ /* Find the ray hit that is closest to the initial curve root position. */
+ int looptri_index_eval;
+ float3 hit_pos_eval_su;
+ if (!this->find_closest_ray_hit(ray_start_su,
+ ray_direction_su,
+ old_first_pos_eval_su,
+ looptri_index_eval,
+ hit_pos_eval_su)) {
+ continue;
+ }
+
+ /* Compute the uv of the new surface position on the evaluated mesh. */
+ const MLoopTri &looptri_eval = surface_looptris_eval_[looptri_index_eval];
+ const float3 bary_weights_eval = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
+ surface_verts_eval_, surface_loops_eval_, looptri_eval, hit_pos_eval_su);
+ const float2 uv = attribute_math::mix3(bary_weights_eval,
+ surface_uv_map_eval_[looptri_eval.tri[0]],
+ surface_uv_map_eval_[looptri_eval.tri[1]],
+ surface_uv_map_eval_[looptri_eval.tri[2]]);
+
+ /* Try to find the same uv on the original surface. */
+ const ReverseUVSampler::Result result = reverse_uv_sampler_orig.sample(uv);
+ if (result.type != ReverseUVSampler::ResultType::Ok) {
+ found_invalid_uv_mapping_.store(true);
+ continue;
+ }
+ const MLoopTri &looptri_orig = *result.looptri;
+ const float3 &bary_weights_orig = result.bary_weights;
+
+ /* Gather old and new surface normal. */
+ const float3 &initial_normal_cu = slide_curve_info.initial_normal_cu;
+ const float3 new_normal_cu = math::normalize(
+ transforms_.surface_to_curves_normal *
+ geometry::compute_surface_point_normal(
+ *result.looptri, result.bary_weights, corner_normals_orig_su_));
+
+ /* Gather old and new surface position. */
+ const float3 old_first_pos_orig_cu = self_->initial_positions_cu_[first_point_i];
+ const float3 new_first_pos_orig_cu =
+ transforms_.surface_to_curves *
+ attribute_math::mix3<float3>(bary_weights_orig,
+ verts_orig_su[loops_orig[looptri_orig.tri[0]].v].co,
+ verts_orig_su[loops_orig[looptri_orig.tri[1]].v].co,
+ verts_orig_su[loops_orig[looptri_orig.tri[2]].v].co);
+
+ /* Actually transform curve points. */
+ const float4x4 slide_transform = this->get_slide_transform(
+ old_first_pos_orig_cu, new_first_pos_orig_cu, initial_normal_cu, new_normal_cu);
+ for (const int point_i : points) {
+ positions_orig_cu[point_i] = slide_transform * self_->initial_positions_cu_[point_i];
+ }
+ surface_uv_coords[curve_i] = uv;
+ }
+ });
+ }
+
+ bool find_closest_ray_hit(const float3 &ray_start_su,
+ const float3 &ray_direction_su,
+ const float3 &point_su,
+ int &r_looptri_index,
+ float3 &r_hit_pos)
+ {
+ float best_dist_sq_su = FLT_MAX;
+ int best_looptri_index_eval;
+ float3 best_hit_pos_su;
+ BLI_bvhtree_ray_cast_all_cpp(
+ *surface_bvh_eval_.tree,
+ ray_start_su,
+ ray_direction_su,
+ 0.0f,
+ FLT_MAX,
+ [&](const int looptri_index, const BVHTreeRay &ray, BVHTreeRayHit &hit) {
+ surface_bvh_eval_.raycast_callback(&surface_bvh_eval_, looptri_index, &ray, &hit);
+ if (hit.index < 0) {
+ return;
+ }
+ const float3 &hit_pos_su = hit.co;
+ const float dist_sq_su = math::distance_squared(hit_pos_su, point_su);
+ if (dist_sq_su < best_dist_sq_su) {
+ best_dist_sq_su = dist_sq_su;
+ best_hit_pos_su = hit_pos_su;
+ best_looptri_index_eval = hit.index;
+ }
+ });
+
+ if (best_dist_sq_su == FLT_MAX) {
+ return false;
+ }
+ r_looptri_index = best_looptri_index_eval;
+ r_hit_pos = best_hit_pos_su;
+ return true;
+ }
+
+ float4x4 get_slide_transform(const float3 &old_root_pos,
+ const float3 &new_root_pos,
+ const float3 &old_normal,
+ const float3 &new_normal)
+ {
+ float3x3 rotation_3x3;
+ rotation_between_vecs_to_mat3(rotation_3x3.values, old_normal, new_normal);
+ float4x4 rotation_4x4;
+ copy_m4_m3(rotation_4x4.values, rotation_3x3.values);
+
+ float4x4 transform = float4x4::identity();
+ sub_v3_v3(transform.values[3], old_root_pos);
+ mul_m4_m4_pre(transform.values, rotation_4x4.values);
+ add_v3_v3(transform.values[3], new_root_pos);
+ return transform;
+ }
+};
+
+void SlideOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
+{
+ SlideOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation()
+{
+ return std::make_unique<SlideOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc b/source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc
new file mode 100644
index 00000000000..37a7f1c83ed
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_crazyspace.hh"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_brush_types.h"
+
+#include "WM_api.h"
+
+#include "BLI_enumerable_thread_specific.hh"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+class SmoothOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ friend struct SmoothOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct SmoothOperationExecutor {
+ SmoothOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+ float2 brush_pos_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ SmoothOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SmoothOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ UNUSED_VARS(C, stroke_extension);
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+ if (stroke_extension.is_first) {
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ }
+ }
+
+ Array<float> point_smooth_factors(curves_->points_num(), 0.0f);
+
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->find_projected_smooth_factors_with_symmetry(point_smooth_factors);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->find_spherical_smooth_factors_with_symmetry(point_smooth_factors);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ this->smooth(point_smooth_factors);
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void find_projected_smooth_factors_with_symmetry(MutableSpan<float> r_point_smooth_factors)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->find_projected_smooth_factors(brush_transform, r_point_smooth_factors);
+ }
+ }
+
+ void find_projected_smooth_factors(const float4x4 &brush_transform,
+ MutableSpan<float> r_point_smooth_factors)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points) {
+ const float3 &pos_cu = brush_transform_inv * deformation.positions[point_i];
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
+ * large. */
+ const float weight_factor = 0.1f;
+ const float weight = weight_factor * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+ math::max_inplace(r_point_smooth_factors[point_i], weight);
+ }
+ }
+ });
+ }
+
+ void find_spherical_smooth_factors_with_symmetry(MutableSpan<float> r_point_smooth_factors)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_pos_wo);
+ const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->find_spherical_smooth_factors(
+ brush_transform * brush_pos_cu, brush_radius_cu, r_point_smooth_factors);
+ }
+ }
+
+ void find_spherical_smooth_factors(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<float> r_point_smooth_factors)
+ {
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points) {
+ const float3 &pos_cu = deformation.positions[point_i];
+ const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
+ * large. */
+ const float weight_factor = 0.1f;
+ const float weight = weight_factor * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+ math::max_inplace(r_point_smooth_factors[point_i], weight);
+ }
+ }
+ });
+ }
+
+ void smooth(const Span<float> point_smooth_factors)
+ {
+ MutableSpan<float3> positions = curves_->positions_for_write();
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ Vector<float3> old_positions;
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ old_positions.clear();
+ old_positions.extend(positions.slice(points));
+ for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
+ const int point_i = points[i];
+ const float smooth_factor = point_smooth_factors[point_i];
+ if (smooth_factor == 0.0f) {
+ continue;
+ }
+ /* Move towards the middle of the neighboring points. */
+ const float3 old_pos = old_positions[i];
+ const float3 &prev_pos = old_positions[i - 1];
+ const float3 &next_pos = old_positions[i + 1];
+ const float3 goal_pos = math::midpoint(prev_pos, next_pos);
+ const float3 new_pos = math::interpolate(old_pos, goal_pos, smooth_factor);
+ positions[point_i] = new_pos;
+ }
+ }
+ });
+ }
+};
+
+void SmoothOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ SmoothOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation()
+{
+ return std::make_unique<SmoothOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index e1aecabdcc7..54b81fa221d 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -89,8 +89,7 @@ struct SnakeHookOperatorExecutor {
Vector<int64_t> selected_curve_indices_;
IndexMask curve_selection_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
@@ -118,15 +117,14 @@ struct SnakeHookOperatorExecutor {
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
-
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
if (curves_->curves_num() == 0) {
return;
}
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
curve_factors_ = get_curves_selection(*curves_id_);
curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
@@ -178,6 +176,8 @@ struct SnakeHookOperatorExecutor {
void projected_snake_hook(const float4x4 &brush_transform)
{
const float4x4 brush_transform_inv = brush_transform.inverted();
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
MutableSpan<float3> positions_cu = curves_->positions_for_write();
@@ -191,12 +191,14 @@ struct SnakeHookOperatorExecutor {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
const int last_point_i = points.last();
- const float3 old_pos_cu = brush_transform_inv * positions_cu[last_point_i];
+ const float3 old_pos_cu = deformation.positions[last_point_i];
+ const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
- float2 old_pos_re;
- ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
+ float2 old_symm_pos_re;
+ ED_view3d_project_float_v2_m4(
+ ctx_.region, old_symm_pos_cu, old_symm_pos_re, projection.values);
- const float distance_to_brush_sq_re = math::distance_squared(old_pos_re,
+ const float distance_to_brush_sq_re = math::distance_squared(old_symm_pos_re,
brush_pos_prev_re_);
if (distance_to_brush_sq_re > brush_radius_sq_re) {
continue;
@@ -206,16 +208,21 @@ struct SnakeHookOperatorExecutor {
brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
- const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
- float3 new_position_wo;
+ const float2 new_symm_pos_re = old_symm_pos_re + brush_pos_diff_re_ * weight;
+ float3 new_symm_pos_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * old_pos_cu,
- new_position_re,
- new_position_wo);
- const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo);
-
- move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
+ transforms_.curves_to_world * old_symm_pos_cu,
+ new_symm_pos_re,
+ new_symm_pos_wo);
+ const float3 new_pos_cu = brush_transform *
+ (transforms_.world_to_curves * new_symm_pos_wo);
+ const float3 translation_eval = new_pos_cu - old_pos_cu;
+ const float3 translation_orig = deformation.translation_from_deformed_to_original(
+ last_point_i, translation_eval);
+
+ move_last_point_and_resample(positions_cu.slice(points),
+ positions_cu[last_point_i] + translation_orig);
}
});
}
@@ -228,16 +235,16 @@ struct SnakeHookOperatorExecutor {
float3 brush_start_wo, brush_end_wo;
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
ED_view3d_win_to_3d(ctx_.v3d,
ctx_.region,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -253,6 +260,9 @@ struct SnakeHookOperatorExecutor {
const float3 &brush_end_cu,
const float brush_radius_cu)
{
+ const bke::crazyspace::GeometryDeformation deformation =
+ bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
+
MutableSpan<float3> positions_cu = curves_->positions_for_write();
const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
@@ -261,7 +271,7 @@ struct SnakeHookOperatorExecutor {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
const int last_point_i = points.last();
- const float3 old_pos_cu = positions_cu[last_point_i];
+ const float3 old_pos_cu = deformation.positions[last_point_i];
const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3(
old_pos_cu, brush_start_cu, brush_end_cu);
@@ -275,9 +285,12 @@ struct SnakeHookOperatorExecutor {
brush_, distance_to_brush_cu, brush_radius_cu);
const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
- const float3 new_pos_cu = old_pos_cu + weight * brush_diff_cu;
+ const float3 translation_eval = weight * brush_diff_cu;
+ const float3 translation_orig = deformation.translation_from_deformed_to_original(
+ last_point_i, translation_eval);
- move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(points),
+ positions_cu[last_point_i] + translation_orig);
}
});
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index c5ebcf870a3..164e13ac3c9 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -628,7 +628,7 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
/* Premultiplied alpha blending. */
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR);
float final_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
if (!col) {
@@ -720,7 +720,7 @@ static bool paint_draw_cursor_overlay(
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR);
float final_color[4] = {UNPACK3(U.sculpt_paint_overlay_col), 1.0f};
mul_v4_fl(final_color, brush->cursor_overlay_alpha * 0.01f);
@@ -915,7 +915,7 @@ static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
/* Draw the bezier handles and the curve segment between the current and next point. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float selec_col[4], handle_col[4], pivot_col[4];
UI_GetThemeColorType4fv(TH_VERTEX_SELECT, SPACE_VIEW3D, selec_col);
@@ -1145,11 +1145,10 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr,
}
GPU_line_width(1.0f);
- if (ss->preview_vert_index_count > 0) {
- immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
- for (int i = 0; i < ss->preview_vert_index_count; i++) {
- immVertex3fv(gpuattr,
- SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_index_list[i]));
+ if (ss->preview_vert_count > 0) {
+ immBegin(GPU_PRIM_LINES, ss->preview_vert_count);
+ for (int i = 0; i < ss->preview_vert_count; i++) {
+ immVertex3fv(gpuattr, SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_list[i]));
}
immEnd();
}
@@ -1209,7 +1208,7 @@ typedef struct PaintCursorContext {
/* Sculpt related data. */
Sculpt *sd;
SculptSession *ss;
- int prev_active_vertex_index;
+ PBVHVertRef prev_active_vertex;
bool is_stroke_active;
bool is_cursor_over_mesh;
bool is_multires;
@@ -1366,7 +1365,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
/* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to
* work correctly */
- pcontext->prev_active_vertex_index = ss->active_vertex_index;
+ pcontext->prev_active_vertex = ss->active_vertex;
if (!ups->stroke_active) {
pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
@@ -1549,7 +1548,7 @@ static void paint_cursor_preview_boundary_data_update(PaintCursorContext *pconte
}
ss->boundary_preview = SCULPT_boundary_data_init(
- pcontext->vc.obact, pcontext->brush, ss->active_vertex_index, pcontext->radius);
+ pcontext->vc.obact, pcontext->brush, ss->active_vertex, pcontext->radius);
}
static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *pcontext)
@@ -1575,8 +1574,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
paint_cursor_update_object_space_radius(pcontext);
- const bool update_previews = pcontext->prev_active_vertex_index !=
- SCULPT_active_vertex_get(pcontext->ss);
+ const bool update_previews = pcontext->prev_active_vertex.i !=
+ SCULPT_active_vertex_get(pcontext->ss).i;
/* Setup drawing. */
wmViewport(&pcontext->region->winrct);
@@ -1870,7 +1869,7 @@ static void paint_cursor_setup_2D_drawing(PaintCursorContext *pcontext)
GPU_line_smooth(true);
pcontext->pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
static void paint_cursor_setup_3D_drawing(PaintCursorContext *pcontext)
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 944b3f953a0..c1289364fb2 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -78,6 +78,12 @@ static void partialvis_update_mesh(Object *ob,
BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+ bool *hide_vert = CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert");
+ if (hide_vert == NULL) {
+ hide_vert = CustomData_add_layer_named(
+ &me->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, me->totvert, ".hide_vert");
+ }
+
SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
for (i = 0; i < totvert; i++) {
@@ -86,16 +92,11 @@ static void partialvis_update_mesh(Object *ob,
/* Hide vertex if in the hide volume. */
if (is_effected(area, planes, v->co, vmask)) {
- if (action == PARTIALVIS_HIDE) {
- v->flag |= ME_HIDE;
- }
- else {
- v->flag &= ~ME_HIDE;
- }
+ hide_vert[vert_indices[i]] = (action == PARTIALVIS_HIDE);
any_changed = true;
}
- if (!(v->flag & ME_HIDE)) {
+ if (!hide_vert[vert_indices[i]]) {
any_visible = true;
}
}
@@ -350,10 +351,10 @@ static int hide_show_exec(bContext *C, wmOperator *op)
/* Start undo. */
switch (action) {
case PARTIALVIS_HIDE:
- SCULPT_undo_push_begin(ob, "Hide area");
+ SCULPT_undo_push_begin_ex(ob, "Hide area");
break;
case PARTIALVIS_SHOW:
- SCULPT_undo_push_begin(ob, "Show area");
+ SCULPT_undo_push_begin_ex(ob, "Show area");
break;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index 56cd4751881..c852fd25bc4 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -125,7 +125,7 @@ void ED_imapaint_dirty_region(
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
- ListBase *undo_tiles = ED_image_paint_tile_list_get();
+ PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
@@ -158,11 +158,21 @@ void imapaint_image_update(
imapaintpartial.dirty_region.xmax,
imapaintpartial.dirty_region.ymax);
+ /* When buffer is partial updated the planes should be set to a larger value than 8. This will
+ * make sure that partial updating is working but uses more GPU memory as the gpu texture will
+ * have 4 channels. When so the whole texture needs to be reuploaded to the GPU using the new
+ * texture format. */
+ if (ibuf != nullptr && ibuf->planes == 8) {
+ ibuf->planes = 32;
+ BKE_image_partial_update_mark_full_update(image);
+ return;
+ }
+
/* TODO: should set_tpage create ->rect? */
if (texpaint || (sima && sima->lock)) {
const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region);
- /* Testing with partial update in uv editor too */
+ /* Testing with partial update in uv editor too. */
BKE_image_update_gputexture(
image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h);
}
@@ -276,10 +286,11 @@ static bool image_paint_poll_ex(bContext *C, bool check_tool)
(ID_IS_LINKED(sima->image) || ID_IS_OVERRIDE_LIBRARY(sima->image))) {
return false;
}
- ARegion *region = CTX_wm_region(C);
-
- if ((sima->mode == SI_MODE_PAINT) && region->regiontype == RGN_TYPE_WINDOW) {
- return true;
+ if (sima->mode == SI_MODE_PAINT) {
+ const ARegion *region = CTX_wm_region(C);
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ return true;
+ }
}
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index fae2e6863fa..5df65e596b9 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1196,7 +1196,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
ImBuf tmpbuf;
IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0);
- ListBase *undo_tiles = ED_image_paint_tile_list_get();
+ PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
index a671c24c514..928f3e9a496 100644
--- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
+++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
@@ -13,6 +13,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_paint.h"
#include "BKE_undo_system.h"
@@ -252,7 +253,7 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
ARegion *region = pop->vc.region;
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_line_width(4.0);
immUniformColor4ub(0, 0, 0, 255);
@@ -293,7 +294,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
copy_v2_v2(pop->startmouse, mouse);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 50480b8aef0..1ca5df47e17 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -56,6 +56,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -414,6 +415,7 @@ typedef struct ProjPaintState {
const float (*vert_normals)[3];
const MEdge *medge_eval;
const MPoly *mpoly_eval;
+ const int *material_indices;
const MLoop *mloop_eval;
const MLoopTri *mlooptri_eval;
@@ -542,8 +544,8 @@ static int project_paint_face_paint_tile(Image *ima, const float *uv)
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
+ const int poly_i = ps->mlooptri_eval[tri_index].poly;
+ Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
}
@@ -553,23 +555,23 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
return ps->stencil_ima;
}
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
+ const int poly_i = ps->mlooptri_eval[tri_index].poly;
+ Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
return slot ? slot->ima : ps->canvas_ima;
}
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
+ const int poly_i = ps->mlooptri_eval[tri_index].poly;
+ Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
}
static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{
- const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->mat_array[mp->mat_nr];
+ const int poly_i = ps->mlooptri_eval[tri_index].poly;
+ Material *ma = ps->mat_array[ps->material_indices == NULL ? 0 : ps->material_indices[poly_i]];
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
return slot ? slot->ima : ps->clone_ima;
}
@@ -1223,12 +1225,12 @@ static VertSeam *find_adjacent_seam(const ProjPaintState *ps,
/* Circulate through the (sorted) vert seam array, in the direction of the seam normal,
* until we find the first opposing seam, matching in UV space. */
if (seam->normal_cw) {
- LISTBASE_CIRCULAR_BACKWARD_BEGIN (vert_seams, adjacent, seam) {
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN (VertSeam *, vert_seams, adjacent, seam) {
if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) {
break;
}
}
- LISTBASE_CIRCULAR_BACKWARD_END(vert_seams, adjacent, seam);
+ LISTBASE_CIRCULAR_BACKWARD_END(VertSeam *, vert_seams, adjacent, seam);
}
else {
LISTBASE_CIRCULAR_FORWARD_BEGIN (vert_seams, adjacent, seam) {
@@ -1813,7 +1815,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
}
if (generate_tile) {
- ListBase *undo_tiles = ED_image_paint_tile_list_get();
+ struct PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
volatile void *undorect;
if (tinf->masked) {
undorect = ED_image_paint_tile_push(undo_tiles,
@@ -4053,13 +4055,15 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
}
ps->mat_array[totmat - 1] = NULL;
- ps->mvert_eval = ps->me_eval->mvert;
+ ps->mvert_eval = BKE_mesh_verts(ps->me_eval);
ps->vert_normals = BKE_mesh_vertex_normals_ensure(ps->me_eval);
if (ps->do_mask_cavity) {
- ps->medge_eval = ps->me_eval->medge;
+ ps->medge_eval = BKE_mesh_edges(ps->me_eval);
}
- ps->mloop_eval = ps->me_eval->mloop;
- ps->mpoly_eval = ps->me_eval->mpoly;
+ ps->mloop_eval = BKE_mesh_loops(ps->me_eval);
+ ps->mpoly_eval = BKE_mesh_polys(ps->me_eval);
+ ps->material_indices = (const int *)CustomData_get_layer_named(
+ &ps->me_eval->pdata, CD_PROP_INT32, "material_index");
ps->totvert_eval = ps->me_eval->totvert;
ps->totedge_eval = ps->me_eval->totedge;
@@ -4151,7 +4155,7 @@ static void proj_paint_face_lookup_init(const ProjPaintState *ps, ProjPaintFaceL
memset(face_lookup, 0, sizeof(*face_lookup));
if (ps->do_face_sel) {
face_lookup->index_mp_to_orig = CustomData_get_layer(&ps->me_eval->pdata, CD_ORIGINDEX);
- face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
+ face_lookup->mpoly_orig = BKE_mesh_polys((Mesh *)ps->ob->data);
}
}
@@ -6038,7 +6042,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
int orig_brush_size;
IDProperty *idgroup;
IDProperty *view_data = NULL;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
bool uvs, mat, tex;
if (ob == NULL || ob->type != OB_MESH) {
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 3f4e660b229..99c25953d50 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -46,7 +46,10 @@ typedef struct CoNo {
/* paint_stroke.c */
-typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
+typedef bool (*StrokeGetLocation)(struct bContext *C,
+ float location[3],
+ const float mouse[2],
+ bool force_original);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
typedef void (*StrokeUpdateStep)(struct bContext *C,
struct wmOperator *op,
@@ -134,18 +137,10 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_color(struct Scene *scene, struct VPaint *vp, bool secondary);
-/* paint_vertex_color_utils.c */
-
/**
* \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
*/
unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i);
-/**
- * Apply callback to each vertex of the active vertex color layer.
- */
-bool ED_vpaint_color_transform(struct Object *ob,
- VPaintTransform_Callback vpaint_tx_fn,
- const void *user_data);
/* paint_vertex_weight_utils.c */
@@ -378,10 +373,12 @@ void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot);
void PAINT_OT_face_select_all(struct wmOperatorType *ot);
void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
-void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
+
+void PAINT_OT_face_vert_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
+void PAINT_OT_vert_select_hide(struct wmOperatorType *ot);
bool vert_paint_poll(struct bContext *C);
bool mask_paint_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 89bbf2a3c92..332a0830081 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -152,7 +152,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin(ob, "Mask flood fill");
+ SCULPT_undo_push_begin(ob, op);
MaskTaskData data = {
.ob = ob,
@@ -663,7 +663,7 @@ static bool sculpt_gesture_is_effected_lasso(SculptGestureContext *sgcontext, co
static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertexIter *vd)
{
float vertex_normal[3];
- SCULPT_vertex_normal_get(sgcontext->ss, vd->index, vertex_normal);
+ SCULPT_vertex_normal_get(sgcontext->ss, vd->vertex, vertex_normal);
float dot = dot_v3v3(sgcontext->view_normal, vertex_normal);
const bool is_effected_front_face = !(sgcontext->front_faces_only && dot < 0.0f);
@@ -687,10 +687,10 @@ static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, P
return false;
}
-static void sculpt_gesture_apply(bContext *C, SculptGestureContext *sgcontext)
+static void sculpt_gesture_apply(bContext *C, SculptGestureContext *sgcontext, wmOperator *op)
{
SculptGestureOperation *operation = sgcontext->operation;
- SCULPT_undo_push_begin(CTX_data_active_object(C), "Sculpt Gesture Apply");
+ SCULPT_undo_push_begin(CTX_data_active_object(C), op);
operation->sculpt_gesture_begin(C, sgcontext);
@@ -743,7 +743,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
- SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id);
+ SCULPT_vertex_face_set_set(sgcontext->ss, vd.vertex, face_set_operation->new_face_set_id);
any_updated = true;
}
}
@@ -1025,7 +1025,9 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext)
trim_operation->depth_back = -FLT_MAX;
for (int i = 0; i < totvert; i++) {
- const float *vco = SCULPT_vertex_co_get(ss, i);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ const float *vco = SCULPT_vertex_co_get(ss, vertex);
/* Convert the coordinates to world space to calculate the depth. When generating the trimming
* mesh, coordinates are first calculated in world space, then converted to object space to
* store them. */
@@ -1121,6 +1123,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
const float(*ob_imat)[4] = vc->obact->imat;
/* Write vertices coordinates for the front face. */
+ MVert *verts = BKE_mesh_verts_for_write(trim_operation->mesh);
float depth_point[3];
madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_front);
for (int i = 0; i < tot_screen_points; i++) {
@@ -1132,7 +1135,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
ED_view3d_win_to_3d_on_plane(region, shape_plane, screen_points[i], false, new_point);
madd_v3_v3fl(new_point, shape_normal, depth_front);
}
- mul_v3_m4v3(trim_operation->mesh->mvert[i].co, ob_imat, new_point);
+ mul_v3_m4v3(verts[i].co, ob_imat, new_point);
mul_v3_m4v3(trim_operation->true_mesh_co[i], ob_imat, new_point);
}
@@ -1147,7 +1150,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
ED_view3d_win_to_3d_on_plane(region, shape_plane, screen_points[i], false, new_point);
madd_v3_v3fl(new_point, shape_normal, depth_back);
}
- mul_v3_m4v3(trim_operation->mesh->mvert[i + tot_screen_points].co, ob_imat, new_point);
+ mul_v3_m4v3(verts[i + tot_screen_points].co, ob_imat, new_point);
mul_v3_m4v3(trim_operation->true_mesh_co[i + tot_screen_points], ob_imat, new_point);
}
@@ -1157,10 +1160,12 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
BLI_polyfill_calc(screen_points, tot_screen_points, 0, r_tris);
/* Write the front face triangle indices. */
- MPoly *mp = trim_operation->mesh->mpoly;
- MLoop *ml = trim_operation->mesh->mloop;
+ MPoly *polys = BKE_mesh_polys_for_write(trim_operation->mesh);
+ MLoop *loops = BKE_mesh_loops_for_write(trim_operation->mesh);
+ MPoly *mp = polys;
+ MLoop *ml = loops;
for (int i = 0; i < tot_tris_face; i++, mp++, ml += 3) {
- mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->loopstart = (int)(ml - loops);
mp->totloop = 3;
ml[0].v = r_tris[i][0];
ml[1].v = r_tris[i][1];
@@ -1169,7 +1174,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
/* Write the back face triangle indices. */
for (int i = 0; i < tot_tris_face; i++, mp++, ml += 3) {
- mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->loopstart = (int)(ml - loops);
mp->totloop = 3;
ml[0].v = r_tris[i][0] + tot_screen_points;
ml[1].v = r_tris[i][1] + tot_screen_points;
@@ -1180,7 +1185,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
/* Write the indices for the lateral triangles. */
for (int i = 0; i < tot_screen_points; i++, mp++, ml += 3) {
- mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->loopstart = (int)(ml - loops);
mp->totloop = 3;
int current_index = i;
int next_index = current_index + 1;
@@ -1193,7 +1198,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
}
for (int i = 0; i < tot_screen_points; i++, mp++, ml += 3) {
- mp->loopstart = (int)(ml - trim_operation->mesh->mloop);
+ mp->loopstart = (int)(ml - loops);
mp->totloop = 3;
int current_index = i;
int next_index = current_index + 1;
@@ -1328,8 +1333,9 @@ static void sculpt_gesture_trim_apply_for_symmetry_pass(bContext *UNUSED(C),
{
SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
Mesh *trim_mesh = trim_operation->mesh;
+ MVert *verts = BKE_mesh_verts_for_write(trim_mesh);
for (int i = 0; i < trim_mesh->totvert; i++) {
- flip_v3_v3(trim_mesh->mvert[i].co, trim_operation->true_mesh_co[i], sgcontext->symmpass);
+ flip_v3_v3(verts[i].co, trim_operation->true_mesh_co[i], sgcontext->symmpass);
}
sculpt_gesture_trim_normals_update(sgcontext);
sculpt_gesture_apply_trim(sgcontext);
@@ -1437,7 +1443,7 @@ static void project_line_gesture_apply_task_cb(void *__restrict userdata,
}
add_v3_v3(vd.co, disp);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(sgcontext->ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(sgcontext->ss->pbvh, vd.vertex);
}
any_updated = true;
}
@@ -1500,7 +1506,7 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_mask_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1512,7 +1518,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_mask_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1524,7 +1530,7 @@ static int paint_mask_gesture_line_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_mask_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1536,7 +1542,7 @@ static int face_set_gesture_box_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_face_set_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1548,7 +1554,7 @@ static int face_set_gesture_lasso_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_face_set_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1573,7 +1579,7 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op)
}
sculpt_gesture_init_trim_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1614,7 +1620,7 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_trim_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
@@ -1643,7 +1649,7 @@ static int project_gesture_line_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
sculpt_gesture_init_project_properties(sgcontext, op);
- sculpt_gesture_apply(C, sgcontext);
+ sculpt_gesture_apply(C, sgcontext, op);
sculpt_gesture_context_free(sgcontext);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 0f2b02ed3ab..b78c60e7964 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -90,13 +90,13 @@ static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
if (STREQ(tool->runtime->data_block, "DRAW")) {
return GP_BRUSH_PRESET_PENCIL;
}
- else if (STREQ(tool->runtime->data_block, "FILL")) {
+ if (STREQ(tool->runtime->data_block, "FILL")) {
return GP_BRUSH_PRESET_FILL_AREA;
}
- else if (STREQ(tool->runtime->data_block, "ERASE")) {
+ if (STREQ(tool->runtime->data_block, "ERASE")) {
return GP_BRUSH_PRESET_ERASER_SOFT;
}
- else if (STREQ(tool->runtime->data_block, "TINT")) {
+ if (STREQ(tool->runtime->data_block, "TINT")) {
return GP_BRUSH_PRESET_TINT;
}
break;
@@ -105,28 +105,28 @@ static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
if (STREQ(tool->runtime->data_block, "SMOOTH")) {
return GP_BRUSH_PRESET_SMOOTH_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "STRENGTH")) {
+ if (STREQ(tool->runtime->data_block, "STRENGTH")) {
return GP_BRUSH_PRESET_STRENGTH_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "THICKNESS")) {
+ if (STREQ(tool->runtime->data_block, "THICKNESS")) {
return GP_BRUSH_PRESET_THICKNESS_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "GRAB")) {
+ if (STREQ(tool->runtime->data_block, "GRAB")) {
return GP_BRUSH_PRESET_GRAB_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "PUSH")) {
+ if (STREQ(tool->runtime->data_block, "PUSH")) {
return GP_BRUSH_PRESET_PUSH_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "TWIST")) {
+ if (STREQ(tool->runtime->data_block, "TWIST")) {
return GP_BRUSH_PRESET_TWIST_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "PINCH")) {
+ if (STREQ(tool->runtime->data_block, "PINCH")) {
return GP_BRUSH_PRESET_PINCH_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "RANDOMIZE")) {
+ if (STREQ(tool->runtime->data_block, "RANDOMIZE")) {
return GP_BRUSH_PRESET_RANDOMIZE_STROKE;
}
- else if (STREQ(tool->runtime->data_block, "CLONE")) {
+ if (STREQ(tool->runtime->data_block, "CLONE")) {
return GP_BRUSH_PRESET_CLONE_STROKE;
}
break;
@@ -138,23 +138,22 @@ static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
if (STREQ(tool->runtime->data_block, "DRAW")) {
return GP_BRUSH_PRESET_VERTEX_DRAW;
}
- else if (STREQ(tool->runtime->data_block, "BLUR")) {
+ if (STREQ(tool->runtime->data_block, "BLUR")) {
return GP_BRUSH_PRESET_VERTEX_BLUR;
}
- else if (STREQ(tool->runtime->data_block, "AVERAGE")) {
+ if (STREQ(tool->runtime->data_block, "AVERAGE")) {
return GP_BRUSH_PRESET_VERTEX_AVERAGE;
}
- else if (STREQ(tool->runtime->data_block, "SMEAR")) {
+ if (STREQ(tool->runtime->data_block, "SMEAR")) {
return GP_BRUSH_PRESET_VERTEX_SMEAR;
}
- else if (STREQ(tool->runtime->data_block, "REPLACE")) {
+ if (STREQ(tool->runtime->data_block, "REPLACE")) {
return GP_BRUSH_PRESET_VERTEX_REPLACE;
}
break;
}
default:
return GP_BRUSH_PRESET_UNKNOWN;
- break;
}
return GP_BRUSH_PRESET_UNKNOWN;
}
@@ -362,7 +361,6 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = paint->brush;
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
Palette *palette = paint->palette;
PaletteColor *color;
@@ -370,17 +368,20 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
color = BKE_palette_color_add(palette);
palette->active_color = BLI_listbase_count(&palette->colors) - 1;
- if (ELEM(mode,
- PAINT_MODE_TEXTURE_3D,
- PAINT_MODE_TEXTURE_2D,
- PAINT_MODE_VERTEX,
- PAINT_MODE_SCULPT)) {
- copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
- color->value = 0.0;
- }
- else if (mode == PAINT_MODE_WEIGHT) {
- zero_v3(color->rgb);
- color->value = brush->weight;
+ if (paint->brush) {
+ const Brush *brush = paint->brush;
+ if (ELEM(mode,
+ PAINT_MODE_TEXTURE_3D,
+ PAINT_MODE_TEXTURE_2D,
+ PAINT_MODE_VERTEX,
+ PAINT_MODE_SCULPT)) {
+ copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
+ color->value = 0.0;
+ }
+ else if (mode == PAINT_MODE_WEIGHT) {
+ zero_v3(color->rgb);
+ color->value = brush->weight;
+ }
}
return OPERATOR_FINISHED;
@@ -1455,6 +1456,7 @@ void ED_operatortypes_paint(void)
/* vertex selection */
WM_operatortype_append(PAINT_OT_vert_select_all);
WM_operatortype_append(PAINT_OT_vert_select_ungrouped);
+ WM_operatortype_append(PAINT_OT_vert_select_hide);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
@@ -1473,7 +1475,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
WM_operatortype_append(PAINT_OT_face_select_hide);
- WM_operatortype_append(PAINT_OT_face_select_reveal);
+
+ WM_operatortype_append(PAINT_OT_face_vert_reveal);
/* partial visibility */
WM_operatortype_append(PAINT_OT_hide_show);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 63e6dc7e965..60f4a9d59a5 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -79,6 +79,8 @@ typedef struct PaintStroke {
float last_mouse_position[2];
float last_world_space_position[3];
+ float last_scene_spacing_delta[3];
+
bool stroke_over_mesh;
/* space distance covered so far */
float stroke_distance;
@@ -120,6 +122,8 @@ typedef struct PaintStroke {
StrokeUpdateStep update_step;
StrokeRedraw redraw;
StrokeDone done;
+
+ bool original; /* Ray-cast original mesh at start of stroke. */
} PaintStroke;
/*** Cursors ***/
@@ -136,7 +140,7 @@ static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata
ARegion *region = stroke->vc.region;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ubv(paint->paint_cursor_col);
immBegin(GPU_PRIM_LINES, 2);
@@ -164,7 +168,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -243,6 +247,11 @@ static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode)
return false;
}
+static bool paint_tool_raycast_original(Brush *brush, ePaintMode UNUSED(mode))
+{
+ return brush->flag & BRUSH_ANCHORED;
+}
+
static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode)
{
if (brush->flag & BRUSH_ANCHORED) {
@@ -392,7 +401,7 @@ static bool paint_brush_update(bContext *C,
halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
if (stroke->get_location) {
- if (stroke->get_location(C, r_location, halfway)) {
+ if (stroke->get_location(C, r_location, halfway, stroke->original)) {
hit = true;
location_sampled = true;
location_success = true;
@@ -466,7 +475,7 @@ static bool paint_brush_update(bContext *C,
if (!location_sampled) {
if (stroke->get_location) {
- if (stroke->get_location(C, r_location, mouse)) {
+ if (stroke->get_location(C, r_location, mouse, stroke->original)) {
location_success = true;
*r_location_is_set = true;
}
@@ -550,8 +559,16 @@ static void paint_brush_stroke_add_step(
stroke->last_pressure = pressure;
if (paint_stroke_use_scene_spacing(brush, mode)) {
- SCULPT_stroke_get_location(C, stroke->last_world_space_position, stroke->last_mouse_position);
- mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ float world_space_position[3];
+
+ if (SCULPT_stroke_get_location(
+ C, world_space_position, stroke->last_mouse_position, stroke->original)) {
+ copy_v3_v3(stroke->last_world_space_position, world_space_position);
+ mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ }
+ else {
+ add_v3_v3(stroke->last_world_space_position, stroke->last_scene_spacing_delta);
+ }
}
if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
@@ -698,7 +715,7 @@ static float paint_space_stroke_spacing(bContext *C,
spacing *= stroke->zoom_2d;
if (paint_stroke_use_scene_spacing(brush, mode)) {
- return max_ff(0.001f, size_clamp * spacing / 50.0f);
+ return size_clamp * spacing / 50.0f;
}
return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f);
}
@@ -807,7 +824,7 @@ static int paint_space_stroke(bContext *C,
if (use_scene_spacing) {
float world_space_position[3];
- bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse);
+ bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position);
if (hit && stroke->stroke_over_mesh) {
sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position);
@@ -838,6 +855,8 @@ static int paint_space_stroke(bContext *C,
stroke->last_world_space_position,
final_world_space_position);
ED_view3d_project_v2(region, final_world_space_position, mouse);
+
+ mul_v3_v3fl(stroke->last_scene_spacing_delta, d_world_space_position, spacing);
}
else {
mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
@@ -896,6 +915,8 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->ups = ups;
stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
+ stroke->original = paint_tool_raycast_original(br, BKE_paintmode_get_active_from_context(C));
+
get_imapaint_zoom(C, &zoomx, &zoomy);
stroke->zoom_2d = max_ff(zoomx, zoomy);
@@ -995,7 +1016,7 @@ static void stroke_done(bContext *C, wmOperator *op, PaintStroke *stroke)
static bool curves_sculpt_brush_uses_spacing(const eBrushCurvesSculptTool tool)
{
- return ELEM(tool, CURVES_SCULPT_TOOL_ADD);
+ return ELEM(tool, CURVES_SCULPT_TOOL_ADD, CURVES_SCULPT_TOOL_DENSITY);
}
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
@@ -1191,8 +1212,10 @@ static void paint_line_strokes_spacing(bContext *C,
copy_v2_v2(stroke->last_mouse_position, old_pos);
if (use_scene_spacing) {
- bool hit_old = SCULPT_stroke_get_location(C, world_space_position_old, old_pos);
- bool hit_new = SCULPT_stroke_get_location(C, world_space_position_new, new_pos);
+ bool hit_old = SCULPT_stroke_get_location(
+ C, world_space_position_old, old_pos, stroke->original);
+ bool hit_new = SCULPT_stroke_get_location(
+ C, world_space_position_new, new_pos, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position_old);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position_new);
if (hit_old && hit_new && stroke->stroke_over_mesh) {
@@ -1336,7 +1359,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (paint_stroke_use_scene_spacing(br, BKE_paintmode_get_active_from_context(C))) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
- C, stroke->last_world_space_position, data + 2 * j);
+ C, stroke->last_world_space_position, data + 2 * j, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
@@ -1468,7 +1491,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
if (paint_stroke_use_scene_spacing(br, mode)) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
- C, stroke->last_world_space_position, sample_average.mouse);
+ C, stroke->last_world_space_position, sample_average.mouse, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
@@ -1527,8 +1550,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
paint_stroke_line_constrain(stroke, mouse);
- if (stroke->stroke_started &&
- (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
+ if (stroke->stroke_started && (first_modal || ISMOUSE_MOTION(event->type))) {
if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
(br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
@@ -1538,7 +1560,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
}
else if (first_modal ||
/* regular dabs */
- (!(br->flag & BRUSH_AIRBRUSH) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
+ (!(br->flag & BRUSH_AIRBRUSH) && ISMOUSE_MOTION(event->type)) ||
/* airbrush */
((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER &&
event->customdata == stroke->timer)) {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 3f26f590b70..1cedcde7035 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -28,7 +28,9 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -286,9 +288,8 @@ static void imapaint_pick_uv(
const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
const int tottri = me_eval->runtime.looptris.len;
- const MVert *mvert = me_eval->mvert;
- const MPoly *mpoly = me_eval->mpoly;
- const MLoop *mloop = me_eval->mloop;
+ const MVert *mvert = BKE_mesh_verts(me_eval);
+ const MLoop *mloop = BKE_mesh_loops(me_eval);
const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
/* get the needed opengl matrices */
@@ -302,6 +303,9 @@ static void imapaint_pick_uv(
minabsw = 1e10;
uv[0] = uv[1] = 0.0;
+ const int *material_indices = (const int *)CustomData_get_layer_named(
+ &me_eval->pdata, CD_PROP_INT32, "material_index");
+
/* test all faces in the derivedmesh with the original index of the picked face */
/* face means poly here, not triangle, indeed */
for (i = 0; i < tottri; i++, lt++) {
@@ -309,7 +313,6 @@ static void imapaint_pick_uv(
if (findex == faceindex) {
const MLoopUV *mloopuv;
- const MPoly *mp = &mpoly[lt->poly];
const MLoopUV *tri_uv[3];
float tri_co[3][3];
@@ -321,7 +324,8 @@ static void imapaint_pick_uv(
const Material *ma;
const TexPaintSlot *slot;
- ma = BKE_object_material_get(ob_eval, mp->mat_nr + 1);
+ ma = BKE_object_material_get(
+ ob_eval, material_indices == NULL ? 1 : material_indices[lt->poly] + 1);
slot = &ma->texpaintslot[ma->paint_active_slot];
if (!(slot && slot->uvname &&
@@ -400,7 +404,7 @@ void paint_sample_color(
if (v3d && texpaint_proj) {
/* first try getting a color directly from the mesh faces if possible */
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
@@ -410,6 +414,8 @@ void paint_sample_color(
cddata_masks.pmask |= CD_MASK_ORIGINDEX;
Mesh *me = (Mesh *)ob->data;
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &cddata_masks);
+ const int *material_indices = (const int *)CustomData_get_layer_named(
+ &me_eval->pdata, CD_PROP_INT32, "material_index");
ViewContext vc;
const int mval[2] = {x, y};
@@ -427,8 +433,8 @@ void paint_sample_color(
if (use_material) {
/* Image and texture interpolation from material. */
- MPoly *mp = me_eval->mpoly + faceindex;
- Material *ma = BKE_object_material_get(ob_eval, mp->mat_nr + 1);
+ Material *ma = BKE_object_material_get(
+ ob_eval, material_indices ? material_indices[faceindex] + 1 : 1);
/* Force refresh since paint slots are not updated when changing interpolation. */
BKE_texpaint_slot_refresh_cache(scene, ma, ob);
@@ -697,7 +703,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(&me->vertex_group_names) || (me->dvert == NULL)) {
+ if (BLI_listbase_is_empty(&me->vertex_group_names) || (BKE_mesh_deform_verts(me) == NULL)) {
BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
return OPERATOR_CANCELLED;
}
@@ -749,25 +755,68 @@ void PAINT_OT_face_select_hide(wmOperatorType *ot)
ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
}
-static int face_select_reveal_exec(bContext *C, wmOperator *op)
+static int vert_select_hide_exec(bContext *C, wmOperator *op)
+{
+ const bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ Object *ob = CTX_data_active_object(C);
+ paintvert_hide(C, ob, unselected);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vert_select_hide(wmOperatorType *ot)
+{
+ ot->name = "Vertex Select Hide";
+ ot->description = "Hide selected vertices";
+ ot->idname = "PAINT_OT_vert_select_hide";
+
+ ot->exec = vert_select_hide_exec;
+ ot->poll = vert_paint_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(
+ ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected vertices");
+}
+
+static int face_vert_reveal_exec(bContext *C, wmOperator *op)
{
const bool select = RNA_boolean_get(op->ptr, "select");
Object *ob = CTX_data_active_object(C);
- paintface_reveal(C, ob, select);
+
+ if (BKE_paint_select_vert_test(ob)) {
+ paintvert_reveal(C, ob, select);
+ }
+ else {
+ paintface_reveal(C, ob, select);
+ }
+
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
-void PAINT_OT_face_select_reveal(wmOperatorType *ot)
+static bool face_vert_reveal_poll(bContext *C)
{
- ot->name = "Face Select Reveal";
- ot->description = "Reveal hidden faces";
- ot->idname = "PAINT_OT_face_select_reveal";
+ Object *ob = CTX_data_active_object(C);
- ot->exec = face_select_reveal_exec;
- ot->poll = facemask_paint_poll;
+ /* Allow using this operator when no selection is enabled but hiding is applied. */
+ return BKE_paint_select_elem_test(ob) || BKE_paint_always_hide_test(ob);
+}
+
+void PAINT_OT_face_vert_reveal(wmOperatorType *ot)
+{
+ ot->name = "Reveal Faces/Vertices";
+ ot->description = "Reveal hidden faces and vertices";
+ ot->idname = "PAINT_OT_face_vert_reveal";
+
+ ot->exec = face_vert_reveal_exec;
+ ot->poll = face_vert_reveal_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna,
+ "select",
+ true,
+ "Select",
+ "Specifies whether the newly revealed geometry should be selected");
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 67b60acc667..c38a79cb6bb 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -36,6 +36,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -227,22 +228,6 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev,
return dv_prev;
}
-/* check if we can do partial updates and have them draw realtime
- * (without evaluating modifiers) */
-static bool vertex_paint_use_fast_update_check(Object *ob)
-{
- const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
-
- if (me_eval != nullptr) {
- const Mesh *me = BKE_mesh_from_object(ob);
- if (me && me->mloopcol) {
- return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_PROP_BYTE_COLOR));
- }
- }
-
- return false;
-}
-
static void paint_last_stroke_update(Scene *scene, const float location[3])
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -788,6 +773,8 @@ struct WeightPaintGroupData {
* paint stroke update - campbell */
struct WeightPaintInfo {
+ MutableSpan<MDeformVert> dvert;
+
int defbase_tot;
/* both must add up to 'defbase_tot' */
@@ -830,7 +817,7 @@ static void do_weight_paint_vertex_single(
float paintweight)
{
Mesh *me = (Mesh *)ob->data;
- MDeformVert *dv = &me->dvert[index];
+ MDeformVert *dv = &wpi->dvert[index];
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
MDeformWeight *dw;
@@ -890,7 +877,7 @@ static void do_weight_paint_vertex_single(
/* get the mirror def vars */
if (index_mirr != -1) {
- dv_mirr = &me->dvert[index_mirr];
+ dv_mirr = &wpi->dvert[index_mirr];
if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
dw_mirr = BKE_defvert_find_index(dv_mirr, vgroup_mirr);
@@ -930,9 +917,9 @@ static void do_weight_paint_vertex_single(
if (!brush_use_accumulate(wp)) {
MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
- MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
+ MDeformVert *dv_prev = defweight_prev_init(dvert_prev, wpi->dvert.data(), index);
if (index_mirr != -1) {
- defweight_prev_init(dvert_prev, me->dvert, index_mirr);
+ defweight_prev_init(dvert_prev, wpi->dvert.data(), index_mirr);
}
weight_prev = BKE_defvert_find_weight(dv_prev, wpi->active.index);
@@ -1043,7 +1030,7 @@ static void do_weight_paint_vertex_multi(
float paintweight)
{
Mesh *me = (Mesh *)ob->data;
- MDeformVert *dv = &me->dvert[index];
+ MDeformVert *dv = &wpi->dvert[index];
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
/* mirror vars */
@@ -1059,7 +1046,7 @@ static void do_weight_paint_vertex_multi(
index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, topology);
if (!ELEM(index_mirr, -1, index)) {
- dv_mirr = &me->dvert[index_mirr];
+ dv_mirr = &wpi->dvert[index_mirr];
}
else {
index_mirr = -1;
@@ -1086,9 +1073,9 @@ static void do_weight_paint_vertex_multi(
if (!brush_use_accumulate(wp)) {
MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
- MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
+ MDeformVert *dv_prev = defweight_prev_init(dvert_prev, wpi->dvert.data(), index);
if (index_mirr != -1) {
- defweight_prev_init(dvert_prev, me->dvert, index_mirr);
+ defweight_prev_init(dvert_prev, wpi->dvert.data(), index_mirr);
}
oldw = BKE_defvert_multipaint_collective_weight(
@@ -1191,12 +1178,12 @@ static void vertex_paint_init_session(Depsgraph *depsgraph,
BLI_assert(ob->sculpt == nullptr);
ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = object_mode;
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
}
static void vwpaint_init_stroke(Depsgraph *depsgraph, Object *ob)
{
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
SculptSession *ss = ob->sculpt;
/* Ensure ss->cache is allocated. It will mostly be initialized in
@@ -1250,6 +1237,8 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
}
Mesh *me = (Mesh *)ob->data;
+ const Span<MPoly> polys = me->polys();
+ const Span<MLoop> loops = me->loops();
if (gmap->vert_to_loop == nullptr) {
gmap->vert_map_mem = nullptr;
@@ -1258,15 +1247,15 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
gmap->vert_to_poly = nullptr;
BKE_mesh_vert_loop_map_create(&gmap->vert_to_loop,
&gmap->vert_map_mem,
- me->mpoly,
- me->mloop,
+ polys.data(),
+ loops.data(),
me->totvert,
me->totpoly,
me->totloop);
BKE_mesh_vert_poly_map_create(&gmap->vert_to_poly,
&gmap->poly_map_mem,
- me->mpoly,
- me->mloop,
+ polys.data(),
+ loops.data(),
me->totvert,
me->totpoly,
me->totloop);
@@ -1804,7 +1793,8 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* set up auto-normalize, and generate map for detecting which
* vgroups affect deform bones */
wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
- if (ts->auto_normalize || ts->multipaint || wpd->lock_flags || ts->wpaint_lock_relative) {
+ if (ts->auto_normalize || ts->multipaint || wpd->lock_flags != nullptr ||
+ ts->wpaint_lock_relative) {
wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
}
@@ -1914,7 +1904,7 @@ static void do_wpaint_precompute_weight_cb_ex(void *__restrict userdata,
const TaskParallelTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = (SculptThreadedTaskData *)userdata;
- const MDeformVert *dv = &data->me->dvert[n];
+ const MDeformVert *dv = &data->wpi->dvert[n];
data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
}
@@ -1975,10 +1965,9 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const char v_flag = data->me->mvert[v_index].flag;
+ const char v_flag = ss->mvert[v_index].flag;
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
/* Get the average poly weight */
@@ -1986,12 +1975,12 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
float weight_final = 0.0f;
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &data->me->mpoly[p_index];
+ const MPoly *mp = &ss->mpoly[p_index];
total_hit_loops += mp->totloop;
for (int k = 0; k < mp->totloop; k++) {
const int l_index = mp->loopstart + k;
- const MLoop *ml = &data->me->mloop[l_index];
+ const MLoop *ml = &ss->mloop[l_index];
weight_final += data->wpd->precomputed_weight[ml->v];
}
}
@@ -2071,10 +2060,9 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv_curr = &data->me->mvert[v_index];
+ const MVert *mv_curr = &ss->mvert[v_index];
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
@@ -2096,12 +2084,12 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
float weight_final = 0.0;
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &data->me->mpoly[p_index];
- const MLoop *ml_other = &data->me->mloop[mp->loopstart];
+ const MPoly *mp = &ss->mpoly[p_index];
+ const MLoop *ml_other = &ss->mloop[mp->loopstart];
for (int k = 0; k < mp->totloop; k++, ml_other++) {
const uint v_other_index = ml_other->v;
if (v_other_index != v_index) {
- const MVert *mv_other = &data->me->mvert[v_other_index];
+ const MVert *mv_other = &ss->mvert[v_other_index];
/* Get the direction from the selected vert to the neighbor. */
float other_dir[3];
@@ -2178,11 +2166,10 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* NOTE: grids are 1:1 with corners (aka loops).
* For multires, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const char v_flag = data->me->mvert[v_index].flag;
+ const char v_flag = ss->mvert[v_index].flag;
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
float brush_strength = cache->bstrength;
@@ -2246,13 +2233,12 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
1.0f;
if (angle_cos > 0.0 &&
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
- const char v_flag = data->me->mvert[v_index].flag;
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
+ const char v_flag = ss->mvert[v_index].flag;
/* If the vertex is selected. */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
- const MDeformVert *dv = &data->me->dvert[v_index];
+ const MDeformVert *dv = &data->wpi->dvert[v_index];
accum->len += 1;
accum->value += wpaint_get_active_weight(dv, data->wpi);
}
@@ -2524,7 +2510,11 @@ static void wpaint_stroke_update_step(bContext *C,
/* load projection matrix */
mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
+ Mesh *mesh = static_cast<Mesh *>(ob->data);
+
/* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
+ wpi.dvert = mesh->deform_verts_for_write();
+
wpi.defbase_tot = wpd->defbase_tot;
wpi.defbase_sel = wpd->defbase_sel;
wpi.defbase_tot_sel = wpd->defbase_tot_sel;
@@ -2546,7 +2536,7 @@ static void wpaint_stroke_update_step(bContext *C,
/* *** done setting up WeightPaintInfo *** */
if (wpd->precomputed_weight) {
- precompute_weight_values(C, ob, brush, wpd, &wpi, (Mesh *)ob->data);
+ precompute_weight_values(C, ob, brush, wpd, &wpi, mesh);
}
wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
@@ -2559,9 +2549,9 @@ static void wpaint_stroke_update_step(bContext *C,
mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
paint_last_stroke_update(scene, loc_world);
- BKE_mesh_batch_cache_dirty_tag((Mesh *)ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update((ID *)ob->data, 0);
+ DEG_id_tag_update(&mesh->id, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
swap_m4m4(wpd->vc.rv3d->persmat, mat);
@@ -2593,31 +2583,14 @@ static void wpaint_stroke_done(const bContext *C, PaintStroke *stroke)
WPaintData *wpd = (WPaintData *)paint_stroke_mode_data(stroke);
if (wpd) {
- if (wpd->defbase_sel) {
- MEM_freeN((void *)wpd->defbase_sel);
- }
- if (wpd->vgroup_validmap) {
- MEM_freeN((void *)wpd->vgroup_validmap);
- }
- if (wpd->vgroup_locked) {
- MEM_freeN((void *)wpd->vgroup_locked);
- }
- if (wpd->vgroup_unlocked) {
- MEM_freeN((void *)wpd->vgroup_unlocked);
- }
- if (wpd->lock_flags) {
- MEM_freeN((void *)wpd->lock_flags);
- }
- if (wpd->active.lock) {
- MEM_freeN((void *)wpd->active.lock);
- }
- if (wpd->mirror.lock) {
- MEM_freeN((void *)wpd->mirror.lock);
- }
- if (wpd->precomputed_weight) {
- MEM_freeN(wpd->precomputed_weight);
- }
-
+ MEM_SAFE_FREE(wpd->defbase_sel);
+ MEM_SAFE_FREE(wpd->vgroup_validmap);
+ MEM_SAFE_FREE(wpd->vgroup_locked);
+ MEM_SAFE_FREE(wpd->vgroup_unlocked);
+ MEM_SAFE_FREE(wpd->lock_flags);
+ MEM_SAFE_FREE(wpd->active.lock);
+ MEM_SAFE_FREE(wpd->mirror.lock);
+ MEM_SAFE_FREE(wpd->precomputed_weight);
MEM_freeN(wpd);
}
@@ -2838,16 +2811,6 @@ struct VPaintData : public VPaintDataBase {
struct VertProjHandle *vp_handle;
CoNo *vertexcosnos;
- /**
- * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this
- * array, otherwise we need to refresh the modifier stack.
- */
- bool use_fast_update;
-
- /* loops tagged as having been painted, to apply shared vertex color
- * blending only to modified loops */
- bool *mlooptag;
-
bool is_texbrush;
/* Special storage for smear brush, avoid feedback loop - update each step. */
@@ -2893,20 +2856,6 @@ static void *vpaint_init_vpaint(bContext *C,
vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
- /* are we painting onto a modified mesh?,
- * if not we can skip face map trickiness */
- if (vertex_paint_use_fast_update_check(ob)) {
- vpd->use_fast_update = true;
- }
- else {
- vpd->use_fast_update = false;
- }
-
- /* to keep tracked of modified loops for shared vertex color blending */
- if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) {
- vpd->mlooptag = (bool *)MEM_mallocN(sizeof(bool) * elem_num, "VPaintData mlooptag");
- }
-
if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
@@ -3035,10 +2984,10 @@ static void do_vpaint_brush_blur_loops(bContext *C,
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v :
vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &me->mvert[v_index];
+ const MVert *mv = &ss->mvert[v_index];
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
@@ -3061,7 +3010,7 @@ static void do_vpaint_brush_blur_loops(bContext *C,
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &me->mpoly[p_index];
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
total_hit_loops += mp->totloop;
for (int k = 0; k < mp->totloop; k++) {
@@ -3095,8 +3044,8 @@ static void do_vpaint_brush_blur_loops(bContext *C,
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
const int p_index = gmap->vert_to_poly[v_index].indices[j];
const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(me->mloop[l_index].v == v_index);
- const MPoly *mp = &me->mpoly[p_index];
+ BLI_assert(ss->mloop[l_index].v == v_index);
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
@@ -3177,10 +3126,10 @@ static void do_vpaint_brush_blur_verts(bContext *C,
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v :
vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &me->mvert[v_index];
+ const MVert *mv = &ss->mvert[v_index];
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
@@ -3203,12 +3152,12 @@ static void do_vpaint_brush_blur_verts(bContext *C,
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &me->mpoly[p_index];
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
total_hit_loops += mp->totloop;
for (int k = 0; k < mp->totloop; k++) {
const uint l_index = mp->loopstart + k;
- const uint v_index = me->mloop[l_index].v;
+ const uint v_index = ss->mloop[l_index].v;
Color *col = lcol + v_index;
@@ -3239,9 +3188,9 @@ static void do_vpaint_brush_blur_verts(bContext *C,
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
const int p_index = gmap->vert_to_poly[v_index].indices[j];
- BLI_assert(me->mloop[gmap->vert_to_loop[v_index].indices[j]].v == v_index);
+ BLI_assert(ss->mloop[gmap->vert_to_loop[v_index].indices[j]].v == v_index);
- const MPoly *mp = &me->mpoly[p_index];
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
@@ -3328,10 +3277,10 @@ static void do_vpaint_brush_smear(bContext *C,
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
/* For grid based pbvh, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v :
vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv_curr = &me->mvert[v_index];
+ const MVert *mv_curr = &ss->mvert[v_index];
/* if the vertex is selected for painting. */
if (!use_vert_sel || mv_curr->flag & SELECT) {
@@ -3360,15 +3309,15 @@ static void do_vpaint_brush_smear(bContext *C,
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
const int p_index = gmap->vert_to_poly[v_index].indices[j];
const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(me->mloop[l_index].v == v_index);
+ BLI_assert(ss->mloop[l_index].v == v_index);
UNUSED_VARS_NDEBUG(l_index);
- const MPoly *mp = &me->mpoly[p_index];
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- const MLoop *ml_other = &me->mloop[mp->loopstart];
+ const MLoop *ml_other = &ss->mloop[mp->loopstart];
for (int k = 0; k < mp->totloop; k++, ml_other++) {
const uint v_other_index = ml_other->v;
if (v_other_index != v_index) {
- const MVert *mv_other = &me->mvert[v_other_index];
+ const MVert *mv_other = &ss->mvert[v_other_index];
/* Get the direction from the
* selected vert to the neighbor. */
@@ -3414,10 +3363,10 @@ static void do_vpaint_brush_smear(bContext *C,
else {
const int l_index = gmap->vert_to_loop[v_index].indices[j];
elem_index = l_index;
- BLI_assert(me->mloop[l_index].v == v_index);
+ BLI_assert(ss->mloop[l_index].v == v_index);
}
- const MPoly *mp = &me->mpoly[p_index];
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
/* Get the previous element color */
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
@@ -3490,11 +3439,11 @@ static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v :
vd.vert_indices[vd.i];
if (BKE_brush_curve_strength(brush, 0.0, cache->radius) > 0.0) {
/* If the vertex is selected for painting. */
- const MVert *mv = &me->mvert[v_index];
+ const MVert *mv = &ss->mvert[v_index];
if (!use_vert_sel || mv->flag & SELECT) {
accum2->len += gmap->vert_to_loop[v_index].count;
/* if a vertex is within the brush region, then add its color to the blend. */
@@ -3610,10 +3559,10 @@ static void vpaint_do_draw(bContext *C,
/* NOTE: Grids are 1:1 with corners (aka loops).
* For grid based pbvh, take the vert whose loop corresponds to the current grid.
* Otherwise, take the current vert. */
- const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ const int v_index = has_grids ? ss->mloop[vd.grid_indices[vd.g]].v :
vd.vert_indices[vd.i];
const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &me->mvert[v_index];
+ const MVert *mv = &ss->mvert[v_index];
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
@@ -3667,8 +3616,8 @@ static void vpaint_do_draw(bContext *C,
for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
const int p_index = gmap->vert_to_poly[v_index].indices[j];
const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(me->mloop[l_index].v == v_index);
- const MPoly *mp = &me->mpoly[p_index];
+ BLI_assert(ss->mloop[l_index].v == v_index);
+ const MPoly *mp = &ss->mpoly[p_index];
if (!use_face_sel || mp->flag & ME_FACE_SEL) {
Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */
@@ -3901,15 +3850,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P
ED_region_tag_redraw(vc->region);
- if (vpd->use_fast_update == false) {
- /* recalculate modifier stack to get new colors, slow,
- * avoid this if we can! */
- DEG_id_tag_update((ID *)ob->data, 0);
- }
- else {
- /* Flush changes through DEG. */
- DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
- }
+ DEG_id_tag_update((ID *)ob->data, ID_RECALC_GEOMETRY);
}
static void vpaint_stroke_update_step(bContext *C,
@@ -3950,9 +3891,6 @@ static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
ED_vpaint_proj_handle_free(vpd->vp_handle);
}
- if (vpd->mlooptag) {
- MEM_freeN(vpd->mlooptag);
- }
if (vpd->smear.color_prev) {
MEM_freeN(vpd->smear.color_prev);
}
@@ -4023,7 +3961,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
BKE_pbvh_ensure_node_loops(ob->sculpt->pbvh);
}
- SCULPT_undo_push_begin(ob, "Vertex Paint");
+ SCULPT_undo_push_begin_ex(ob, "Vertex Paint");
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
paint_stroke_free(C, op, (PaintStroke *)op->customdata);
@@ -4099,7 +4037,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
* \{ */
template<typename Color, typename Traits, eAttrDomain domain>
-static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_layer)
+static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, CustomDataLayer *layer)
{
Mesh *me;
if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
@@ -4112,30 +4050,73 @@ static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- const MPoly *mp = me->mpoly;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
+ if (me->edit_mesh) {
+ BMesh *bm = me->edit_mesh->bm;
+ BMFace *f;
+ BMIter iter;
+
+ int cd_offset = -1;
+
+ /* Find customdata offset inside of bmesh. */
+ CustomData *cdata = domain == ATTR_DOMAIN_POINT ? &bm->vdata : &bm->ldata;
+
+ for (int i = 0; i < cdata->totlayer; i++) {
+ if (STREQ(cdata->layers[i].name, layer->name)) {
+ cd_offset = layer->offset;
+ }
}
- int j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
+ BLI_assert(cd_offset != -1);
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- if constexpr (domain == ATTR_DOMAIN_CORNER) {
- color_layer[mp->loopstart + j] = paintcol;
- }
- else {
- color_layer[vidx] = paintcol;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ Color *color;
+ BMLoop *l = f->l_first;
+
+ do {
+ if (!(use_vert_sel && !(BM_elem_flag_test(l->v, BM_ELEM_SELECT)))) {
+ if constexpr (domain == ATTR_DOMAIN_CORNER) {
+ color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset));
+ }
+ else {
+ color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset));
+ }
+
+ *color = paintcol;
}
- }
- j++;
- } while (j < mp->totloop);
+ } while ((l = l->next) != f->l_first);
+ }
}
+ else {
+ Color *color_layer = static_cast<Color *>(layer->data);
+ const Span<MVert> verts = me->verts();
+ const Span<MPoly> polys = me->polys();
+ const Span<MLoop> loops = me->loops();
+
+ for (const int i : polys.index_range()) {
+ const MPoly &poly = polys[i];
+ if (use_face_sel && !(poly.flag & ME_FACE_SEL)) {
+ continue;
+ }
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
+ int j = 0;
+ do {
+ uint vidx = loops[poly.loopstart + j].v;
+
+ if (!(use_vert_sel && !(verts[vidx].flag & SELECT))) {
+ if constexpr (domain == ATTR_DOMAIN_CORNER) {
+ color_layer[poly.loopstart + j] = paintcol;
+ }
+ else {
+ color_layer[vidx] = paintcol;
+ }
+ }
+ j++;
+ } while (j < poly.totloop);
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+ }
DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
@@ -4160,7 +4141,7 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob,
if (!layer) {
return false;
}
- /* Store original #Mesh.editflag.*/
+ /* Store original #Mesh.editflag. */
const decltype(me->editflag) editflag = me->editflag;
if (!only_selected) {
me->editflag &= ~ME_EDIT_PAINT_FACE_SEL;
@@ -4170,22 +4151,18 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob,
bool ok = false;
if (domain == ATTR_DOMAIN_POINT) {
if (layer->type == CD_PROP_COLOR) {
- ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
- ob, fill_color, static_cast<ColorPaint4f *>(layer->data));
+ ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
- ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
- ob, fill_color, static_cast<ColorPaint4b *>(layer->data));
+ ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
}
}
else {
if (layer->type == CD_PROP_COLOR) {
- ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
- ob, fill_color, static_cast<ColorPaint4f *>(layer->data));
+ ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
- ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
- ob, fill_color, static_cast<ColorPaint4b *>(layer->data));
+ ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
}
}
/* Restore #Mesh.editflag. */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
deleted file mode 100644
index a2e1adff50a..00000000000
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_color.h"
-
-#include "BKE_context.h"
-#include "BKE_deform.h"
-#include "BKE_mesh.h"
-
-#include "DEG_depsgraph.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-
-#include "paint_intern.h" /* own include */
-
-/* -------------------------------------------------------------------- */
-/** \name Internal Utility Functions
- * \{ */
-
-static bool vertex_weight_paint_mode_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- Mesh *me = BKE_mesh_from_object(ob);
- return (ob && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) &&
- (me && me->totpoly && me->dvert);
-}
-
-static void tag_object_after_update(Object *object)
-{
- BLI_assert(object->type == OB_MESH);
- Mesh *mesh = object->data;
- DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
- /* NOTE: Original mesh is used for display, so tag it directly here. */
- BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Vertex Color from Weight Operator
- * \{ */
-
-static bool vertex_paint_from_weight(Object *ob)
-{
- Mesh *me;
- const MPoly *mp;
- int vgroup_active;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) {
- return false;
- }
-
- /* 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 = me->vertex_group_active_index - 1;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
- uint j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- const float weight = BKE_defvert_find_weight(&me->dvert[vidx], vgroup_active);
- const uchar grayscale = weight * 255;
- lcol->r = grayscale;
- lcol->b = grayscale;
- lcol->g = grayscale;
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- tag_object_after_update(ob);
-
- return true;
-}
-
-static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
- if (vertex_paint_from_weight(obact)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color from Weight";
- ot->idname = "PAINT_OT_vertex_color_from_weight";
- ot->description = "Convert active weight into gray scale vertex colors";
-
- /* api callback */
- ot->exec = vertex_paint_from_weight_exec;
- ot->poll = vertex_weight_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* TODO: invert, alpha */
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Smooth Vertex Colors Operator
- * \{ */
-
-static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
-{
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const MPoly *mp;
- int(*scol)[4];
- bool has_shared = false;
-
- if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) {
- return;
- }
-
- scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
-
- int i;
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
- scol[ml->v][0] += lcol->r;
- scol[ml->v][1] += lcol->g;
- scol[ml->v][2] += lcol->b;
- scol[ml->v][3] += 1;
- has_shared = 1;
- }
- }
- }
-
- if (has_shared) {
- for (i = 0; i < me->totvert; i++) {
- if (scol[i][3] != 0) {
- scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
- scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
- scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
- }
- }
-
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
- if (mlooptag[mp->loopstart + j]) {
- lcol->r = scol[ml->v][0];
- lcol->g = scol[ml->v][1];
- lcol->b = scol[ml->v][2];
- }
- }
- }
- }
- }
-
- MEM_freeN(scol);
-}
-
-static bool vertex_color_smooth(Object *ob)
-{
- Mesh *me;
- const MPoly *mp;
- int i, j;
-
- bool *mlooptag;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
- return false;
- }
-
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
-
- /* simply tag loops of selected faces */
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- const MLoop *ml = me->mloop + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- j = 0;
- do {
- if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
- mlooptag[mp->loopstart + j] = true;
- }
- ml++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- vertex_color_smooth_looptag(me, mlooptag);
-
- MEM_freeN(mlooptag);
-
- tag_object_after_update(ob);
-
- return true;
-}
-
-static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
- if (vertex_color_smooth(obact)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Smooth Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_smooth";
- ot->description = "Smooth colors across vertices";
-
- /* api callbacks */
- ot->exec = vertex_color_smooth_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Vertex Color Transformation Operators
- * \{ */
-
-struct VPaintTx_BrightContrastData {
- /* pre-calculated */
- float gain;
- float offset;
-};
-
-static void vpaint_tx_brightness_contrast(const float col[3],
- const void *user_data,
- float r_col[3])
-{
- const struct VPaintTx_BrightContrastData *data = user_data;
-
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * col[i] + data->offset;
- }
-}
-
-static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
-
- float gain, offset;
- {
- float brightness = RNA_float_get(op->ptr, "brightness");
- float contrast = RNA_float_get(op->ptr, "contrast");
- brightness /= 100.0f;
- float delta = contrast / 200.0f;
- /*
- * The algorithm is by Werner D. Streidt
- * (http://visca.com/ffactory/archives/5-99/msg00021.html)
- * Extracted of OpenCV demhist.c
- */
- if (contrast > 0) {
- gain = 1.0f - delta * 2.0f;
- gain = 1.0f / max_ff(gain, FLT_EPSILON);
- offset = gain * (brightness - delta);
- }
- else {
- delta *= -1;
- gain = max_ff(1.0f - delta * 2.0f, 0.0f);
- offset = gain * brightness + delta;
- }
- }
-
- const struct VPaintTx_BrightContrastData user_data = {
- .gain = gain,
- .offset = offset,
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Vertex Paint Brightness/Contrast";
- ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
- ot->description = "Adjust vertex color brightness/contrast";
-
- /* api callbacks */
- ot->exec = vertex_color_brightness_contrast_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- const float min = -100, max = +100;
- prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
- prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
- RNA_def_property_ui_range(prop, min, max, 1, 1);
-}
-
-struct VPaintTx_HueSatData {
- float hue;
- float sat;
- float val;
-};
-
-static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
-{
- const struct VPaintTx_HueSatData *data = user_data;
- float hsv[3];
- rgb_to_hsv_v(col, hsv);
-
- hsv[0] += (data->hue - 0.5f);
- if (hsv[0] > 1.0f) {
- hsv[0] -= 1.0f;
- }
- else if (hsv[0] < 0.0f) {
- hsv[0] += 1.0f;
- }
- hsv[1] *= data->sat;
- hsv[2] *= data->val;
-
- hsv_to_rgb_v(hsv, r_col);
-}
-
-static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
-
- const struct VPaintTx_HueSatData user_data = {
- .hue = RNA_float_get(op->ptr, "h"),
- .sat = RNA_float_get(op->ptr, "s"),
- .val = RNA_float_get(op->ptr, "v"),
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Paint Hue Saturation Value";
- ot->idname = "PAINT_OT_vertex_color_hsv";
- ot->description = "Adjust vertex color HSV values";
-
- /* api callbacks */
- ot->exec = vertex_color_hsv_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
- RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
- RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
-}
-
-static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
-{
- for (int i = 0; i < 3; i++) {
- r_col[i] = 1.0f - col[i];
- }
-}
-
-static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Paint Invert";
- ot->idname = "PAINT_OT_vertex_color_invert";
- ot->description = "Invert RGB values";
-
- /* api callbacks */
- ot->exec = vertex_color_invert_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-struct VPaintTx_LevelsData {
- float gain;
- float offset;
-};
-
-static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
-{
- const struct VPaintTx_LevelsData *data = user_data;
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * (col[i] + data->offset);
- }
-}
-
-static int vertex_color_levels_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
-
- const struct VPaintTx_LevelsData user_data = {
- .gain = RNA_float_get(op->ptr, "gain"),
- .offset = RNA_float_get(op->ptr, "offset"),
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Paint Levels";
- ot->idname = "PAINT_OT_vertex_color_levels";
- ot->description = "Adjust levels of vertex colors";
-
- /* api callbacks */
- ot->exec = vertex_color_levels_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- RNA_def_float(
- ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
- RNA_def_float(
- ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
new file mode 100644
index 00000000000..10ad4c2192f
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
@@ -0,0 +1,514 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_array.hh"
+#include "BLI_index_mask_ops.hh"
+#include "BLI_math_base.h"
+#include "BLI_math_color.h"
+#include "BLI_vector.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+
+#include "paint_intern.h" /* own include */
+
+using blender::Array;
+using blender::ColorGeometry4f;
+using blender::GMutableSpan;
+using blender::IndexMask;
+using blender::Vector;
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utility Functions
+ * \{ */
+
+static bool vertex_weight_paint_mode_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = BKE_mesh_from_object(ob);
+ return (ob && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) &&
+ (me && me->totpoly && !me->deform_verts().is_empty());
+}
+
+static void tag_object_after_update(Object *object)
+{
+ BLI_assert(object->type == OB_MESH);
+ Mesh *mesh = static_cast<Mesh *>(object->data);
+ DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
+ /* NOTE: Original mesh is used for display, so tag it directly here. */
+ BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Color from Weight Operator
+ * \{ */
+
+static bool vertex_paint_from_weight(Object *ob)
+{
+ using namespace blender;
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(ob)) == nullptr ||
+ (ED_mesh_color_ensure(me, nullptr)) == false)) {
+ return false;
+ }
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ const int active_vertex_group_index = me->vertex_group_active_index - 1;
+ const bDeformGroup *deform_group = static_cast<const bDeformGroup *>(
+ BLI_findlink(&me->vertex_group_names, active_vertex_group_index));
+ if (deform_group == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ bke::MutableAttributeAccessor attributes = me->attributes_for_write();
+
+ bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
+ if (!color_attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ /* Retrieve the vertex group with the domain and type of the existing color
+ * attribute, in order to let the attribute API handle both conversions. */
+ const GVArray vertex_group = attributes.lookup(
+ deform_group->name,
+ ATTR_DOMAIN_POINT,
+ bke::cpp_type_to_custom_data_type(color_attribute.varray.type()));
+ if (!vertex_group) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ GVArraySpan interpolated{
+ attributes.adapt_domain(vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)};
+
+ color_attribute.varray.set_all(interpolated.data());
+ color_attribute.finish();
+ tag_object_after_update(ob);
+
+ return true;
+}
+
+static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_paint_from_weight(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color from Weight";
+ ot->idname = "PAINT_OT_vertex_color_from_weight";
+ ot->description = "Convert active weight into gray scale vertex colors";
+
+ /* api callback */
+ ot->exec = vertex_paint_from_weight_exec;
+ ot->poll = vertex_weight_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* TODO: invert, alpha */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertex Colors Operator
+ * \{ */
+
+static IndexMask get_selected_indices(const Mesh &mesh,
+ const eAttrDomain domain,
+ Vector<int64_t> &indices)
+{
+ using namespace blender;
+ const Span<MVert> verts = mesh.verts();
+ const Span<MPoly> polys = mesh.polys();
+
+ bke::AttributeAccessor attributes = mesh.attributes();
+
+ if (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) {
+ const VArray<bool> selection = attributes.adapt_domain(
+ VArray<bool>::ForFunc(polys.size(),
+ [&](const int i) { return polys[i].flag & ME_FACE_SEL; }),
+ ATTR_DOMAIN_FACE,
+ domain);
+
+ return index_mask_ops::find_indices_from_virtual_array(
+ IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
+ }
+ if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) {
+ const VArray<bool> selection = attributes.adapt_domain(
+ VArray<bool>::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }),
+ ATTR_DOMAIN_POINT,
+ domain);
+
+ return index_mask_ops::find_indices_from_virtual_array(
+ IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
+ }
+ return IndexMask(attributes.domain_size(domain));
+}
+
+static void face_corner_color_equalize_verts(Mesh &mesh, const IndexMask selection)
+{
+ using namespace blender;
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ bke::AttributeAccessor attributes = mesh.attributes();
+
+ if (attributes.lookup_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
+ return;
+ }
+
+ GVArray color_attribute_point = attributes.lookup(active_color_layer->name, ATTR_DOMAIN_POINT);
+
+ GVArray color_attribute_corner = attributes.adapt_domain(
+ color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER);
+
+ color_attribute_corner.materialize(selection, active_color_layer->data);
+}
+
+static bool vertex_color_smooth(Object *ob)
+{
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return false;
+ }
+
+ Vector<int64_t> indices;
+ const IndexMask selection = get_selected_indices(*me, ATTR_DOMAIN_CORNER, indices);
+
+ face_corner_color_equalize_verts(*me, selection);
+
+ tag_object_after_update(ob);
+
+ return true;
+}
+
+static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_color_smooth(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Smooth Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_smooth";
+ ot->description = "Smooth colors across vertices";
+
+ /* api callbacks */
+ ot->exec = vertex_color_smooth_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Color Transformation Operators
+ * \{ */
+
+template<typename TransformFn>
+static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
+{
+ using namespace blender;
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
+
+ bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
+ if (!color_attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ Vector<int64_t> indices;
+ const IndexMask selection = get_selected_indices(mesh, color_attribute.domain, indices);
+
+ attribute_math::convert_to_static_type(color_attribute.varray.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for ([[maybe_unused]] const int i : selection.slice(range)) {
+ if constexpr (std::is_same_v<T, ColorGeometry4f>) {
+ ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4f>(i);
+ transform_fn(color);
+ color_attribute.varray.set_by_copy(i, &color);
+ }
+ else if constexpr (std::is_same_v<T, ColorGeometry4b>) {
+ ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4b>(i).decode();
+ transform_fn(color);
+ ColorGeometry4b color_encoded = color.encode();
+ color_attribute.varray.set_by_copy(i, &color_encoded);
+ }
+ }
+ });
+ });
+
+ color_attribute.finish();
+
+ DEG_id_tag_update(&mesh.id, 0);
+
+ return true;
+}
+
+static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f - delta * 2.0f;
+ gain = 1.0f / max_ff(gain, FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ gain = max_ff(1.0f - delta * 2.0f, 0.0f);
+ offset = gain * brightness + delta;
+ }
+ }
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = gain * color[i] + offset;
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Vertex Paint Brightness/Contrast";
+ ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
+
+ /* api callbacks */
+ ot->exec = vertex_color_brightness_contrast_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
+}
+
+static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const float hue = RNA_float_get(op->ptr, "h");
+ const float sat = RNA_float_get(op->ptr, "s");
+ const float val = RNA_float_get(op->ptr, "v");
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ float hsv[3];
+ rgb_to_hsv_v(color, hsv);
+
+ hsv[0] += (hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= sat;
+ hsv[2] *= val;
+
+ hsv_to_rgb_v(hsv, color);
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "PAINT_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_hsv_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+}
+
+static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = 1.0f - color[i];
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "PAINT_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_invert_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int vertex_color_levels_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const float gain = RNA_float_get(op->ptr, "gain");
+ const float offset = RNA_float_get(op->ptr, "offset");
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = gain * (color[i] + offset);
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "PAINT_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = vertex_color_levels_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(
+ ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(
+ ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
deleted file mode 100644
index cd099f71ccd..00000000000
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edsculpt
- *
- * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
- */
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_color.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-
-#include "BKE_context.h"
-#include "BKE_mesh.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_mesh.h"
-
-#include "paint_intern.h" /* own include */
-
-#define EPS_SATURATION 0.0005f
-
-bool ED_vpaint_color_transform(struct Object *ob,
- VPaintTransform_Callback vpaint_tx_fn,
- const void *user_data)
-{
- Mesh *me;
- const MPoly *mp;
- int i, j;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
- return false;
- }
-
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- float col_mix[3];
- rgb_uchar_to_float(col_mix, &lcol->r);
-
- vpaint_tx_fn(col_mix, user_data, col_mix);
-
- rgb_float_to_uchar(&lcol->r, col_mix);
- }
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- DEG_id_tag_update(&me->id, 0);
-
- return true;
-}
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 d98660d8939..0a0d7cff214 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -168,8 +168,9 @@ 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);
+ const MDeformVert *dvert = BKE_mesh_deform_verts(me);
- if (me && me->dvert && vc.v3d && vc.rv3d && (me->vertex_group_active_index != 0)) {
+ if (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;
@@ -200,7 +201,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
ToolSettings *ts = vc.scene->toolsettings;
Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
const int vgroup_active = me->vertex_group_active_index - 1;
- float vgroup_weight = BKE_defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
+ float vgroup_weight = BKE_defvert_find_weight(&dvert[v_idx_best], vgroup_active);
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;
@@ -232,7 +233,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
bool is_normalized = ts->auto_normalize || use_lock_relative;
vgroup_weight = BKE_defvert_multipaint_collective_weight(
- &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, is_normalized);
+ &dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, is_normalized);
}
MEM_freeN(defbase_sel);
@@ -243,7 +244,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
defbase_tot, defbase_locked, defbase_unlocked, defbase_locked, defbase_unlocked);
vgroup_weight = BKE_defvert_lock_relative_weight(
- vgroup_weight, &me->dvert[v_idx_best], defbase_tot, defbase_locked, defbase_unlocked);
+ vgroup_weight, &dvert[v_idx_best], defbase_tot, defbase_locked, defbase_unlocked);
}
MEM_SAFE_FREE(defbase_locked);
@@ -316,8 +317,11 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
+ const MPoly *polys = BKE_mesh_polys(me);
+ const MLoop *loops = BKE_mesh_loops(me);
+ const MDeformVert *dverts = BKE_mesh_deform_verts(me);
- if (me && me->dvert && vc.v3d && vc.rv3d && me->vertex_group_names.first) {
+ if (me && dverts && 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");
@@ -334,17 +338,17 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
if (use_vert_sel) {
if (ED_mesh_pick_vert(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
- MDeformVert *dvert = &me->dvert[index];
+ const MDeformVert *dvert = &dverts[index];
found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
}
}
else {
if (ED_mesh_pick_face(C, vc.obact, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
- const MPoly *mp = &me->mpoly[index];
+ const MPoly *mp = &polys[index];
uint fidx = mp->totloop - 1;
do {
- MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
+ const MDeformVert *dvert = &dverts[loops[mp->loopstart + fidx].v];
found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
} while (fidx--);
}
@@ -441,7 +445,12 @@ static bool weight_paint_set(Object *ob, float paintweight)
/* mutually exclusive, could be made into a */
const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
- if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
+ const MVert *verts = BKE_mesh_verts(me);
+ const MPoly *polys = BKE_mesh_polys(me);
+ const MLoop *loops = BKE_mesh_loops(me);
+ MDeformVert *dvert = BKE_mesh_deform_verts_for_write(me);
+
+ if (me->totpoly == 0 || dvert == NULL) {
return false;
}
@@ -453,9 +462,9 @@ static bool weight_paint_set(Object *ob, float paintweight)
}
struct WPaintPrev wpp;
- wpaint_prev_create(&wpp, me->dvert, me->totvert);
+ wpaint_prev_create(&wpp, dvert, me->totvert);
- for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
+ for (index = 0, mp = polys; index < me->totpoly; index++, mp++) {
uint fidx = mp->totloop - 1;
if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
@@ -463,14 +472,14 @@ static bool weight_paint_set(Object *ob, float paintweight)
}
do {
- uint vidx = me->mloop[mp->loopstart + fidx].v;
+ uint vidx = loops[mp->loopstart + fidx].v;
- if (!me->dvert[vidx].flag) {
- if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
+ if (!dvert[vidx].flag) {
+ if ((paint_selmode == SCE_SELECT_VERTEX) && !(verts[vidx].flag & SELECT)) {
continue;
}
- dw = BKE_defvert_ensure_index(&me->dvert[vidx], vgroup_active);
+ dw = BKE_defvert_ensure_index(&dvert[vidx], vgroup_active);
if (dw) {
dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + vidx, vgroup_active);
dw_prev->weight = dw->weight; /* set the undo weight */
@@ -482,11 +491,11 @@ static bool weight_paint_set(Object *ob, float paintweight)
if (j >= 0) {
/* copy, not paint again */
if (vgroup_mirror != -1) {
- dw = BKE_defvert_ensure_index(me->dvert + j, vgroup_mirror);
+ dw = BKE_defvert_ensure_index(dvert + j, vgroup_mirror);
dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + j, vgroup_mirror);
}
else {
- dw = BKE_defvert_ensure_index(me->dvert + j, vgroup_active);
+ dw = BKE_defvert_ensure_index(dvert + j, vgroup_active);
dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + j, vgroup_active);
}
dw_prev->weight = dw->weight; /* set the undo weight */
@@ -494,14 +503,14 @@ static bool weight_paint_set(Object *ob, float paintweight)
}
}
}
- me->dvert[vidx].flag = 1;
+ dvert[vidx].flag = 1;
}
} while (fidx--);
}
{
- MDeformVert *dv = me->dvert;
+ MDeformVert *dv = dvert;
for (index = me->totvert; index != 0; index--, dv++) {
dv->flag = 0;
}
@@ -574,6 +583,7 @@ typedef struct WPGradient_userData {
struct ARegion *region;
Scene *scene;
Mesh *me;
+ MDeformVert *dvert;
Brush *brush;
const float *sco_start; /* [2] */
const float *sco_end; /* [2] */
@@ -593,7 +603,6 @@ typedef struct WPGradient_userData {
static void gradientVert_update(WPGradient_userData *grad_data, int index)
{
- Mesh *me = grad_data->me;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
/* Optionally restrict to assigned vertices only. */
@@ -617,7 +626,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index)
alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
if (alpha != 0.0f) {
- MDeformVert *dv = &me->dvert[index];
+ MDeformVert *dv = &grad_data->dvert[index];
MDeformWeight *dw = BKE_defvert_ensure_index(dv, grad_data->def_nr);
// dw->weight = alpha; // testing
int tool = grad_data->brush->blend;
@@ -631,7 +640,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index)
vs->flag |= VGRAD_STORE_IS_MODIFIED;
}
else {
- MDeformVert *dv = &me->dvert[index];
+ MDeformVert *dv = &grad_data->dvert[index];
if (vs->flag & VGRAD_STORE_DW_EXIST) {
/* normally we NULL check, but in this case we know it exists */
MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
@@ -669,10 +678,9 @@ static void gradientVertInit__mapFunc(void *userData,
const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
- Mesh *me = grad_data->me;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
- if (grad_data->use_select && !(me->mvert[index].flag & SELECT)) {
+ if (grad_data->use_select && !(grad_data->dvert[index].flag & SELECT)) {
copy_v2_fl(vs->sco, FLT_MAX);
return;
}
@@ -693,7 +701,7 @@ static void gradientVertInit__mapFunc(void *userData,
return;
}
- MDeformVert *dv = &me->dvert[index];
+ MDeformVert *dv = &grad_data->dvert[index];
const MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
if (dw) {
vs->weight_orig = dw->weight;
@@ -727,8 +735,9 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEven
if (vert_cache != NULL) {
Mesh *me = ob->data;
if (vert_cache->wpp.wpaint_prev) {
- BKE_defvert_array_free_elems(me->dvert, me->totvert);
- BKE_defvert_array_copy(me->dvert, vert_cache->wpp.wpaint_prev, me->totvert);
+ MDeformVert *dvert = BKE_mesh_deform_verts_for_write(me);
+ BKE_defvert_array_free_elems(dvert, me->totvert);
+ BKE_defvert_array_copy(dvert, vert_cache->wpp.wpaint_prev, me->totvert);
wpaint_prev_destroy(&vert_cache->wpp);
}
MEM_freeN(vert_cache);
@@ -753,6 +762,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
+ MDeformVert *dverts = BKE_mesh_deform_verts_for_write(me);
int x_start = RNA_int_get(op->ptr, "xstart");
int y_start = RNA_int_get(op->ptr, "ystart");
int x_end = RNA_int_get(op->ptr, "xend");
@@ -774,7 +784,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.is_init = true;
wpaint_prev_create(
- &((WPGradient_vertStoreBase *)gesture->user_data.data)->wpp, me->dvert, me->totvert);
+ &((WPGradient_vertStoreBase *)gesture->user_data.data)->wpp, dverts, me->totvert);
/* On initialization only, convert face -> vert sel. */
if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
@@ -797,6 +807,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.region = region;
data.scene = scene;
data.me = ob->data;
+ data.dvert = dverts;
data.sco_start = sco_start;
data.sco_end = sco_end;
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
@@ -851,7 +862,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
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;
+ MDeformVert *dvert = dverts;
for (int i = 0; i < me->totvert; i++) {
if ((data.vert_cache->elem[i].flag & VGRAD_STORE_IS_MODIFIED) != 0) {
BKE_defvert_normalize_lock_single(&dvert[i], vgroup_validmap, vgroup_num, data.def_nr);
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 5a63af4149a..ac16631f115 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -59,7 +59,7 @@ bool ED_wpaint_ensure_data(bContext *C,
}
/* if nothing was added yet, we make dverts and a vertex deform group */
- if (!me->dvert) {
+ if (BKE_mesh_deform_verts(me) == NULL) {
BKE_object_defgroup_data_create(&me->id);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 9ce80e4a433..51ff064c58d 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -116,28 +116,28 @@ int SCULPT_vertex_count_get(SculptSession *ss)
case PBVH_BMESH:
return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
case PBVH_GRIDS:
- return BKE_pbvh_get_grid_num_vertices(ss->pbvh);
+ return BKE_pbvh_get_grid_num_verts(ss->pbvh);
}
return 0;
}
-const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_co_get(SculptSession *ss, PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- return mverts[index].co;
+ return mverts[vertex.i].co;
}
- return ss->mvert[index].co;
+ return ss->mvert[vertex.i].co;
}
case PBVH_BMESH:
- return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
+ return ((BMVert *)vertex.i)->co;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
}
@@ -158,31 +158,33 @@ bool SCULPT_has_colors(const SculptSession *ss)
return ss->vcol || ss->mcol;
}
-void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4])
+void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4])
{
- BKE_pbvh_vertex_color_get(ss->pbvh, index, r_color);
+ BKE_pbvh_vertex_color_get(ss->pbvh, vertex, r_color);
}
-void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4])
+void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4])
{
- BKE_pbvh_vertex_color_set(ss->pbvh, index, color);
+ BKE_pbvh_vertex_color_set(ss->pbvh, vertex, color);
}
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh);
- copy_v3_v3(no, vert_normals[index]);
+ copy_v3_v3(no, vert_normals[vertex.i]);
break;
}
- case PBVH_BMESH:
- copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
+ case PBVH_BMESH: {
+ BMVert *v = (BMVert *)vertex.i;
+ copy_v3_v3(no, v->no);
break;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index)));
break;
@@ -190,42 +192,42 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
}
}
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex)
{
if (ss->persistent_base) {
- return ss->persistent_base[index].co;
+ return ss->persistent_base[BKE_pbvh_vertex_to_index(ss->pbvh, vertex)].co;
}
- return SCULPT_vertex_co_get(ss, index);
+ return SCULPT_vertex_co_get(ss, vertex);
}
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, PBVHVertRef vertex)
{
- /* Always grab active shape key if the sculpt happens on shapekey. */
- if (ss->shapekey_active) {
- const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- return mverts[index].co;
- }
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
+ /* Always grab active shape key if the sculpt happens on shapekey. */
+ if (ss->shapekey_active) {
+ const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
+ return mverts[vertex.i].co;
+ }
- /* Sculpting on the base mesh. */
- if (ss->mvert) {
- return ss->mvert[index].co;
+ /* Sculpting on the base mesh. */
+ return ss->mvert[vertex.i].co;
}
/* Everything else, such as sculpting on multires. */
- return SCULPT_vertex_co_get(ss, index);
+ return SCULPT_vertex_co_get(ss, vertex);
}
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3])
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, float r_co[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
case PBVH_BMESH:
- copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, index));
+ copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, vertex));
break;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
@@ -236,30 +238,30 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]
}
}
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3])
{
if (ss->persistent_base) {
- copy_v3_v3(no, ss->persistent_base[index].no);
+ copy_v3_v3(no, ss->persistent_base[vertex.i].no);
return;
}
- SCULPT_vertex_normal_get(ss, index, no);
+ SCULPT_vertex_normal_get(ss, vertex, no);
}
-float SCULPT_vertex_mask_get(SculptSession *ss, int index)
+float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex)
{
BMVert *v;
float *mask;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->vmask[index];
+ return ss->vmask[vertex.i];
case PBVH_BMESH:
- v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
+ v = (BMVert *)vertex.i;
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
}
@@ -268,12 +270,13 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index)
return 0.0f;
}
-int SCULPT_active_vertex_get(SculptSession *ss)
+PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss)
{
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
- return ss->active_vertex_index;
+ return ss->active_vertex;
}
- return 0;
+
+ return BKE_pbvh_make_vref(PBVH_REF_NONE);
}
const float *SCULPT_active_vertex_co_get(SculptSession *ss)
@@ -338,32 +341,37 @@ int SCULPT_active_face_set_get(SculptSession *ss)
return SCULPT_FACE_SET_NONE;
}
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
+void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- SET_FLAG_FROM_TEST(ss->mvert[index].flag, !visible, ME_HIDE);
- BKE_pbvh_vert_mark_update(ss->pbvh, index);
+ case PBVH_FACES: {
+ bool *hide_vert = BKE_pbvh_get_vert_hide_for_write(ss->pbvh);
+ hide_vert[vertex.i] = visible;
break;
- case PBVH_BMESH:
- BM_elem_flag_set(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN, !visible);
+ }
+ case PBVH_BMESH: {
+ BMVert *v = (BMVert *)vertex.i;
+ BM_elem_flag_set(v, BM_ELEM_HIDDEN, !visible);
break;
+ }
case PBVH_GRIDS:
break;
}
}
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return !(ss->mvert[index].flag & ME_HIDE);
+ case PBVH_FACES: {
+ const bool *hide_vert = BKE_pbvh_get_vert_hide(ss->pbvh);
+ return hide_vert == NULL || !hide_vert[vertex.i];
+ }
case PBVH_BMESH:
- return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN);
+ return !BM_elem_flag_test((BMVert *)vertex.i, BM_ELEM_HIDDEN);
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
BLI_bitmap **grid_hidden = BKE_pbvh_get_grid_visibility(ss->pbvh);
if (grid_hidden && grid_hidden[grid_index]) {
return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index);
@@ -436,12 +444,12 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
}
}
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int j = 0; j < ss->pmap[index].count; j++) {
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
+ for (int j = 0; j < ss->pmap[vertex.i].count; j++) {
if (ss->face_sets[vert_map->indices[j]] > 0) {
return true;
}
@@ -456,12 +464,12 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
return true;
}
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int j = 0; j < ss->pmap[index].count; j++) {
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
+ for (int j = 0; j < ss->pmap[vertex.i].count; j++) {
if (ss->face_sets[vert_map->indices[j]] < 0) {
return false;
}
@@ -472,7 +480,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
return true;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
return ss->face_sets[face_index] > 0;
}
@@ -480,12 +488,12 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
return true;
}
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
+void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int j = 0; j < ss->pmap[index].count; j++) {
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
+ for (int j = 0; j < ss->pmap[vertex.i].count; j++) {
if (ss->face_sets[vert_map->indices[j]] > 0) {
ss->face_sets[vert_map->indices[j]] = abs(face_set);
}
@@ -495,7 +503,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
break;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
if (ss->face_sets[face_index] > 0) {
ss->face_sets[face_index] = abs(face_set);
@@ -505,13 +513,13 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
}
}
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
+int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
int face_set = 0;
- for (int i = 0; i < ss->pmap[index].count; i++) {
+ for (int i = 0; i < ss->pmap[vertex.i].count; i++) {
if (ss->face_sets[vert_map->indices[i]] > face_set) {
face_set = abs(ss->face_sets[vert_map->indices[i]]);
}
@@ -522,7 +530,7 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
return 0;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
return ss->face_sets[face_index];
}
@@ -530,12 +538,12 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
return 0;
}
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
+bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int i = 0; i < ss->pmap[index].count; i++) {
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
+ for (int i = 0; i < ss->pmap[vertex.i].count; i++) {
if (ss->face_sets[vert_map->indices[i]] == face_set) {
return true;
}
@@ -546,7 +554,7 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
return true;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
return ss->face_sets[face_index] == face_set;
}
@@ -554,7 +562,7 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
return true;
}
-void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
+void SCULPT_visibility_sync_all_face_sets_to_verts(Object *ob)
{
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
@@ -574,11 +582,11 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
}
static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss,
- int index)
+ PBVHVertRef vertex)
{
- MeshElemMap *vert_map = &ss->pmap[index];
- const bool visible = SCULPT_vertex_visible_get(ss, index);
- for (int i = 0; i < ss->pmap[index].count; i++) {
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
+ const bool visible = SCULPT_vertex_visible_get(ss, vertex);
+ for (int i = 0; i < ss->pmap[vertex.i].count; i++) {
if (visible) {
ss->face_sets[vert_map->indices[i]] = abs(ss->face_sets[vert_map->indices[i]]);
}
@@ -586,18 +594,17 @@ static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSe
ss->face_sets[vert_map->indices[i]] = -abs(ss->face_sets[vert_map->indices[i]]);
}
}
- BKE_pbvh_vert_mark_update(ss->pbvh, index);
}
void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
for (int i = 0; i < ss->totfaces; i++) {
- MPoly *poly = &ss->mpoly[i];
+ const MPoly *poly = &ss->mpoly[i];
bool poly_visible = true;
for (int l = 0; l < poly->totloop; l++) {
- MLoop *loop = &ss->mloop[poly->loopstart + l];
- if (!SCULPT_vertex_visible_get(ss, (int)loop->v)) {
+ const MLoop *loop = &ss->mloop[poly->loopstart + l];
+ if (!SCULPT_vertex_visible_get(ss, BKE_pbvh_make_vref(loop->v))) {
poly_visible = false;
}
}
@@ -637,9 +644,9 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss
MeshElemMap *vert_map = &ss->pmap[v1];
int p1 = -1, p2 = -1;
for (int i = 0; i < ss->pmap[v1].count; i++) {
- MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
for (int l = 0; l < p->totloop; l++) {
- MLoop *loop = &ss->mloop[p->loopstart + l];
+ const MLoop *loop = &ss->mloop[p->loopstart + l];
if (loop->v == v2) {
if (p1 == -1) {
p1 = vert_map->indices[i];
@@ -660,18 +667,18 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss
return true;
}
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- return sculpt_check_unique_face_set_in_base_mesh(ss, index);
+ return sculpt_check_unique_face_set_in_base_mesh(ss, vertex.i);
}
case PBVH_BMESH:
return true;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
const SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
.y = vertex_index / key->grid_size};
@@ -715,10 +722,12 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
-static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
+static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter,
+ PBVHVertRef neighbor,
+ int neighbor_index)
{
for (int i = 0; i < iter->size; i++) {
- if (iter->neighbors[i] == neighbor_index) {
+ if (iter->neighbors[i].i == neighbor.i) {
return;
}
}
@@ -727,63 +736,74 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neigh
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
if (iter->neighbors == iter->neighbors_fixed) {
- iter->neighbors = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
- memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(int) * iter->size);
+ iter->neighbors = MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array");
+ memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(PBVHVertRef) * iter->size);
}
else {
iter->neighbors = MEM_reallocN_id(
- iter->neighbors, iter->capacity * sizeof(int), "neighbor array");
+ iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array");
+ }
+
+ if (iter->neighbor_indices == iter->neighbor_indices_fixed) {
+ iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
+ memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size);
+ }
+ else {
+ iter->neighbor_indices = MEM_reallocN_id(
+ iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array");
}
}
- iter->neighbors[iter->size] = neighbor_index;
+ iter->neighbors[iter->size] = neighbor;
+ iter->neighbor_indices[iter->size] = neighbor_index;
iter->size++;
}
-static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
- int index,
- SculptVertexNeighborIter *iter)
+static void sculpt_vertex_neighbors_get_bmesh(PBVHVertRef vertex, SculptVertexNeighborIter *iter)
{
- BMVert *v = BM_vert_at_index(ss->bm, index);
+ BMVert *v = (BMVert *)vertex.i;
BMIter liter;
BMLoop *l;
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
+ iter->neighbor_indices = iter->neighbor_indices_fixed;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
const BMVert *adj_v[2] = {l->prev->v, l->next->v};
for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
const BMVert *v_other = adj_v[i];
- if (BM_elem_index_get(v_other) != (int)index) {
- sculpt_vertex_neighbor_add(iter, BM_elem_index_get(v_other));
+ if (v_other != v) {
+ sculpt_vertex_neighbor_add(
+ iter, BKE_pbvh_make_vref((intptr_t)v_other), BM_elem_index_get(v_other));
}
}
}
}
static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
- int index,
+ PBVHVertRef vertex,
SculptVertexNeighborIter *iter)
{
- MeshElemMap *vert_map = &ss->pmap[index];
+ MeshElemMap *vert_map = &ss->pmap[vertex.i];
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
+ iter->neighbor_indices = iter->neighbor_indices_fixed;
- for (int i = 0; i < ss->pmap[index].count; i++) {
+ for (int i = 0; i < ss->pmap[vertex.i].count; i++) {
if (ss->face_sets[vert_map->indices[i]] < 0) {
/* Skip connectivity from hidden faces. */
continue;
}
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
uint f_adj_v[2];
- if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vertex.i, f_adj_v) != -1) {
for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (f_adj_v[j] != index) {
- sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
+ if (f_adj_v[j] != vertex.i) {
+ sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]);
}
}
}
@@ -791,14 +811,17 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (ss->fake_neighbors.use_fake_neighbors) {
BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
- if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) {
- sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]);
+ if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) {
+ sculpt_vertex_neighbor_add(
+ iter,
+ BKE_pbvh_make_vref(ss->fake_neighbors.fake_neighbor_index[vertex.i]),
+ ss->fake_neighbors.fake_neighbor_index[vertex.i]);
}
}
}
static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
- const int index,
+ const PBVHVertRef vertex,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
@@ -806,8 +829,8 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
* maybe provide coordinate and mask pointers directly rather than converting
* back and forth between #CCGElem and global index. */
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
@@ -820,17 +843,20 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
iter->num_duplicates = neighbors.num_duplicates;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
+ iter->neighbor_indices = iter->neighbor_indices_fixed;
for (int i = 0; i < neighbors.size; i++) {
- sculpt_vertex_neighbor_add(iter,
- neighbors.coords[i].grid_index * key->grid_area +
- neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x);
+ int v = neighbors.coords[i].grid_index * key->grid_area +
+ neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x;
+
+ sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v);
}
if (ss->fake_neighbors.use_fake_neighbors) {
BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
- if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) {
- sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]);
+ if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) {
+ int v = ss->fake_neighbors.fake_neighbor_index[vertex.i];
+ sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v);
}
}
@@ -840,19 +866,19 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
}
void SCULPT_vertex_neighbors_get(SculptSession *ss,
- const int index,
+ const PBVHVertRef vertex,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- sculpt_vertex_neighbors_get_faces(ss, index, iter);
+ sculpt_vertex_neighbors_get_faces(ss, vertex, iter);
return;
case PBVH_BMESH:
- sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
+ sculpt_vertex_neighbors_get_bmesh(vertex, iter);
return;
case PBVH_GRIDS:
- sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter);
+ sculpt_vertex_neighbors_get_grids(ss, vertex, include_duplicates, iter);
return;
}
}
@@ -863,24 +889,24 @@ static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss, c
return BLI_BITMAP_TEST(ss->vertex_info.boundary, index);
}
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) {
+ if (!SCULPT_vertex_all_face_sets_visible_get(ss, vertex)) {
return true;
}
- return sculpt_check_boundary_vertex_in_base_mesh(ss, index);
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, vertex.i);
}
case PBVH_BMESH: {
- BMVert *v = BM_vert_at_index(ss->bm, index);
+ BMVert *v = (BMVert *)vertex.i;
return BM_vert_is_boundary(v);
}
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = vertex.i / key->grid_area;
+ const int vertex_index = vertex.i - grid_index * key->grid_area;
const SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
.y = vertex_index / key->grid_size};
@@ -941,7 +967,7 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3],
}
typedef struct NearestVertexTLSData {
- int nearest_vertex_index;
+ PBVHVertRef nearest_vertex;
float nearest_vertex_distance_squared;
} NearestVertexTLSData;
@@ -958,7 +984,7 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
- nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex = vd.vertex;
nvtd->nearest_vertex_distance_squared = distance_squared;
}
}
@@ -971,17 +997,17 @@ static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
{
NearestVertexTLSData *join = chunk_join;
NearestVertexTLSData *nvtd = chunk;
- if (join->nearest_vertex_index == -1) {
- join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ if (join->nearest_vertex.i == PBVH_REF_NONE) {
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) {
- join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
}
-int SCULPT_nearest_vertex_get(
+PBVHVertRef SCULPT_nearest_vertex_get(
Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
{
SculptSession *ss = ob->sculpt;
@@ -996,7 +1022,7 @@ int SCULPT_nearest_vertex_get(
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
if (totnode == 0) {
- return -1;
+ return BKE_pbvh_make_vref(PBVH_REF_NONE);
}
SculptThreadedTaskData task_data = {
@@ -1008,7 +1034,7 @@ int SCULPT_nearest_vertex_get(
copy_v3_v3(task_data.nearest_vertex_search_co, co);
NearestVertexTLSData nvtd;
- nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex.i = PBVH_REF_NONE;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
TaskParallelSettings settings;
@@ -1020,7 +1046,7 @@ int SCULPT_nearest_vertex_get(
MEM_SAFE_FREE(nodes);
- return nvtd.nearest_vertex_index;
+ return nvtd.nearest_vertex;
}
bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
@@ -1075,23 +1101,27 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
int vertex_count = SCULPT_vertex_count_get(ss);
SCULPT_vertex_random_access_ensure(ss);
- flood->queue = BLI_gsqueue_new(sizeof(int));
- flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices");
+ flood->queue = BLI_gsqueue_new(sizeof(intptr_t));
+ flood->visited_verts = BLI_BITMAP_NEW(vertex_count, "visited verts");
}
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, PBVHVertRef vertex)
{
- BLI_gsqueue_push(flood->queue, &index);
+ BLI_gsqueue_push(flood->queue, &vertex);
}
-void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index)
+void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex)
{
- BLI_gsqueue_push(flood->queue, &index);
- BLI_BITMAP_ENABLE(flood->visited_vertices, index);
+ BLI_gsqueue_push(flood->queue, &vertex);
+ BLI_BITMAP_ENABLE(flood->visited_verts, vertex.i);
}
-void SCULPT_floodfill_add_initial_with_symmetry(
- Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius)
+void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ SculptFloodFill *flood,
+ PBVHVertRef vertex,
+ float radius)
{
/* Add active vertex and symmetric vertices to the queue. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@@ -1099,18 +1129,19 @@ void SCULPT_floodfill_add_initial_with_symmetry(
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
continue;
}
- int v = -1;
+ PBVHVertRef v = {PBVH_REF_NONE};
+
if (i == 0) {
- v = index;
+ v = vertex;
}
else if (radius > 0.0f) {
float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
float location[3];
- flip_v3_v3(location, SCULPT_vertex_co_get(ss, index), i);
+ flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i);
v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
}
- if (v != -1) {
+ if (v.i != PBVH_REF_NONE) {
SCULPT_floodfill_add_initial(flood, v);
}
}
@@ -1125,7 +1156,9 @@ void SCULPT_floodfill_add_active(
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
continue;
}
- int v = -1;
+
+ PBVHVertRef v = {PBVH_REF_NONE};
+
if (i == 0) {
v = SCULPT_active_vertex_get(ss);
}
@@ -1135,26 +1168,31 @@ void SCULPT_floodfill_add_active(
v = SCULPT_nearest_vertex_get(sd, ob, location, radius, false);
}
- if (v != -1) {
+ if (v.i != PBVH_REF_NONE) {
SCULPT_floodfill_add_initial(flood, v);
}
}
}
-void SCULPT_floodfill_execute(
- SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata)
+void SCULPT_floodfill_execute(SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ PBVHVertRef from_v,
+ PBVHVertRef to_v,
+ bool is_duplicate,
+ void *userdata),
+ void *userdata)
{
while (!BLI_gsqueue_is_empty(flood->queue)) {
- int from_v;
+ PBVHVertRef from_v;
+
BLI_gsqueue_pop(flood->queue, &from_v);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- const int to_v = ni.index;
+ const PBVHVertRef to_v = ni.vertex;
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
- if (BLI_BITMAP_TEST(flood->visited_vertices, to_v)) {
+ if (BLI_BITMAP_TEST(flood->visited_verts, to_v_i)) {
continue;
}
@@ -1162,7 +1200,7 @@ void SCULPT_floodfill_execute(
continue;
}
- BLI_BITMAP_ENABLE(flood->visited_vertices, to_v);
+ BLI_BITMAP_ENABLE(flood->visited_verts, BKE_pbvh_vertex_to_index(ss->pbvh, to_v));
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
BLI_gsqueue_push(flood->queue, &to_v);
@@ -1174,13 +1212,19 @@ void SCULPT_floodfill_execute(
void SCULPT_floodfill_free(SculptFloodFill *flood)
{
- MEM_SAFE_FREE(flood->visited_vertices);
+ MEM_SAFE_FREE(flood->visited_verts);
BLI_gsqueue_free(flood->queue);
flood->queue = NULL;
}
/** \} */
+static bool sculpt_tool_has_cube_tip(const char sculpt_tool)
+{
+ return ELEM(
+ sculpt_tool, SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_PAINT, SCULPT_TOOL_MULTIPLANE_SCRAPE);
+}
+
/* -------------------------------------------------------------------- */
/** \name Tool Capabilities
*
@@ -1282,10 +1326,13 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
}
}
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node,
+ SculptUndoType type)
{
SculptUndoNode *unode;
- unode = SCULPT_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+ unode = SCULPT_undo_push_node(ob, node, type);
SCULPT_orig_vert_data_unode_init(data, ob, unode);
}
@@ -1359,16 +1406,13 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
switch (data->brush->sculpt_tool) {
case SCULPT_TOOL_MASK:
type = SCULPT_UNDO_MASK;
- BKE_pbvh_node_mark_update_mask(data->nodes[n]);
break;
case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_SMEAR:
type = SCULPT_UNDO_COLOR;
- BKE_pbvh_node_mark_update_color(data->nodes[n]);
break;
default:
type = SCULPT_UNDO_COORDS;
- BKE_pbvh_node_mark_update(data->nodes[n]);
break;
}
@@ -1376,13 +1420,27 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
unode = SCULPT_undo_push_node(data->ob, data->nodes[n], type);
}
else {
- unode = SCULPT_undo_get_node(data->nodes[n]);
+ unode = SCULPT_undo_get_node(data->nodes[n], type);
}
if (!unode) {
return;
}
+ switch (type) {
+ case SCULPT_UNDO_MASK:
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ break;
+ case SCULPT_UNDO_COLOR:
+ BKE_pbvh_node_mark_update_color(data->nodes[n]);
+ break;
+ case SCULPT_UNDO_COORDS:
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ break;
+ default:
+ break;
+ }
+
PBVHVertexIter vd;
SculptOrigVertData orig_data;
@@ -1399,16 +1457,15 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
else {
copy_v3_v3(vd.fno, orig_data.no);
}
+ if (vd.mvert) {
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
+ }
}
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
*vd.mask = orig_data.mask;
}
else if (orig_data.unode->type == SCULPT_UNDO_COLOR) {
- SCULPT_vertex_color_set(ss, vd.index, orig_data.col);
- }
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ SCULPT_vertex_color_set(ss, vd.vertex, orig_data.col);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1623,7 +1680,7 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float local[4][4],
const float roundness)
{
- float side = M_SQRT1_2;
+ float side = 1.0f;
float local_co[3];
if (sculpt_brush_test_clipping(test, co)) {
@@ -2352,12 +2409,12 @@ static float brush_strength(const Sculpt *sd,
float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
- const float len,
+ float len,
const float vno[3],
const float fno[3],
- const float mask,
- const int vertex_index,
- const int thread_id)
+ float mask,
+ const PBVHVertRef vertex,
+ int thread_id)
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
@@ -2375,7 +2432,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
/* Get strength by feeding the vertex location directly into a texture. */
avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool);
}
- else if (ss->texcache) {
+ else {
float symm_point[3], point_2d[2];
/* Quite warnings. */
float x = 0.0f, y = 0.0f;
@@ -2441,7 +2498,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
avg *= 1.0f - mask;
/* Auto-masking. */
- avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex_index);
+ avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex);
return avg;
}
@@ -2810,7 +2867,7 @@ typedef struct {
float depth;
bool original;
- int active_vertex_index;
+ PBVHVertRef active_vertex;
float *face_normal;
int active_face_grid_index;
@@ -3030,13 +3087,13 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -3105,12 +3162,12 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
/* Modifying of basis key should update mesh. */
if (kb == me->key->refkey) {
- MVert *mvert = me->mvert;
+ MVert *verts = BKE_mesh_verts_for_write(me);
- for (a = 0; a < me->totvert; a++, mvert++) {
- copy_v3_v3(mvert->co, vertCos[a]);
+ for (a = 0; a < me->totvert; a++) {
+ copy_v3_v3(verts[a].co, vertCos[a]);
}
- BKE_mesh_normals_tag_dirty(me);
+ BKE_mesh_tag_coords_changed(me);
}
/* Apply new coords on active key block, no need to re-allocate kb->data here! */
@@ -3196,24 +3253,29 @@ static void do_brush_action_task_cb(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ bool need_coords = ss->cache->supports_gravity;
+
/* Face Sets modifications do a single undo push */
if (data->brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
BKE_pbvh_node_mark_redraw(data->nodes[n]);
/* Draw face sets in smooth mode moves the vertices. */
if (ss->cache->alt_smooth) {
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+ need_coords = true;
}
}
else if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
BKE_pbvh_node_mark_update_mask(data->nodes[n]);
}
- else if (SCULPT_TOOL_NEEDS_COLOR(data->brush->sculpt_tool)) {
+ else if (SCULPT_tool_is_paint(data->brush->sculpt_tool)) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
BKE_pbvh_node_mark_update_color(data->nodes[n]);
}
else {
+ need_coords = true;
+ }
+
+ if (need_coords) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_node_mark_update(data->nodes[n]);
}
@@ -3232,7 +3294,7 @@ static void do_brush_action(Sculpt *sd,
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
- if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) && SCULPT_has_loop_colors(ob)) {
+ if (SCULPT_tool_is_paint(brush->sculpt_tool) && SCULPT_has_loop_colors(ob)) {
if (type != PBVH_FACES) {
return;
}
@@ -3254,6 +3316,11 @@ static void do_brush_action(Sculpt *sd,
ss->cache->original;
float radius_scale = 1.0f;
+ /* Corners of square brushes can go outside the brush radius. */
+ if (sculpt_tool_has_cube_tip(brush->sculpt_tool)) {
+ radius_scale = M_SQRT2;
+ }
+
/* With these options enabled not all required nodes are inside the original brush radius, so
* the brush can produce artifacts in some situations. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) {
@@ -3343,7 +3410,7 @@ static void do_brush_action(Sculpt *sd,
if (brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) {
if (!ss->cache->cloth_sim) {
ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
- ss, 1.0f, 0.0f, 0.0f, false, true);
+ ob, 1.0f, 0.0f, 0.0f, false, true);
SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim);
}
SCULPT_cloth_brush_store_simulation_state(ss, ss->cache->cloth_sim);
@@ -3522,8 +3589,9 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
copy_v3_v3(ss->deform_cos[index], vd->co);
copy_v3_v3(ss->orig_cos[index], newco);
+ MVert *verts = BKE_mesh_verts_for_write(me);
if (!ss->shapekey_active) {
- copy_v3_v3(me->mvert[index].co, newco);
+ copy_v3_v3(verts[index].co, newco);
}
}
@@ -3926,27 +3994,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
}
}
-static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const int radius = BKE_brush_size_get(scene, brush);
-
- MEM_SAFE_FREE(ss->texcache);
-
- if (ss->tex_pool) {
- BKE_image_pool_free(ss->tex_pool);
- ss->tex_pool = NULL;
- }
-
- /* Need to allocate a bigger buffer for bigger brush size. */
- ss->texcache_side = 2 * radius;
- if (!ss->texcache || ss->texcache_side > ss->texcache_actual) {
- ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false);
- ss->texcache_actual = ss->texcache_side;
- ss->tex_pool = BKE_image_pool_new();
- }
-}
-
bool SCULPT_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -4338,13 +4385,16 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
* generally used to create grab deformations. */
static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
{
+ if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && (brush->flag & BRUSH_ANCHORED)) {
+ return true;
+ }
+
if (ELEM(brush->sculpt_tool,
SCULPT_TOOL_GRAB,
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_SMEAR)) {
+ SCULPT_TOOL_ELASTIC_DEFORM)) {
return true;
}
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
@@ -4692,8 +4742,8 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
(brush->sculpt_tool == SCULPT_TOOL_POSE) ||
(brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) ||
(brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) ||
- SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) ||
- (brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
+ SCULPT_tool_is_paint(brush->sculpt_tool) || (brush->sculpt_tool == SCULPT_TOOL_CLOTH) ||
+ (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) ||
(brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR) ||
(brush->sculpt_tool == SCULPT_TOOL_PAINT));
@@ -4709,7 +4759,8 @@ void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *b
if (ss->shapekey_active || ss->deform_modifiers_active ||
(!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false, false);
+ BKE_sculpt_update_object_for_edit(
+ depsgraph, ob, need_pmap, false, SCULPT_tool_is_paint(brush->sculpt_tool));
}
}
@@ -4728,7 +4779,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
}
else {
/* Intersect with coordinates from before we started stroke. */
- SculptUndoNode *unode = SCULPT_undo_get_node(node);
+ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
origco = (unode) ? unode->co : NULL;
use_origco = origco ? true : false;
}
@@ -4742,7 +4793,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
srd->ray_normal,
&srd->isect_precalc,
&srd->depth,
- &srd->active_vertex_index,
+ &srd->active_vertex,
&srd->active_face_grid_index,
srd->face_normal)) {
srd->hit = true;
@@ -4765,7 +4816,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
else {
/* Intersect with coordinates from before we started stroke. */
- SculptUndoNode *unode = SCULPT_undo_get_node(node);
+ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
origco = (unode) ? unode->co : NULL;
use_origco = origco ? true : false;
}
@@ -4876,7 +4927,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
}
/* Update the active vertex of the SculptSession. */
- ss->active_vertex_index = srd.active_vertex_index;
+ ss->active_vertex = srd.active_vertex;
SCULPT_vertex_random_access_ensure(ss);
copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss));
@@ -4950,7 +5001,10 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
+bool SCULPT_stroke_get_location(bContext *C,
+ float out[3],
+ const float mval[2],
+ bool force_original)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
@@ -4966,7 +5020,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
ss = ob->sculpt;
cache = ss->cache;
- original = (cache) ? cache->original : false;
+ original = force_original || ((cache) ? cache->original : false);
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
@@ -5029,7 +5083,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
return hit;
}
-static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
+static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss)
{
Brush *brush = BKE_paint_brush(&sd->paint);
MTex *mtex = &brush->mtex;
@@ -5040,16 +5094,16 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession
ntreeTexBeginExecTree(mtex->tex->nodetree);
}
- /* TODO: Shouldn't really have to do this at the start of every stroke, but sculpt would need
- * some sort of notification when changes are made to the texture. */
- sculpt_update_tex(scene, sd, ss);
+ if (ss->tex_pool == NULL) {
+ ss->tex_pool = BKE_image_pool_new();
+ }
}
static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ToolSettings *tool_settings = CTX_data_tool_settings(C);
+ Sculpt *sd = tool_settings->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
int mode = RNA_enum_get(op->ptr, "mode");
@@ -5066,10 +5120,11 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
}
view3d_operator_needs_opengl(C);
- sculpt_brush_init_tex(scene, sd, ss);
+ sculpt_brush_init_tex(sd, ss);
need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, mode);
- needs_colors = SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool);
+ needs_colors = SCULPT_tool_is_paint(brush->sculpt_tool) &&
+ !SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob);
if (needs_colors) {
BKE_sculpt_color_layer_create_if_needed(ob);
@@ -5078,7 +5133,8 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
/* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
* earlier steps modifying the data. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, need_mask, needs_colors);
+ BKE_sculpt_update_object_for_edit(
+ depsgraph, ob, need_pmap, need_mask, SCULPT_tool_is_paint(brush->sculpt_tool));
ED_paint_tool_update_sticky_shading_color(C, ob);
}
@@ -5280,7 +5336,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2])
{
float co_dummy[3];
- return SCULPT_stroke_get_location(C, co_dummy, mval);
+ return SCULPT_stroke_get_location(C, co_dummy, mval, false);
}
bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
@@ -5316,7 +5372,8 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* NOTE: This should be removed when paint mode is available. Paint mode can force based on the
* canvas it is painting on. (ref. use_sculpt_texture_paint). */
- if (brush && SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
+ if (brush && SCULPT_tool_is_paint(brush->sculpt_tool) &&
+ !SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
View3D *v3d = CTX_wm_view3d(C);
if (v3d->shading.type == OB_SOLID) {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
@@ -5337,7 +5394,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
ED_image_undo_push_begin(op->type->name, PAINT_MODE_SCULPT);
}
else {
- SCULPT_undo_push_begin(ob, sculpt_tool_name(sd));
+ SCULPT_undo_push_begin_ex(ob, sculpt_tool_name(sd));
}
return true;
@@ -5347,7 +5404,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
static void sculpt_stroke_update_step(bContext *C,
wmOperator *UNUSED(op),
- struct PaintStroke *UNUSED(stroke),
+ struct PaintStroke *stroke,
PointerRNA *itemptr)
{
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -5356,6 +5413,8 @@ static void sculpt_stroke_update_step(bContext *C,
SculptSession *ss = ob->sculpt;
const Brush *brush = BKE_paint_brush(&sd->paint);
ToolSettings *tool_settings = CTX_data_tool_settings(C);
+ StrokeCache *cache = ss->cache;
+ cache->stroke_distance = paint_stroke_distance_get(stroke);
SCULPT_stroke_modifiers_check(C, ob, brush);
sculpt_update_cache_variants(C, sd, ob, itemptr);
@@ -5408,7 +5467,7 @@ static void sculpt_stroke_update_step(bContext *C,
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
}
- else if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
+ else if (SCULPT_tool_is_paint(brush->sculpt_tool)) {
if (SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
SCULPT_flush_update_step(C, SCULPT_UPDATE_IMAGE);
}
@@ -5494,14 +5553,27 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
struct PaintStroke *stroke;
int ignore_background_click;
int retval;
+ Object *ob = CTX_data_active_object(C);
+
+ /* Test that ob is visible; otherwise we won't be able to get evaluated data
+ * from the depsgraph. We do this here instead of SCULPT_mode_poll
+ * to avoid falling through to the translate operator in the
+ * global view3d keymap.
+ *
+ * NOTE: #BKE_object_is_visible_in_viewport is not working here (it returns false
+ * if the object is in local view); instead, test for OB_HIDE_VIEWPORT directly.
+ */
+
+ if (ob->visibility_flag & OB_HIDE_VIEWPORT) {
+ return OPERATOR_CANCELLED;
+ }
sculpt_brush_stroke_init(C, op);
- Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) &&
+ if (SCULPT_tool_is_paint(brush->sculpt_tool) &&
!SCULPT_handles_colors_report(ob->sculpt, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -5585,6 +5657,10 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent
return paint_stroke_modal(C, op, event, (struct PaintStroke **)&op->customdata);
}
+static void sculpt_redo_empty_ui(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+}
+
void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
/* Identifiers. */
@@ -5598,9 +5674,10 @@ void SCULPT_OT_brush_stroke(wmOperatorType *ot)
ot->exec = sculpt_brush_stroke_exec;
ot->poll = SCULPT_poll;
ot->cancel = sculpt_brush_stroke_cancel;
+ ot->ui = sculpt_redo_empty_ui;
/* Flags (sculpt does own undo? (ton)). */
- ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO;
/* Properties. */
@@ -5640,10 +5717,10 @@ enum {
SCULPT_TOPOLOGY_ID_DEFAULT,
};
-static int SCULPT_vertex_get_connected_component(SculptSession *ss, int index)
+static int SCULPT_vertex_get_connected_component(SculptSession *ss, PBVHVertRef vertex)
{
if (ss->vertex_info.connected_component) {
- return ss->vertex_info.connected_component[index];
+ return ss->vertex_info.connected_component[vertex.i];
}
return SCULPT_TOPOLOGY_ID_DEFAULT;
}
@@ -5660,8 +5737,11 @@ static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist)
ss->fake_neighbors.current_max_distance = max_dist;
}
-static void SCULPT_fake_neighbor_add(SculptSession *ss, int v_index_a, int v_index_b)
+static void SCULPT_fake_neighbor_add(SculptSession *ss, PBVHVertRef v_a, PBVHVertRef v_b)
{
+ int v_index_a = BKE_pbvh_vertex_to_index(ss->pbvh, v_a);
+ int v_index_b = BKE_pbvh_vertex_to_index(ss->pbvh, v_b);
+
if (ss->fake_neighbors.fake_neighbor_index[v_index_a] == FAKE_NEIGHBOR_NONE) {
ss->fake_neighbors.fake_neighbor_index[v_index_a] = v_index_b;
ss->fake_neighbors.fake_neighbor_index[v_index_b] = v_index_a;
@@ -5674,7 +5754,7 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss)
}
typedef struct NearestVertexFakeNeighborTLSData {
- int nearest_vertex_index;
+ PBVHVertRef nearest_vertex;
float nearest_vertex_distance_squared;
int current_topology_id;
} NearestVertexFakeNeighborTLSData;
@@ -5689,13 +5769,13 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index);
+ int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.vertex);
if (vd_topology_id != nvtd->current_topology_id &&
ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) {
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
- nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex = vd.vertex;
nvtd->nearest_vertex_distance_squared = distance_squared;
}
}
@@ -5709,17 +5789,20 @@ static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata),
{
NearestVertexFakeNeighborTLSData *join = chunk_join;
NearestVertexFakeNeighborTLSData *nvtd = chunk;
- if (join->nearest_vertex_index == -1) {
- join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ if (join->nearest_vertex.i == PBVH_REF_NONE) {
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) {
- join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
}
-static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, float max_distance)
+static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd,
+ Object *ob,
+ const PBVHVertRef vertex,
+ float max_distance)
{
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
@@ -5729,12 +5812,12 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index,
.sd = sd,
.radius_squared = max_distance * max_distance,
.original = false,
- .center = SCULPT_vertex_co_get(ss, index),
+ .center = SCULPT_vertex_co_get(ss, vertex),
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
if (totnode == 0) {
- return -1;
+ return BKE_pbvh_make_vref(PBVH_REF_NONE);
}
SculptThreadedTaskData task_data = {
@@ -5744,12 +5827,12 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index,
.max_distance_squared = max_distance * max_distance,
};
- copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, index));
+ copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, vertex));
NearestVertexFakeNeighborTLSData nvtd;
- nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex.i = -1;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
- nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, index);
+ nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, vertex);
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -5760,19 +5843,26 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index,
MEM_SAFE_FREE(nodes);
- return nvtd.nearest_vertex_index;
+ return nvtd.nearest_vertex;
}
typedef struct SculptTopologyIDFloodFillData {
int next_id;
} SculptTopologyIDFloodFillData;
-static bool SCULPT_connected_components_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
+static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss,
+ PBVHVertRef from_v,
+ PBVHVertRef to_v,
+ bool UNUSED(is_duplicate),
+ void *userdata)
{
SculptTopologyIDFloodFillData *data = userdata;
- ss->vertex_info.connected_component[from_v] = data->next_id;
- ss->vertex_info.connected_component[to_v] = data->next_id;
+
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
+ ss->vertex_info.connected_component[from_v_i] = data->next_id;
+ ss->vertex_info.connected_component[to_v_i] = data->next_id;
return true;
}
@@ -5796,10 +5886,12 @@ void SCULPT_connected_components_ensure(Object *ob)
int next_id = 0;
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
if (ss->vertex_info.connected_component[i] == SCULPT_TOPOLOGY_ID_NONE) {
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_initial(&flood, i);
+ SCULPT_floodfill_add_initial(&flood, vertex);
SculptTopologyIDFloodFillData data;
data.next_id = next_id;
SCULPT_floodfill_execute(ss, &flood, SCULPT_connected_components_floodfill_cb, &data);
@@ -5817,21 +5909,25 @@ void SCULPT_boundary_info_ensure(Object *object)
}
Mesh *base_mesh = BKE_mesh_from_object(object);
+ const MEdge *edges = BKE_mesh_edges(base_mesh);
+ const MPoly *polys = BKE_mesh_polys(base_mesh);
+ const MLoop *loops = BKE_mesh_loops(base_mesh);
+
ss->vertex_info.boundary = BLI_BITMAP_NEW(base_mesh->totvert, "Boundary info");
int *adjacent_faces_edge_count = MEM_calloc_arrayN(
base_mesh->totedge, sizeof(int), "Adjacent face edge count");
for (int p = 0; p < base_mesh->totpoly; p++) {
- MPoly *poly = &base_mesh->mpoly[p];
+ const MPoly *poly = &polys[p];
for (int l = 0; l < poly->totloop; l++) {
- MLoop *loop = &base_mesh->mloop[l + poly->loopstart];
+ const MLoop *loop = &loops[l + poly->loopstart];
adjacent_faces_edge_count[loop->e]++;
}
}
for (int e = 0; e < base_mesh->totedge; e++) {
if (adjacent_faces_edge_count[e] < 2) {
- MEdge *edge = &base_mesh->medge[e];
+ const MEdge *edge = &edges[e];
BLI_BITMAP_SET(ss->vertex_info.boundary, edge->v1, true);
BLI_BITMAP_SET(ss->vertex_info.boundary, edge->v2, true);
}
@@ -5857,12 +5953,12 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
SCULPT_fake_neighbor_init(ss, max_dist);
for (int i = 0; i < totvert; i++) {
- const int from_v = i;
+ const PBVHVertRef from_v = BKE_pbvh_index_to_vertex(ss->pbvh, i);
/* This vertex does not have a fake neighbor yet, search one for it. */
- if (ss->fake_neighbors.fake_neighbor_index[from_v] == FAKE_NEIGHBOR_NONE) {
- const int to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist);
- if (to_v != -1) {
+ if (ss->fake_neighbors.fake_neighbor_index[i] == FAKE_NEIGHBOR_NONE) {
+ const PBVHVertRef to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist);
+ if (to_v.i != PBVH_REF_NONE) {
/* Add the fake neighbor if available. */
SCULPT_fake_neighbor_add(ss, from_v, to_v);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index bb101717c9b..a9fe8cc4b2f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -114,16 +114,21 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
return false;
}
-float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert)
+float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
+ SculptSession *ss,
+ PBVHVertRef vert)
{
if (!automasking) {
return 1.0f;
}
+
+ int index = BKE_pbvh_vertex_to_index(ss->pbvh, vert);
+
/* If the cache is initialized with valid info, use the cache. This is used when the
* automasking information can't be computed in real time per vertex and needs to be
* initialized for the whole mesh when the stroke starts. */
if (automasking->factor) {
- return automasking->factor[vert];
+ return automasking->factor[index];
}
if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
@@ -178,13 +183,18 @@ struct AutomaskFloodFillData {
char symm;
};
-static bool automask_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
+static bool automask_floodfill_cb(SculptSession *ss,
+ PBVHVertRef from_v,
+ PBVHVertRef to_v,
+ bool UNUSED(is_duplicate),
+ void *userdata)
{
AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata;
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
- data->automask_factor[to_v] = 1.0f;
- data->automask_factor[from_v] = 1.0f;
+ data->automask_factor[to_v_i] = 1.0f;
+ data->automask_factor[from_v_i] = 1.0f;
return (!data->use_radius ||
SCULPT_is_vertex_inside_brush_radius_symm(
SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm));
@@ -243,7 +253,9 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_active_face_set_get(ss);
for (int i : IndexRange(tot_vert)) {
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) {
automask_factor[i] *= 0.0f;
}
}
@@ -269,15 +281,17 @@ float *SCULPT_boundary_automasking_init(Object *ob,
int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor");
for (int i : IndexRange(totvert)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
- if (SCULPT_vertex_is_boundary(ss, i)) {
+ if (SCULPT_vertex_is_boundary(ss, vertex)) {
edge_distance[i] = 0;
}
break;
case AUTOMASK_INIT_BOUNDARY_FACE_SETS:
- if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
+ if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) {
edge_distance[i] = 0;
}
break;
@@ -286,11 +300,13 @@ float *SCULPT_boundary_automasking_init(Object *ob,
for (int propagation_it : IndexRange(propagation_steps)) {
for (int i : IndexRange(totvert)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
if (edge_distance[i] != EDGE_DISTANCE_INF) {
continue;
}
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
if (edge_distance[ni.index] == propagation_it) {
edge_distance[i] = propagation_it + 1;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 8bf09ce3d05..005892b88a0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -46,32 +46,38 @@
#define BOUNDARY_STEPS_NONE -1
typedef struct BoundaryInitialVertexFloodFillData {
- int initial_vertex;
+ PBVHVertRef initial_vertex;
+ int initial_vertex_i;
int boundary_initial_vertex_steps;
- int boundary_initial_vertex;
+ PBVHVertRef boundary_initial_vertex;
+ int boundary_initial_vertex_i;
int *floodfill_steps;
float radius_sq;
} BoundaryInitialVertexFloodFillData;
static bool boundary_initial_vertex_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
BoundaryInitialVertexFloodFillData *data = userdata;
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
if (!SCULPT_vertex_visible_get(ss, to_v)) {
return false;
}
if (!is_duplicate) {
- data->floodfill_steps[to_v] = data->floodfill_steps[from_v] + 1;
+ data->floodfill_steps[to_v_i] = data->floodfill_steps[from_v_i] + 1;
}
else {
- data->floodfill_steps[to_v] = data->floodfill_steps[from_v];
+ data->floodfill_steps[to_v_i] = data->floodfill_steps[from_v_i];
}
if (SCULPT_vertex_is_boundary(ss, to_v)) {
- if (data->floodfill_steps[to_v] < data->boundary_initial_vertex_steps) {
- data->boundary_initial_vertex_steps = data->floodfill_steps[to_v];
+ if (data->floodfill_steps[to_v_i] < data->boundary_initial_vertex_steps) {
+ data->boundary_initial_vertex_steps = data->floodfill_steps[to_v_i];
+ data->boundary_initial_vertex_i = to_v_i;
data->boundary_initial_vertex = to_v;
}
}
@@ -83,9 +89,9 @@ static bool boundary_initial_vertex_floodfill_cb(
/* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside
* the given radius, if it exists. */
-static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
- const int initial_vertex,
- const float radius)
+static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
+ const PBVHVertRef initial_vertex,
+ const float radius)
{
if (SCULPT_vertex_is_boundary(ss, initial_vertex)) {
@@ -98,7 +104,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
BoundaryInitialVertexFloodFillData fdata = {
.initial_vertex = initial_vertex,
- .boundary_initial_vertex = BOUNDARY_VERTEX_NONE,
+ .boundary_initial_vertex = {BOUNDARY_VERTEX_NONE},
.boundary_initial_vertex_steps = INT_MAX,
.radius_sq = radius * radius,
};
@@ -119,34 +125,38 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
static int BOUNDARY_INDICES_BLOCK_SIZE = 300;
static void sculpt_boundary_index_add(SculptBoundary *boundary,
+ const PBVHVertRef new_vertex,
const int new_index,
const float distance,
- GSet *included_vertices)
+ GSet *included_verts)
{
- boundary->vertices[boundary->num_vertices] = new_index;
+ boundary->verts[boundary->verts_num] = new_vertex;
+
if (boundary->distance) {
boundary->distance[new_index] = distance;
}
- if (included_vertices) {
- BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index));
+ if (included_verts) {
+ BLI_gset_add(included_verts, POINTER_FROM_INT(new_index));
}
- boundary->num_vertices++;
- if (boundary->num_vertices >= boundary->vertices_capacity) {
- boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
- boundary->vertices = MEM_reallocN_id(
- boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices");
+ boundary->verts_num++;
+ if (boundary->verts_num >= boundary->verts_capacity) {
+ boundary->verts_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
+ boundary->verts = MEM_reallocN_id(
+ boundary->verts, boundary->verts_capacity * sizeof(PBVHVertRef), "boundary indices");
}
};
-static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
+static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary,
+ const PBVHVertRef v1,
+ const PBVHVertRef v2)
{
- boundary->edges[boundary->num_edges].v1 = v1;
- boundary->edges[boundary->num_edges].v2 = v2;
- boundary->num_edges++;
+ boundary->edges[boundary->edges_num].v1 = v1;
+ boundary->edges[boundary->edges_num].v2 = v2;
+ boundary->edges_num++;
- if (boundary->num_edges >= boundary->edges_capacity) {
+ if (boundary->edges_num >= boundary->edges_capacity) {
boundary->edges_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
boundary->edges = MEM_reallocN_id(boundary->edges,
boundary->edges_capacity * sizeof(SculptBoundaryPreviewEdge),
@@ -159,7 +169,7 @@ static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int
* as well as to check if the initial vertex is valid.
*/
static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
- const int initial_vertex)
+ const PBVHVertRef initial_vertex)
{
if (!SCULPT_vertex_visible_get(ss, initial_vertex)) {
@@ -170,9 +180,9 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
int boundary_vertex_count = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) {
- if (SCULPT_vertex_visible_get(ss, ni.index)) {
+ if (SCULPT_vertex_visible_get(ss, ni.vertex)) {
neighbor_count++;
- if (SCULPT_vertex_is_boundary(ss, ni.index)) {
+ if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
boundary_vertex_count++;
}
}
@@ -199,16 +209,19 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
typedef struct BoundaryFloodFillData {
SculptBoundary *boundary;
- GSet *included_vertices;
+ GSet *included_verts;
EdgeSet *preview_edges;
- int last_visited_vertex;
+ PBVHVertRef last_visited_vertex;
} BoundaryFloodFillData;
static bool boundary_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
BoundaryFloodFillData *data = userdata;
SculptBoundary *boundary = data->boundary;
if (!SCULPT_vertex_is_boundary(ss, to_v)) {
@@ -217,9 +230,10 @@ static bool boundary_floodfill_cb(
const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v),
SCULPT_vertex_co_get(ss, to_v));
const float distance_boundary_to_dst = boundary->distance ?
- boundary->distance[from_v] + edge_len :
+ boundary->distance[from_v_i] + edge_len :
0.0f;
- sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices);
+ sculpt_boundary_index_add(
+ boundary, to_v, to_v_i, distance_boundary_to_dst, data->included_verts);
if (!is_duplicate) {
sculpt_boundary_preview_edge_add(boundary, from_v, to_v);
}
@@ -229,32 +243,38 @@ static bool boundary_floodfill_cb(
static void sculpt_boundary_indices_init(SculptSession *ss,
SculptBoundary *boundary,
const bool init_boundary_distances,
- const int initial_boundary_index)
+ const PBVHVertRef initial_boundary_vertex)
{
const int totvert = SCULPT_vertex_count_get(ss);
- boundary->vertices = MEM_malloc_arrayN(
- BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices");
+ boundary->verts = MEM_malloc_arrayN(
+ BOUNDARY_INDICES_BLOCK_SIZE, sizeof(PBVHVertRef), "boundary indices");
+
if (init_boundary_distances) {
boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances");
}
boundary->edges = MEM_malloc_arrayN(
BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptBoundaryPreviewEdge), "boundary edges");
- GSet *included_vertices = BLI_gset_int_new_ex("included vertices", BOUNDARY_INDICES_BLOCK_SIZE);
+ GSet *included_verts = BLI_gset_int_new_ex("included verts", BOUNDARY_INDICES_BLOCK_SIZE);
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
- boundary->initial_vertex = initial_boundary_index;
+ int initial_boundary_index = BKE_pbvh_vertex_to_index(ss->pbvh, initial_boundary_vertex);
+
+ boundary->initial_vertex = initial_boundary_vertex;
+ boundary->initial_vertex_i = initial_boundary_index;
+
copy_v3_v3(boundary->initial_vertex_position,
SCULPT_vertex_co_get(ss, boundary->initial_vertex));
- sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices);
- SCULPT_floodfill_add_initial(&flood, initial_boundary_index);
+ sculpt_boundary_index_add(
+ boundary, initial_boundary_vertex, initial_boundary_index, 0.0f, included_verts);
+ SCULPT_floodfill_add_initial(&flood, boundary->initial_vertex);
BoundaryFloodFillData fdata = {
.boundary = boundary,
- .included_vertices = included_vertices,
- .last_visited_vertex = BOUNDARY_VERTEX_NONE,
+ .included_verts = included_verts,
+ .last_visited_vertex = {BOUNDARY_VERTEX_NONE},
};
@@ -262,20 +282,20 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
SCULPT_floodfill_free(&flood);
/* Check if the boundary loops into itself and add the extra preview edge to close the loop. */
- if (fdata.last_visited_vertex != BOUNDARY_VERTEX_NONE &&
+ if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE &&
sculpt_boundary_is_vertex_in_editable_boundary(ss, fdata.last_visited_vertex)) {
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, fdata.last_visited_vertex, ni) {
- if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) &&
- sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.index)) {
- sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.index);
+ if (BLI_gset_haskey(included_verts, POINTER_FROM_INT(ni.index)) &&
+ sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.vertex)) {
+ sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.vertex);
boundary->forms_loop = true;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
- BLI_gset_free(included_vertices, NULL);
+ BLI_gset_free(included_verts, NULL);
}
/**
@@ -286,7 +306,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
*/
static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptBoundary *boundary,
- const int initial_vertex,
+ const PBVHVertRef initial_vertex,
const float radius)
{
const int totvert = SCULPT_vertex_count_get(ss);
@@ -297,72 +317,78 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info");
for (int i = 0; i < totvert; i++) {
- boundary->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE;
- boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE;
+ boundary->edit_info[i].original_vertex_i = BOUNDARY_VERTEX_NONE;
+ boundary->edit_info[i].propagation_steps_num = BOUNDARY_STEPS_NONE;
}
- GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int));
- GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int));
+ GSQueue *current_iteration = BLI_gsqueue_new(sizeof(PBVHVertRef));
+ GSQueue *next_iteration = BLI_gsqueue_new(sizeof(PBVHVertRef));
/* Initialized the first iteration with the vertices already in the boundary. This is propagation
* step 0. */
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
- for (int i = 0; i < boundary->num_vertices; i++) {
- boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i];
- boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0;
+ BLI_bitmap *visited_verts = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_verts");
+ for (int i = 0; i < boundary->verts_num; i++) {
+ int index = BKE_pbvh_vertex_to_index(ss->pbvh, boundary->verts[i]);
+
+ boundary->edit_info[index].original_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh,
+ boundary->verts[i]);
+ boundary->edit_info[index].propagation_steps_num = 0;
/* This ensures that all duplicate vertices in the boundary have the same original_vertex
* index, so the deformation for them will be the same. */
if (has_duplicates) {
SculptVertexNeighborIter ni_duplis;
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) {
+ SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->verts[i], ni_duplis) {
if (ni_duplis.is_duplicate) {
- boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i];
+ boundary->edit_info[ni_duplis.index].original_vertex_i = BKE_pbvh_vertex_to_index(
+ ss->pbvh, boundary->verts[i]);
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
}
- BLI_gsqueue_push(current_iteration, &boundary->vertices[i]);
+ BLI_gsqueue_push(current_iteration, &boundary->verts[i]);
}
- int num_propagation_steps = 0;
+ int propagation_steps_num = 0;
float accum_distance = 0.0f;
while (true) {
/* Stop adding steps to edit info. This happens when a steps is further away from the boundary
* than the brush radius or when the entire mesh was already processed. */
if (accum_distance > radius || BLI_gsqueue_is_empty(current_iteration)) {
- boundary->max_propagation_steps = num_propagation_steps;
+ boundary->max_propagation_steps = propagation_steps_num;
break;
}
while (!BLI_gsqueue_is_empty(current_iteration)) {
- int from_v;
+ PBVHVertRef from_v;
BLI_gsqueue_pop(current_iteration, &from_v);
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index);
+ const bool is_visible = SCULPT_vertex_visible_get(ss, ni.vertex);
if (!is_visible ||
- boundary->edit_info[ni.index].num_propagation_steps != BOUNDARY_STEPS_NONE) {
+ boundary->edit_info[ni.index].propagation_steps_num != BOUNDARY_STEPS_NONE) {
continue;
}
- boundary->edit_info[ni.index].original_vertex =
- boundary->edit_info[from_v].original_vertex;
+ boundary->edit_info[ni.index].original_vertex_i =
+ boundary->edit_info[from_v_i].original_vertex_i;
- BLI_BITMAP_ENABLE(visited_vertices, ni.index);
+ BLI_BITMAP_ENABLE(visited_verts, ni.index);
if (ni.is_duplicate) {
/* Grids duplicates handling. */
- boundary->edit_info[ni.index].num_propagation_steps =
- boundary->edit_info[from_v].num_propagation_steps;
+ boundary->edit_info[ni.index].propagation_steps_num =
+ boundary->edit_info[from_v_i].propagation_steps_num;
}
else {
- boundary->edit_info[ni.index].num_propagation_steps =
- boundary->edit_info[from_v].num_propagation_steps + 1;
+ boundary->edit_info[ni.index].propagation_steps_num =
+ boundary->edit_info[from_v_i].propagation_steps_num + 1;
- BLI_gsqueue_push(next_iteration, &ni.index);
+ BLI_gsqueue_push(next_iteration, &ni.vertex);
/* When copying the data to the neighbor for the next iteration, it has to be copied to
* all its duplicates too. This is because it is not possible to know if the updated
@@ -370,12 +396,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
* copy the data in the from_v neighbor iterator. */
if (has_duplicates) {
SculptVertexNeighborIter ni_duplis;
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.index, ni_duplis) {
+ SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.vertex, ni_duplis) {
if (ni_duplis.is_duplicate) {
- boundary->edit_info[ni_duplis.index].original_vertex =
- boundary->edit_info[from_v].original_vertex;
- boundary->edit_info[ni_duplis.index].num_propagation_steps =
- boundary->edit_info[from_v].num_propagation_steps + 1;
+ boundary->edit_info[ni_duplis.index].original_vertex_i =
+ boundary->edit_info[from_v_i].original_vertex_i;
+ boundary->edit_info[ni_duplis.index].propagation_steps_num =
+ boundary->edit_info[from_v_i].propagation_steps_num + 1;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
@@ -383,11 +409,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Check the distance using the vertex that was propagated from the initial vertex that
* was used to initialize the boundary. */
- if (boundary->edit_info[from_v].original_vertex == initial_vertex) {
- boundary->pivot_vertex = ni.index;
- copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index));
+ if (boundary->edit_info[from_v_i].original_vertex_i ==
+ BKE_pbvh_vertex_to_index(ss->pbvh, initial_vertex)) {
+ boundary->pivot_vertex = ni.vertex;
+ copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.vertex));
accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v),
- SCULPT_vertex_co_get(ss, ni.index));
+ SCULPT_vertex_co_get(ss, ni.vertex));
}
}
}
@@ -396,15 +423,15 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Copy the new vertices to the queue to be processed in the next iteration. */
while (!BLI_gsqueue_is_empty(next_iteration)) {
- int next_v;
+ PBVHVertRef next_v;
BLI_gsqueue_pop(next_iteration, &next_v);
BLI_gsqueue_push(current_iteration, &next_v);
}
- num_propagation_steps++;
+ propagation_steps_num++;
}
- MEM_SAFE_FREE(visited_vertices);
+ MEM_SAFE_FREE(visited_verts);
BLI_gsqueue_free(current_iteration);
BLI_gsqueue_free(next_iteration);
@@ -422,12 +449,13 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
BKE_curvemapping_init(brush->curve);
for (int i = 0; i < totvert; i++) {
- if (boundary->edit_info[i].num_propagation_steps != -1) {
+ if (boundary->edit_info[i].propagation_steps_num != -1) {
boundary->edit_info[i].strength_factor = BKE_brush_curve_strength(
- brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps);
+ brush, boundary->edit_info[i].propagation_steps_num, boundary->max_propagation_steps);
}
- if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) {
+ if (boundary->edit_info[i].original_vertex_i ==
+ BKE_pbvh_vertex_to_index(ss->pbvh, boundary->initial_vertex)) {
/* All vertices that are propagated from the original vertex won't be affected by the
* boundary falloff, so there is no need to calculate anything else. */
continue;
@@ -439,7 +467,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
continue;
}
- const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex];
+ const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex_i];
float falloff_distance = 0.0f;
float direction = 1.0f;
@@ -473,22 +501,22 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
- const int initial_vertex,
+ const PBVHVertRef initial_vertex,
const float radius)
{
SculptSession *ss = object->sculpt;
- if (initial_vertex == BOUNDARY_VERTEX_NONE) {
+ if (initial_vertex.i == PBVH_REF_NONE) {
return NULL;
}
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(object);
- const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
+ const PBVHVertRef boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
ss, initial_vertex, radius);
- if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) {
+ if (boundary_initial_vertex.i == BOUNDARY_VERTEX_NONE) {
return NULL;
}
@@ -514,7 +542,7 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object,
void SCULPT_boundary_data_free(SculptBoundary *boundary)
{
- MEM_SAFE_FREE(boundary->vertices);
+ MEM_SAFE_FREE(boundary->verts);
MEM_SAFE_FREE(boundary->edges);
MEM_SAFE_FREE(boundary->distance);
MEM_SAFE_FREE(boundary->edit_info);
@@ -536,30 +564,35 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo
boundary->bend.pivot_positions = MEM_calloc_arrayN(totvert, sizeof(float[3]), "pivot positions");
for (int i = 0; i < totvert; i++) {
- if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
+ if (boundary->edit_info[i].propagation_steps_num != boundary->max_propagation_steps) {
continue;
}
+
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float dir[3];
float normal[3];
- SCULPT_vertex_normal_get(ss, i, normal);
- sub_v3_v3v3(dir,
- SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
- SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, vertex, normal);
+ sub_v3_v3v3(
+ dir,
+ SCULPT_vertex_co_get(
+ ss, BKE_pbvh_index_to_vertex(ss->pbvh, boundary->edit_info[i].original_vertex_i)),
+ SCULPT_vertex_co_get(ss, vertex));
cross_v3_v3v3(
- boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal);
- normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
- copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex],
- SCULPT_vertex_co_get(ss, i));
+ boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i], dir, normal);
+ normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]);
+ copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i],
+ SCULPT_vertex_co_get(ss, vertex));
}
for (int i = 0; i < totvert; i++) {
- if (boundary->edit_info[i].num_propagation_steps == BOUNDARY_STEPS_NONE) {
+ if (boundary->edit_info[i].propagation_steps_num == BOUNDARY_STEPS_NONE) {
continue;
}
copy_v3_v3(boundary->bend.pivot_positions[i],
- boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]);
+ boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i]);
copy_v3_v3(boundary->bend.pivot_rotation_axis[i],
- boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
+ boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]);
}
}
@@ -569,36 +602,37 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b
boundary->slide.directions = MEM_calloc_arrayN(totvert, sizeof(float[3]), "slide directions");
for (int i = 0; i < totvert; i++) {
- if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
+ if (boundary->edit_info[i].propagation_steps_num != boundary->max_propagation_steps) {
continue;
}
- sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
- SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
- SCULPT_vertex_co_get(ss, i));
- normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]);
+ sub_v3_v3v3(
+ boundary->slide.directions[boundary->edit_info[i].original_vertex_i],
+ SCULPT_vertex_co_get(
+ ss, BKE_pbvh_index_to_vertex(ss->pbvh, boundary->edit_info[i].original_vertex_i)),
+ SCULPT_vertex_co_get(ss, BKE_pbvh_index_to_vertex(ss->pbvh, i)));
+ normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex_i]);
}
for (int i = 0; i < totvert; i++) {
- if (boundary->edit_info[i].num_propagation_steps == BOUNDARY_STEPS_NONE) {
+ if (boundary->edit_info[i].propagation_steps_num == BOUNDARY_STEPS_NONE) {
continue;
}
copy_v3_v3(boundary->slide.directions[i],
- boundary->slide.directions[boundary->edit_info[i].original_vertex]);
+ boundary->slide.directions[boundary->edit_info[i].original_vertex_i]);
}
}
static void sculpt_boundary_twist_data_init(SculptSession *ss, SculptBoundary *boundary)
{
zero_v3(boundary->twist.pivot_position);
- float(*poly_verts)[3] = MEM_malloc_arrayN(
- boundary->num_vertices, sizeof(float[3]), "poly verts");
- for (int i = 0; i < boundary->num_vertices; i++) {
- add_v3_v3(boundary->twist.pivot_position, SCULPT_vertex_co_get(ss, boundary->vertices[i]));
- copy_v3_v3(poly_verts[i], SCULPT_vertex_co_get(ss, boundary->vertices[i]));
+ float(*poly_verts)[3] = MEM_malloc_arrayN(boundary->verts_num, sizeof(float[3]), "poly verts");
+ for (int i = 0; i < boundary->verts_num; i++) {
+ add_v3_v3(boundary->twist.pivot_position, SCULPT_vertex_co_get(ss, boundary->verts[i]));
+ copy_v3_v3(poly_verts[i], SCULPT_vertex_co_get(ss, boundary->verts[i]));
}
- mul_v3_fl(boundary->twist.pivot_position, 1.0f / boundary->num_vertices);
+ mul_v3_fl(boundary->twist.pivot_position, 1.0f / boundary->verts_num);
if (boundary->forms_loop) {
- normal_poly_v3(boundary->twist.rotation_axis, poly_verts, boundary->num_vertices);
+ normal_poly_v3(boundary->twist.rotation_axis, poly_verts, boundary->verts_num);
}
else {
sub_v3_v3v3(boundary->twist.rotation_axis,
@@ -638,7 +672,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -649,7 +683,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
const float angle = angle_factor * M_PI;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
+ if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
@@ -660,7 +694,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
@@ -671,7 +705,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -692,12 +726,12 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
+ if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
@@ -708,7 +742,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -717,7 +751,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
strength);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -738,12 +772,12 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
+ if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
@@ -754,7 +788,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -763,7 +797,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
strength);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -784,10 +818,10 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
+ if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
@@ -798,7 +832,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -806,7 +840,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
boundary->edit_info[vd.index].strength_factor * mask * automask * strength);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -827,7 +861,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -838,7 +872,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
const float angle = angle_factor * M_PI;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
+ if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
@@ -849,7 +883,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position);
@@ -860,7 +894,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
add_v3_v3(target_co, boundary->twist.pivot_position);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -881,10 +915,10 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
+ if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
@@ -896,11 +930,11 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
float coord_accum[3] = {0.0f, 0.0f, 0.0f};
int total_neighbors = 0;
- const int current_propagation_steps = boundary->edit_info[vd.index].num_propagation_steps;
+ const int current_propagation_steps = boundary->edit_info[vd.index].propagation_steps_num;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- if (current_propagation_steps == boundary->edit_info[ni.index].num_propagation_steps) {
- add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.index));
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
+ if (current_propagation_steps == boundary->edit_info[ni.index].propagation_steps_num) {
+ add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.vertex));
total_neighbors++;
}
}
@@ -919,7 +953,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
target_co, vd.co, disp, boundary->edit_info[vd.index].strength_factor * mask * strength);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -933,7 +967,8 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
const int symm_area = ss->cache->mirror_symmetry_pass;
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- int initial_vertex;
+ PBVHVertRef initial_vertex;
+
if (ss->cache->mirror_symmetry_pass == 0) {
initial_vertex = SCULPT_active_vertex_get(ss);
}
@@ -1017,8 +1052,8 @@ void SCULPT_boundary_edges_preview_draw(const uint gpuattr,
}
immUniformColor3fvAlpha(outline_col, outline_alpha);
GPU_line_width(2.0f);
- immBegin(GPU_PRIM_LINES, ss->boundary_preview->num_edges * 2);
- for (int i = 0; i < ss->boundary_preview->num_edges; i++) {
+ immBegin(GPU_PRIM_LINES, ss->boundary_preview->edges_num * 2);
+ for (int i = 0; i < ss->boundary_preview->edges_num; i++) {
immVertex3fv(gpuattr, SCULPT_vertex_co_get(ss, ss->boundary_preview->edges[i].v1));
immVertex3fv(gpuattr, SCULPT_vertex_co_get(ss, ss->boundary_preview->edges[i].v2));
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
index 39544a41a87..245cbe0f54e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -314,13 +314,13 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -412,13 +412,13 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -510,13 +510,13 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -628,13 +628,13 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -783,13 +783,13 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
}
@@ -940,13 +940,13 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1066,13 +1066,13 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1219,7 +1219,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
}
@@ -1267,12 +1267,12 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
if (vd.mask) {
mul_v3_fl(disp, 1.0f - *vd.mask);
}
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex));
copy_v3_v3(proxy[vd.i], disp);
}
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1330,7 +1330,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -1352,13 +1352,13 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1403,7 +1403,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -1426,7 +1426,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
@@ -1436,7 +1436,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
sub_v3_v3(proxy[vd.i], orig_data.co);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1477,7 +1477,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
@@ -1497,7 +1497,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
const int vi = vd.index;
@@ -1533,9 +1533,10 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
float normal[3];
if (use_persistent_base) {
- SCULPT_vertex_persistent_normal_get(ss, vi, normal);
+ SCULPT_vertex_persistent_normal_get(ss, vd.vertex, normal);
mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
+ madd_v3_v3v3fl(
+ final_co, SCULPT_vertex_persistent_co_get(ss, vd.vertex), normal, *disp_factor);
}
else {
copy_v3_v3(normal, orig_data.no);
@@ -1551,7 +1552,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
SCULPT_clip(sd, ss, vd.co, final_co);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1609,7 +1610,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float val[3];
@@ -1624,7 +1625,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1677,13 +1678,13 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1756,7 +1757,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float val1[3];
float val2[3];
@@ -1777,7 +1778,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
add_v3_v3v3(proxy[vd.i], val1, val2);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1872,7 +1873,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float disp_center[3];
float x_disp[3];
@@ -1896,7 +1897,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(proxy[vd.i], disp_center, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1964,7 +1965,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -1988,7 +1989,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
if (grab_silhouette) {
@@ -2005,7 +2006,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2052,7 +2053,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2108,12 +2109,12 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
mul_v3_fl(final_disp, 1.0f - *vd.mask);
}
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex));
copy_v3_v3(proxy[vd.i], final_disp);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2163,7 +2164,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
float(*proxy)[3];
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2185,13 +2186,13 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2247,7 +2248,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
float(*proxy)[3];
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2268,7 +2269,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float current_disp[3];
float current_disp_norm[3];
@@ -2290,10 +2291,10 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co);
normalize_v3_v3(vertex_disp_norm, vertex_disp);
if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
@@ -2304,7 +2305,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(proxy[vd.i], final_disp, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2323,31 +2324,31 @@ void SCULPT_relax_vertex(SculptSession *ss,
int neighbor_count = 0;
zero_v3(smooth_pos);
zero_v3(boundary_normal);
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->vertex);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) {
neighbor_count++;
if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.vertex))) {
/* When the vertex to relax is boundary, use only connected boundary vertices for the average
* position. */
if (is_boundary) {
- if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
+ if (!SCULPT_vertex_is_boundary(ss, ni.vertex)) {
continue;
}
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex));
avg_count++;
/* Calculate a normal for the constraint plane using the edges of the boundary. */
float to_neighbor[3];
- sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.vertex), vd->co);
normalize_v3(to_neighbor);
add_v3_v3(boundary_normal, to_neighbor);
}
else {
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex));
avg_count++;
}
}
@@ -2376,7 +2377,7 @@ void SCULPT_relax_vertex(SculptSession *ss,
normalize_v3_v3(vno, boundary_normal);
}
else {
- SCULPT_vertex_normal_get(ss, vd->index, vno);
+ SCULPT_vertex_normal_get(ss, vd->vertex, vno);
}
if (is_zero_v3(vno)) {
@@ -2404,7 +2405,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
@@ -2425,12 +2426,12 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2501,17 +2502,17 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float limit_co[3];
float disp[3];
- SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
+ SCULPT_vertex_limit_surface_get(ss, vd.vertex, limit_co);
sub_v3_v3v3(disp, limit_co, vd.co);
mul_v3_v3fl(proxy[vd.i], disp, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2567,7 +2568,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float current_disp[3];
@@ -2594,11 +2595,11 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
float weights_accum = 1.0f;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
float neighbor_limit_co[3];
- SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ SCULPT_vertex_limit_surface_get(ss, ni.vertex, neighbor_limit_co);
sub_v3_v3v3(vertex_disp,
ss->cache->limit_surface_co[ni.index],
ss->cache->limit_surface_co[vd.index]);
@@ -2623,7 +2624,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
interp_v3_v3v3(vd.co, vd.co, new_co, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2638,7 +2639,7 @@ static void do_displacement_smear_store_prev_disp_task_cb_ex(
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
- SCULPT_vertex_co_get(ss, vd.index),
+ SCULPT_vertex_co_get(ss, vd.vertex),
ss->cache->limit_surface_co[vd.index]);
}
BKE_pbvh_vertex_iter_end;
@@ -2657,9 +2658,11 @@ void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes
totvert, sizeof(float[3]), "prev displacement");
ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_limit_surface_get(ss, vertex, ss->cache->limit_surface_co[i]);
sub_v3_v3v3(ss->cache->prev_displacement[i],
- SCULPT_vertex_co_get(ss, i),
+ SCULPT_vertex_co_get(ss, vertex),
ss->cache->limit_surface_co[i]);
}
}
@@ -2722,7 +2725,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const float fade =
bstrength *
SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.vertex, thread_id) *
ss->cache->pressure;
float avg[3], val[3];
@@ -2736,7 +2739,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
SCULPT_clip(sd, ss, vd.co, val);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -2799,7 +2802,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
}
const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.vertex, thread_id);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
@@ -2808,12 +2811,8 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
(*vd.mask) += fade * bstrength * (*vd.mask);
}
*vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 9d231f2ccd2..691dfa21851 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -220,13 +220,16 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
+ PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1);
+ PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2);
+
if (use_persistent) {
- length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1),
- SCULPT_vertex_persistent_co_get(ss, v2));
+ length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, vertex1),
+ SCULPT_vertex_persistent_co_get(ss, vertex2));
}
else {
- length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1),
- SCULPT_vertex_co_get(ss, v2));
+ length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, vertex1),
+ SCULPT_vertex_co_get(ss, vertex2));
}
length_constraint->strength = 1.0f;
@@ -370,7 +373,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
int tot_indices = 0;
build_indices[tot_indices] = vd.index;
tot_indices++;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
build_indices[tot_indices] = ni.index;
tot_indices++;
}
@@ -540,7 +543,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float brush_disp[3];
@@ -611,13 +614,17 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-static ListBase *cloth_brush_collider_cache_create(Depsgraph *depsgraph)
+static ListBase *cloth_brush_collider_cache_create(Object *object, Depsgraph *depsgraph)
{
ListBase *cache = NULL;
DEG_OBJECT_ITER_BEGIN (depsgraph,
ob,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_DUPLI) {
+ if (STREQ(object->id.name, ob->id.name)) {
+ continue;
+ }
+
CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Collision);
if (!cmd) {
@@ -780,7 +787,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor);
const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
- SCULPT_automasking_factor_get(automasking, ss, vd.index);
+ SCULPT_automasking_factor_get(automasking, ss, vd.vertex);
madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
@@ -798,7 +805,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
copy_v3_v3(vd.co, cloth_sim->pos[vd.index]);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -848,10 +855,13 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
mul_v3_v3fl(correction_vector_half, correction_vector, 0.5f);
- const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1)) *
- SCULPT_automasking_factor_get(automasking, ss, v1);
- const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) *
- SCULPT_automasking_factor_get(automasking, ss, v2);
+ PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1);
+ PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2);
+
+ const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, vertex1)) *
+ SCULPT_automasking_factor_get(automasking, ss, vertex1);
+ const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, vertex2)) *
+ SCULPT_automasking_factor_get(automasking, ss, vertex2);
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
@@ -1029,13 +1039,14 @@ static void cloth_sim_initialize_default_node_state(SculptSession *ss,
MEM_SAFE_FREE(nodes);
}
-SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
+SculptClothSimulation *SCULPT_cloth_brush_simulation_create(Object *ob,
const float cloth_mass,
const float cloth_damping,
const float cloth_softbody_strength,
const bool use_collisions,
const bool needs_deform_coords)
{
+ SculptSession *ss = ob->sculpt;
const int totverts = SCULPT_vertex_count_get(ss);
SculptClothSimulation *cloth_sim;
@@ -1073,7 +1084,7 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
cloth_sim->softbody_strength = cloth_softbody_strength;
if (use_collisions) {
- cloth_sim->collider_list = cloth_brush_collider_cache_create(ss->depsgraph);
+ cloth_sim->collider_list = cloth_brush_collider_cache_create(ob, ss->depsgraph);
}
cloth_sim_initialize_default_node_state(ss, cloth_sim);
@@ -1124,15 +1135,17 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation
const bool has_deformation_pos = cloth_sim->deformation_pos != NULL;
const bool has_softbody_pos = cloth_sim->softbody_pos != NULL;
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
- copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
- copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, vertex));
+ copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, vertex));
+ copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, vertex));
if (has_deformation_pos) {
- copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, vertex));
cloth_sim->deformation_strength[i] = 1.0f;
}
if (has_softbody_pos) {
- copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, vertex));
}
}
}
@@ -1141,7 +1154,9 @@ void SCULPT_cloth_brush_store_simulation_state(SculptSession *ss, SculptClothSim
{
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex));
}
}
@@ -1184,7 +1199,7 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* The simulation structure only needs to be created on the first symmetry pass. */
if (SCULPT_stroke_is_first_brush_step(ss->cache) || !ss->cache->cloth_sim) {
ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
- ss,
+ ob,
brush->cloth_mass,
brush->cloth_damping,
brush->cloth_constraint_softbody_strength,
@@ -1422,13 +1437,13 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float fade = vd.mask ? *vd.mask : 0.0f;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
fade = 1.0f - fade;
float force[3] = {0.0f, 0.0f, 0.0f};
float disp[3], temp[3], transform[3][3];
if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
- if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
+ if (!SCULPT_vertex_has_face_set(ss, vd.vertex, ss->filter_cache->active_face_set)) {
continue;
}
}
@@ -1447,7 +1462,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
break;
case CLOTH_FILTER_INFLATE: {
float normal[3];
- SCULPT_vertex_normal_get(ss, vd.index, normal);
+ SCULPT_vertex_normal_get(ss, vd.vertex, normal);
mul_v3_v3fl(force, normal, fade * data->filter_strength);
} break;
case CLOTH_FILTER_EXPAND:
@@ -1512,7 +1527,9 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex));
}
SculptThreadedTaskData data = {
@@ -1562,7 +1579,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
/* Needs mask data to be available as it is used when solving the constraints. */
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
- SCULPT_undo_push_begin(ob, "Cloth filter");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
ss->filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
@@ -1571,7 +1588,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
ss->filter_cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
- ss,
+ ob,
cloth_mass,
cloth_damping,
0.0f,
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index 00503087e39..8f87cd1b6ed 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -76,7 +76,7 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C)
/** \name Detail Flood Fill
* \{ */
-static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
+static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
@@ -106,7 +106,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
- SCULPT_undo_push_begin(ob, "Dynamic topology flood fill");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
while (BKE_pbvh_bmesh_update_topology(
@@ -174,13 +174,13 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
/* Average the edge length of the connected edges to the active vertex. */
- int active_vertex = SCULPT_active_vertex_get(ss);
+ PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
const float *active_vertex_co = SCULPT_active_vertex_co_get(ss);
float edge_length = 0.0f;
int tot = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
- edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index));
+ edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.vertex));
tot += 1;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -578,14 +578,14 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob,
DyntopoDetailSizeEditCustomData *cd)
{
SculptSession *ss = ob->sculpt;
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
float len_accum = 0;
int num_neighbors = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
- SCULPT_vertex_co_get(ss, ni.index));
+ SCULPT_vertex_co_get(ss, ni.vertex));
num_neighbors++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 4f884420401..ad8a1cde9dc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -92,13 +92,16 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
{
int cd_node_layer_index;
- char layer_id[] = "_dyntopo_node_id";
+ char node_vertex_id[] = "_dyntopo_vnode_id";
+ char node_face_id[] = "_dyntopo_fnode_id";
+
+ cd_node_layer_index = CustomData_get_named_layer_index(
+ &ss->bm->vdata, CD_PROP_INT32, node_vertex_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, layer_id);
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, node_vertex_id);
cd_node_layer_index = CustomData_get_named_layer_index(
- &ss->bm->vdata, CD_PROP_INT32, layer_id);
+ &ss->bm->vdata, CD_PROP_INT32, node_vertex_id);
}
ss->cd_vert_node_offset = CustomData_get_n_offset(
@@ -108,11 +111,12 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT32, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(
+ &ss->bm->pdata, CD_PROP_INT32, node_face_id);
if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, layer_id);
+ BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, node_face_id);
cd_node_layer_index = CustomData_get_named_layer_index(
- &ss->bm->pdata, CD_PROP_INT32, layer_id);
+ &ss->bm->pdata, CD_PROP_INT32, node_face_id);
}
ss->cd_face_node_offset = CustomData_get_n_offset(
@@ -206,15 +210,13 @@ static void SCULPT_dynamic_topology_disable_ex(
&geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop);
CustomData_copy(
&geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
-
- BKE_mesh_update_customdata_pointers(me, false);
}
else {
BKE_sculptsession_bm_to_me(ob, true);
/* Reset Face Sets as they are no longer valid. */
if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
- CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly);
+ CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, NULL, me->totpoly);
}
ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
for (int i = 0; i < me->totpoly; i++) {
@@ -223,8 +225,9 @@ static void SCULPT_dynamic_topology_disable_ex(
me->face_sets_color_default = 1;
/* Sync the visibility to vertices manually as the pmap is still not initialized. */
- for (int i = 0; i < me->totvert; i++) {
- me->mvert[i].flag &= ~ME_HIDE;
+ bool *hide_vert = (bool *)CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert");
+ if (hide_vert != NULL) {
+ memset(hide_vert, 0, sizeof(bool) * me->totvert);
}
}
@@ -269,7 +272,7 @@ void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
/* May be false in background mode. */
const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true;
if (use_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology disable");
+ SCULPT_undo_push_begin_ex(ob, "Dynamic topology disable");
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
}
SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
@@ -289,7 +292,7 @@ static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
/* May be false in background mode. */
const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true;
if (use_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology enable");
+ SCULPT_undo_push_begin_ex(ob, "Dynamic topology enable");
}
SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (use_undo) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index fbf988d63e8..4aafeacfbff 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -140,10 +140,12 @@ enum {
*/
static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss,
ExpandCache *expand_cache,
- const int v)
+ const PBVHVertRef v)
{
+ int v_i = BKE_pbvh_vertex_to_index(ss->pbvh, v);
+
for (int i = 0; i < EXPAND_SYMM_AREAS; i++) {
- if (ss->vertex_info.connected_component[v] == expand_cache->active_connected_components[i]) {
+ if (ss->vertex_info.connected_component[v_i] == expand_cache->active_connected_components[i]) {
return true;
}
}
@@ -158,7 +160,7 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss,
const int f)
{
const MLoop *loop = &ss->mloop[ss->mpoly[f].loopstart];
- return sculpt_expand_is_vert_in_active_component(ss, expand_cache, loop->v);
+ return sculpt_expand_is_vert_in_active_component(ss, expand_cache, BKE_pbvh_make_vref(loop->v));
}
/**
@@ -167,14 +169,16 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss,
*/
static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
ExpandCache *expand_cache,
- const int v)
+ const PBVHVertRef v)
{
+ int v_i = BKE_pbvh_vertex_to_index(ss->pbvh, v);
+
if (expand_cache->texture_distortion_strength == 0.0f) {
- return expand_cache->vert_falloff[v];
+ return expand_cache->vert_falloff[v_i];
}
if (!expand_cache->brush->mtex.tex) {
- return expand_cache->vert_falloff[v];
+ return expand_cache->vert_falloff[v_i];
}
float rgba[4];
@@ -184,7 +188,7 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength *
expand_cache->max_vert_falloff;
- return expand_cache->vert_falloff[v] + distortion;
+ return expand_cache->vert_falloff[v_i] + distortion;
}
/**
@@ -209,7 +213,9 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache)
* Main function to get the state of a vertex for the current state and settings of a #ExpandCache.
* Returns true when the target data should be modified by expand.
*/
-static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v)
+static bool sculpt_expand_state_get(SculptSession *ss,
+ ExpandCache *expand_cache,
+ const PBVHVertRef v)
{
if (!SCULPT_vertex_visible_get(ss, v)) {
return false;
@@ -303,7 +309,7 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_
*/
static float sculpt_expand_gradient_value_get(SculptSession *ss,
ExpandCache *expand_cache,
- const int v)
+ const PBVHVertRef v)
{
if (!expand_cache->falloff_gradient) {
return 1.0f;
@@ -345,12 +351,13 @@ static float sculpt_expand_gradient_value_get(SculptSession *ss,
static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCache *expand_cache)
{
const int totvert = SCULPT_vertex_count_get(ss);
- BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices");
+ BLI_bitmap *enabled_verts = BLI_BITMAP_NEW(totvert, "enabled verts");
for (int i = 0; i < totvert; i++) {
- const bool enabled = sculpt_expand_state_get(ss, expand_cache, i);
- BLI_BITMAP_SET(enabled_vertices, i, enabled);
+ const bool enabled = sculpt_expand_state_get(
+ ss, expand_cache, BKE_pbvh_index_to_vertex(ss->pbvh, i));
+ BLI_BITMAP_SET(enabled_verts, i, enabled);
}
- return enabled_vertices;
+ return enabled_verts;
}
/**
@@ -359,33 +366,35 @@ static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCa
* vertex that is not enabled.
*/
static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss,
- const BLI_bitmap *enabled_vertices,
+ const BLI_bitmap *enabled_verts,
const bool use_mesh_boundary)
{
const int totvert = SCULPT_vertex_count_get(ss);
- BLI_bitmap *boundary_vertices = BLI_BITMAP_NEW(totvert, "boundary vertices");
+ BLI_bitmap *boundary_verts = BLI_BITMAP_NEW(totvert, "boundary verts");
for (int i = 0; i < totvert; i++) {
- if (!BLI_BITMAP_TEST(enabled_vertices, i)) {
+ if (!BLI_BITMAP_TEST(enabled_verts, i)) {
continue;
}
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
bool is_expand_boundary = false;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
- if (!BLI_BITMAP_TEST(enabled_vertices, ni.index)) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
+ if (!BLI_BITMAP_TEST(enabled_verts, ni.index)) {
is_expand_boundary = true;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
- if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, i)) {
+ if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, vertex)) {
is_expand_boundary = true;
}
- BLI_BITMAP_SET(boundary_vertices, i, is_expand_boundary);
+ BLI_BITMAP_SET(boundary_verts, i, is_expand_boundary);
}
- return boundary_vertices;
+ return boundary_verts;
}
/* Functions implementing different algorithms for initializing falloff values. */
@@ -394,12 +403,12 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss,
* Utility function to get the closet vertex after flipping an original vertex position based on
* an symmetry pass iteration index.
*/
-static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob,
- const char symm_it,
- const int original_vertex)
+static PBVHVertRef sculpt_expand_get_vertex_index_for_symmetry_pass(
+ Object *ob, const char symm_it, const PBVHVertRef original_vertex)
{
SculptSession *ss = ob->sculpt;
- int symm_vertex = SCULPT_EXPAND_VERTEX_NONE;
+ PBVHVertRef symm_vertex = {SCULPT_EXPAND_VERTEX_NONE};
+
if (symm_it == 0) {
symm_vertex = original_vertex;
}
@@ -415,7 +424,7 @@ static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob,
* Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking
* symmetry into account.
*/
-static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int v)
+static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const PBVHVertRef v)
{
return SCULPT_geodesic_from_vertex_and_symm(sd, ob, v, FLT_MAX);
}
@@ -432,20 +441,23 @@ typedef struct ExpandFloodFillData {
} ExpandFloodFillData;
static bool expand_topology_floodfill_cb(
- SculptSession *UNUSED(ss), int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
ExpandFloodFillData *data = userdata;
if (!is_duplicate) {
- const float to_it = data->dists[from_v] + 1.0f;
- data->dists[to_v] = to_it;
+ const float to_it = data->dists[from_v_i] + 1.0f;
+ data->dists[to_v_i] = to_it;
}
else {
- data->dists[to_v] = data->dists[from_v];
+ data->dists[to_v_i] = data->dists[from_v_i];
}
return true;
}
-static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const int v)
+static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
@@ -470,23 +482,26 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons
* This creates falloff patterns that follow and snap to the hard edges of the object.
*/
static bool mask_expand_normal_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
ExpandFloodFillData *data = userdata;
if (!is_duplicate) {
float current_normal[3], prev_normal[3];
SCULPT_vertex_normal_get(ss, to_v, current_normal);
SCULPT_vertex_normal_get(ss, from_v, prev_normal);
- const float from_edge_factor = data->edge_factor[from_v];
- data->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * from_edge_factor;
- data->dists[to_v] = dot_v3v3(data->original_normal, current_normal) *
- powf(from_edge_factor, data->edge_sensitivity);
- CLAMP(data->dists[to_v], 0.0f, 1.0f);
+ const float from_edge_factor = data->edge_factor[from_v_i];
+ data->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * from_edge_factor;
+ data->dists[to_v_i] = dot_v3v3(data->original_normal, current_normal) *
+ powf(from_edge_factor, data->edge_sensitivity);
+ CLAMP(data->dists[to_v_i], 0.0f, 1.0f);
}
else {
/* PBVH_GRIDS duplicate handling. */
- data->edge_factor[to_v] = data->edge_factor[from_v];
- data->dists[to_v] = data->dists[from_v];
+ data->edge_factor[to_v_i] = data->edge_factor[from_v_i];
+ data->dists[to_v_i] = data->dists[from_v_i];
}
return true;
@@ -494,7 +509,7 @@ static bool mask_expand_normal_floodfill_cb(
static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
Object *ob,
- const int v,
+ const PBVHVertRef v,
const float edge_sensitivity)
{
SculptSession *ss = ob->sculpt;
@@ -520,9 +535,11 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
for (int repeat = 0; repeat < 2; repeat++) {
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float avg = 0.0f;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += dists[ni.index];
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -539,7 +556,7 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
* Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into
* account.
*/
-static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
+static float *sculpt_expand_spherical_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
@@ -554,11 +571,14 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
- if (symm_vertex != -1) {
+ const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
+ ob, symm_it, v);
+ if (symm_vertex.i != SCULPT_EXPAND_VERTEX_NONE) {
const float *co = SCULPT_vertex_co_get(ss, symm_vertex);
for (int i = 0; i < totvert; i++) {
- dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, i)));
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, vertex)));
}
}
}
@@ -571,13 +591,13 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
* boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it
* stays parallel to the boundary, increasing the falloff value by 1 on each step.
*/
-static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const int v)
+static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "spherical dist");
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices");
- GSQueue *queue = BLI_gsqueue_new(sizeof(int));
+ BLI_bitmap *visited_verts = BLI_BITMAP_NEW(totvert, "visited verts");
+ GSQueue *queue = BLI_gsqueue_new(sizeof(PBVHVertRef));
/* Search and initialize a boundary per symmetry pass, then mark those vertices as visited. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@@ -586,16 +606,17 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
+ const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
+ ob, symm_it, v);
SculptBoundary *boundary = SCULPT_boundary_data_init(ob, NULL, symm_vertex, FLT_MAX);
if (!boundary) {
continue;
}
- for (int i = 0; i < boundary->num_vertices; i++) {
- BLI_gsqueue_push(queue, &boundary->vertices[i]);
- BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices[i]);
+ for (int i = 0; i < boundary->verts_num; i++) {
+ BLI_gsqueue_push(queue, &boundary->verts[i]);
+ BLI_BITMAP_ENABLE(visited_verts, boundary->verts_i[i]);
}
SCULPT_boundary_data_free(boundary);
}
@@ -607,23 +628,25 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
/* Propagate the values from the boundaries to the rest of the mesh. */
while (!BLI_gsqueue_is_empty(queue)) {
- int v_next;
+ PBVHVertRef v_next;
+
BLI_gsqueue_pop(queue, &v_next);
+ int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_next, ni) {
- if (BLI_BITMAP_TEST(visited_vertices, ni.index)) {
+ if (BLI_BITMAP_TEST(visited_verts, ni.index)) {
continue;
}
- dists[ni.index] = dists[v_next] + 1.0f;
- BLI_BITMAP_ENABLE(visited_vertices, ni.index);
- BLI_gsqueue_push(queue, &ni.index);
+ dists[ni.index] = dists[v_next_i] + 1.0f;
+ BLI_BITMAP_ENABLE(visited_verts, ni.index);
+ BLI_gsqueue_push(queue, &ni.vertex);
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
BLI_gsqueue_free(queue);
- MEM_freeN(visited_vertices);
+ MEM_freeN(visited_verts);
return dists;
}
@@ -632,7 +655,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
* the base mesh faces when checking a vertex neighbor. For this reason, this is not implement
* using the general flood-fill and sculpt neighbors accessors.
*/
-static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
+static float *sculpt_expand_diagonals_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
@@ -646,18 +669,20 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
}
/* Search and mask as visited the initial vertices using the enabled symmetry passes. */
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices");
- GSQueue *queue = BLI_gsqueue_new(sizeof(int));
+ BLI_bitmap *visited_verts = BLI_BITMAP_NEW(totvert, "visited verts");
+ GSQueue *queue = BLI_gsqueue_new(sizeof(PBVHVertRef));
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char symm_it = 0; symm_it <= symm; symm_it++) {
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
+ const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
+ ob, symm_it, v);
+ int symm_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, symm_vertex);
BLI_gsqueue_push(queue, &symm_vertex);
- BLI_BITMAP_ENABLE(visited_vertices, symm_vertex);
+ BLI_BITMAP_ENABLE(visited_verts, symm_vertex_i);
}
if (BLI_gsqueue_is_empty(queue)) {
@@ -665,26 +690,28 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
}
/* Propagate the falloff increasing the value by 1 each time a new vertex is visited. */
- Mesh *mesh = ob->data;
while (!BLI_gsqueue_is_empty(queue)) {
- int v_next;
+ PBVHVertRef v_next;
BLI_gsqueue_pop(queue, &v_next);
- for (int j = 0; j < ss->pmap[v_next].count; j++) {
- MPoly *p = &ss->mpoly[ss->pmap[v_next].indices[j]];
+
+ int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next);
+
+ for (int j = 0; j < ss->pmap[v_next_i].count; j++) {
+ const MPoly *p = &ss->mpoly[ss->pmap[v_next_i].indices[j]];
for (int l = 0; l < p->totloop; l++) {
- const int neighbor_v = mesh->mloop[p->loopstart + l].v;
- if (BLI_BITMAP_TEST(visited_vertices, neighbor_v)) {
+ const PBVHVertRef neighbor_v = BKE_pbvh_make_vref(ss->mloop[p->loopstart + l].v);
+ if (BLI_BITMAP_TEST(visited_verts, neighbor_v.i)) {
continue;
}
- dists[neighbor_v] = dists[v_next] + 1.0f;
- BLI_BITMAP_ENABLE(visited_vertices, neighbor_v);
+ dists[neighbor_v.i] = dists[v_next_i] + 1.0f;
+ BLI_BITMAP_ENABLE(visited_verts, neighbor_v.i);
BLI_gsqueue_push(queue, &neighbor_v);
}
}
}
BLI_gsqueue_free(queue);
- MEM_freeN(visited_vertices);
+ MEM_freeN(visited_verts);
return dists;
}
@@ -701,11 +728,13 @@ static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss,
const int totvert = SCULPT_vertex_count_get(ss);
expand_cache->max_vert_falloff = -FLT_MAX;
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
if (expand_cache->vert_falloff[i] == FLT_MAX) {
continue;
}
- if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) {
+ if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex)) {
continue;
}
@@ -747,11 +776,11 @@ static void sculpt_expand_grids_to_faces_falloff(SculptSession *ss,
Mesh *mesh,
ExpandCache *expand_cache)
{
-
+ const MPoly *polys = BKE_mesh_polys(mesh);
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
for (int p = 0; p < mesh->totpoly; p++) {
- MPoly *poly = &mesh->mpoly[p];
+ const MPoly *poly = &polys[p];
float accum = 0.0f;
for (int l = 0; l < poly->totloop; l++) {
const int grid_loop_index = (poly->loopstart + l) * key->grid_area;
@@ -765,11 +794,14 @@ static void sculpt_expand_grids_to_faces_falloff(SculptSession *ss,
static void sculpt_expand_vertex_to_faces_falloff(Mesh *mesh, ExpandCache *expand_cache)
{
+ const MPoly *polys = BKE_mesh_polys(mesh);
+ const MLoop *loops = BKE_mesh_loops(mesh);
+
for (int p = 0; p < mesh->totpoly; p++) {
- MPoly *poly = &mesh->mpoly[p];
+ const MPoly *poly = &polys[p];
float accum = 0.0f;
for (int l = 0; l < poly->totloop; l++) {
- MLoop *loop = &mesh->mloop[l + poly->loopstart];
+ const MLoop *loop = &loops[l + poly->loopstart];
accum += expand_cache->vert_falloff[loop->v];
}
expand_cache->face_falloff[p] = accum / poly->totloop;
@@ -810,27 +842,27 @@ static void sculpt_expand_mesh_face_falloff_from_vertex_falloff(SculptSession *s
*/
static void sculpt_expand_geodesics_from_state_boundary(Object *ob,
ExpandCache *expand_cache,
- BLI_bitmap *enabled_vertices)
+ BLI_bitmap *enabled_verts)
{
SculptSession *ss = ob->sculpt;
BLI_assert(BKE_pbvh_type(ss->pbvh) == PBVH_FACES);
- GSet *initial_vertices = BLI_gset_int_new("initial_vertices");
- BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(ss, enabled_vertices, false);
+ GSet *initial_verts = BLI_gset_int_new("initial_verts");
+ BLI_bitmap *boundary_verts = sculpt_expand_boundary_from_enabled(ss, enabled_verts, false);
const int totvert = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totvert; i++) {
- if (!BLI_BITMAP_TEST(boundary_vertices, i)) {
+ if (!BLI_BITMAP_TEST(boundary_verts, i)) {
continue;
}
- BLI_gset_add(initial_vertices, POINTER_FROM_INT(i));
+ BLI_gset_add(initial_verts, POINTER_FROM_INT(i));
}
- MEM_freeN(boundary_vertices);
+ MEM_freeN(boundary_verts);
MEM_SAFE_FREE(expand_cache->vert_falloff);
MEM_SAFE_FREE(expand_cache->face_falloff);
- expand_cache->vert_falloff = SCULPT_geodesic_distances_create(ob, initial_vertices, FLT_MAX);
- BLI_gset_free(initial_vertices, NULL);
+ expand_cache->vert_falloff = SCULPT_geodesic_distances_create(ob, initial_verts, FLT_MAX);
+ BLI_gset_free(initial_verts, NULL);
}
/**
@@ -839,7 +871,7 @@ static void sculpt_expand_geodesics_from_state_boundary(Object *ob,
*/
static void sculpt_expand_topology_from_state_boundary(Object *ob,
ExpandCache *expand_cache,
- BLI_bitmap *enabled_vertices)
+ BLI_bitmap *enabled_verts)
{
MEM_SAFE_FREE(expand_cache->vert_falloff);
MEM_SAFE_FREE(expand_cache->face_falloff);
@@ -848,17 +880,19 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob,
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "topology dist");
- BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(ss, enabled_vertices, false);
+ BLI_bitmap *boundary_verts = sculpt_expand_boundary_from_enabled(ss, enabled_verts, false);
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
for (int i = 0; i < totvert; i++) {
- if (!BLI_BITMAP_TEST(boundary_vertices, i)) {
+ if (!BLI_BITMAP_TEST(boundary_verts, i)) {
continue;
}
- SCULPT_floodfill_add_and_skip_initial(&flood, i);
+
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+ SCULPT_floodfill_add_and_skip_initial(&flood, vertex);
}
- MEM_freeN(boundary_vertices);
+ MEM_freeN(boundary_verts);
ExpandFloodFillData fdata;
fdata.dists = dists;
@@ -880,7 +914,7 @@ static void sculpt_expand_resursion_step_add(Object *ob,
return;
}
- BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
+ BLI_bitmap *enabled_verts = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
/* Each time a new recursion step is created, reset the distortion strength. This is the expected
* result from the recursion, as otherwise the new falloff will render with undesired distortion
@@ -889,10 +923,10 @@ static void sculpt_expand_resursion_step_add(Object *ob,
switch (recursion_type) {
case SCULPT_EXPAND_RECURSION_GEODESICS:
- sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_vertices);
+ sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_verts);
break;
case SCULPT_EXPAND_RECURSION_TOPOLOGY:
- sculpt_expand_topology_from_state_boundary(ob, expand_cache, enabled_vertices);
+ sculpt_expand_topology_from_state_boundary(ob, expand_cache, enabled_verts);
break;
}
@@ -902,7 +936,7 @@ static void sculpt_expand_resursion_step_add(Object *ob,
sculpt_expand_update_max_face_falloff_factor(ss, expand_cache);
}
- MEM_freeN(enabled_vertices);
+ MEM_freeN(enabled_verts);
}
/* Face Set Boundary falloff. */
@@ -919,30 +953,34 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices");
+ BLI_bitmap *enabled_verts = BLI_BITMAP_NEW(totvert, "enabled verts");
for (int i = 0; i < totvert; i++) {
- if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) {
continue;
}
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) {
continue;
}
- BLI_BITMAP_ENABLE(enabled_vertices, i);
+ BLI_BITMAP_ENABLE(enabled_verts, i);
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_vertices);
+ sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_verts);
}
else {
- sculpt_expand_topology_from_state_boundary(ob, expand_cache, enabled_vertices);
+ sculpt_expand_topology_from_state_boundary(ob, expand_cache, enabled_verts);
}
- MEM_freeN(enabled_vertices);
+ MEM_freeN(enabled_verts);
if (internal_falloff) {
for (int i = 0; i < totvert; i++) {
- if (!(SCULPT_vertex_has_face_set(ss, i, active_face_set) &&
- SCULPT_vertex_has_unique_face_set(ss, i))) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!(SCULPT_vertex_has_face_set(ss, vertex, active_face_set) &&
+ SCULPT_vertex_has_unique_face_set(ss, vertex))) {
continue;
}
expand_cache->vert_falloff[i] *= -1.0f;
@@ -960,7 +998,9 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
}
else {
for (int i = 0; i < totvert; i++) {
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) {
continue;
}
expand_cache->vert_falloff[i] = 0.0f;
@@ -976,7 +1016,7 @@ static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(
ExpandCache *expand_cache,
Sculpt *sd,
Object *ob,
- const int v,
+ const PBVHVertRef v,
eSculptExpandFalloffType falloff_type)
{
MEM_SAFE_FREE(expand_cache->vert_falloff);
@@ -1046,7 +1086,7 @@ static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss,
expand_cache->snap = false;
expand_cache->invert = false;
- BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
+ BLI_bitmap *enabled_verts = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
const int totface = ss->totfaces;
for (int i = 0; i < totface; i++) {
@@ -1055,11 +1095,11 @@ static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss,
}
for (int p = 0; p < totface; p++) {
- MPoly *poly = &ss->mpoly[p];
+ const MPoly *poly = &ss->mpoly[p];
bool any_disabled = false;
for (int l = 0; l < poly->totloop; l++) {
- MLoop *loop = &ss->mloop[l + poly->loopstart];
- if (!BLI_BITMAP_TEST(enabled_vertices, loop->v)) {
+ const MLoop *loop = &ss->mloop[l + poly->loopstart];
+ if (!BLI_BITMAP_TEST(enabled_verts, loop->v)) {
any_disabled = true;
break;
}
@@ -1070,7 +1110,7 @@ static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss,
}
}
- MEM_freeN(enabled_vertices);
+ MEM_freeN(enabled_verts);
expand_cache->snap = prev_snap_state;
expand_cache->invert = prev_invert_state;
}
@@ -1128,7 +1168,7 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp
PBVHNode *node = nodes[n];
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
- SCULPT_vertex_color_set(ss, vd.index, expand_cache->original_colors[vd.index]);
+ SCULPT_vertex_color_set(ss, vd.vertex, expand_cache->original_colors[vd.index]);
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_redraw(node);
@@ -1215,12 +1255,12 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
const float initial_mask = *vd.mask;
- const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index);
+ const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex);
float new_mask;
if (enabled) {
- new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index);
+ new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex);
}
else {
new_mask = 0.0f;
@@ -1236,9 +1276,6 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
*vd.mask = clamp_f(new_mask, 0.0f, 1.0f);
any_changed = true;
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
}
BKE_pbvh_vertex_iter_end;
if (any_changed) {
@@ -1287,13 +1324,13 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
float initial_color[4];
- SCULPT_vertex_color_get(ss, vd.index, initial_color);
+ SCULPT_vertex_color_get(ss, vd.vertex, initial_color);
- const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index);
+ const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex);
float fade;
if (enabled) {
- fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index);
+ fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex);
}
else {
fade = 0.0f;
@@ -1314,12 +1351,9 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
continue;
}
- SCULPT_vertex_color_set(ss, vd.index, final_color);
+ SCULPT_vertex_color_set(ss, vd.vertex, final_color);
any_changed = true;
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
}
BKE_pbvh_vertex_iter_end;
if (any_changed) {
@@ -1364,14 +1398,18 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c
if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) {
expand_cache->original_mask = MEM_malloc_arrayN(totvert, sizeof(float), "initial mask");
for (int i = 0; i < totvert; i++) {
- expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, i);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, vertex);
}
}
if (expand_cache->target == SCULPT_EXPAND_TARGET_COLORS) {
expand_cache->original_colors = MEM_malloc_arrayN(totvert, sizeof(float[4]), "initial colors");
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_color_get(ss, i, expand_cache->original_colors[i]);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_color_get(ss, vertex, expand_cache->original_colors[i]);
}
}
}
@@ -1394,14 +1432,16 @@ static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expa
}
}
-static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int vertex)
+static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const PBVHVertRef vertex)
{
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
ExpandCache *expand_cache = ss->expand_cache;
+ int vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, vertex);
+
/* Update the active factor in the cache. */
- if (vertex == SCULPT_EXPAND_VERTEX_NONE) {
+ if (vertex.i == SCULPT_EXPAND_VERTEX_NONE) {
/* This means that the cursor is not over the mesh, so a valid active falloff can't be
* determined. In this situations, don't evaluate enabled states and default all vertices in
* connected components to enabled. */
@@ -1409,7 +1449,7 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
expand_cache->all_enabled = true;
}
else {
- expand_cache->active_falloff = expand_cache->vert_falloff[vertex];
+ expand_cache->active_falloff = expand_cache->vert_falloff[vertex_i];
expand_cache->all_enabled = false;
}
@@ -1450,14 +1490,16 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
* Updates the #SculptSession cursor data and gets the active vertex
* if the cursor is over the mesh.
*/
-static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2])
+static PBVHVertRef sculpt_expand_target_vertex_update_and_get(bContext *C,
+ Object *ob,
+ const float mval[2])
{
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) {
return SCULPT_active_vertex_get(ss);
}
- return SCULPT_EXPAND_VERTEX_NONE;
+ return BKE_pbvh_make_vref(SCULPT_EXPAND_VERTEX_NONE);
}
/**
@@ -1472,7 +1514,7 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
const bool initial_invert_state = expand_cache->invert;
expand_cache->invert = false;
- BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
+ BLI_bitmap *enabled_verts = sculpt_expand_bitmap_from_enabled(ss, expand_cache);
/* For boundary topology, position the pivot using only the boundary of the enabled vertices,
* without taking mesh boundary into account. This allows to create deformations like bending the
@@ -1480,8 +1522,8 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
const float use_mesh_boundary = expand_cache->falloff_type !=
SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY;
- BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(
- ss, enabled_vertices, use_mesh_boundary);
+ BLI_bitmap *boundary_verts = sculpt_expand_boundary_from_enabled(
+ ss, enabled_verts, use_mesh_boundary);
/* Ignore invert state, as this is the expected behavior in most cases and mask are created in
* inverted state by default. */
@@ -1493,15 +1535,17 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
const float *expand_init_co = SCULPT_vertex_co_get(ss, expand_cache->initial_active_vertex);
for (int i = 0; i < totvert; i++) {
- if (!BLI_BITMAP_TEST(boundary_vertices, i)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!BLI_BITMAP_TEST(boundary_verts, i)) {
continue;
}
- if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) {
+ if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex)) {
continue;
}
- const float *vertex_co = SCULPT_vertex_co_get(ss, i);
+ const float *vertex_co = SCULPT_vertex_co_get(ss, vertex);
if (!SCULPT_check_vertex_pivot_symmetry(vertex_co, expand_init_co, symm)) {
continue;
@@ -1511,8 +1555,8 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
total++;
}
- MEM_freeN(enabled_vertices);
- MEM_freeN(boundary_vertices);
+ MEM_freeN(enabled_verts);
+ MEM_freeN(boundary_verts);
if (total > 0) {
mul_v3_v3fl(ss->pivot_pos, avg, 1.0f / total);
@@ -1556,9 +1600,8 @@ static void sculpt_expand_finish(bContext *C)
* Finds and stores in the #ExpandCache the sculpt connected component index for each symmetry pass
* needed for expand.
*/
-static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
- ExpandCache *expand_cache,
- const int initial_vertex)
+static void sculpt_expand_find_active_connected_components_from_vert(
+ Object *ob, ExpandCache *expand_cache, const PBVHVertRef initial_vertex)
{
SculptSession *ss = ob->sculpt;
for (int i = 0; i < EXPAND_SYMM_AREAS; i++) {
@@ -1571,11 +1614,13 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
+ const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
ob, symm_it, initial_vertex);
+ int symm_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, symm_vertex);
+
expand_cache->active_connected_components[(int)symm_it] =
- ss->vertex_info.connected_component[symm_vertex];
+ ss->vertex_info.connected_component[symm_vertex_i];
}
}
@@ -1589,14 +1634,20 @@ static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
const float mval[2])
{
SculptSession *ss = ob->sculpt;
- int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval);
- if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) {
+
+ PBVHVertRef initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval);
+
+ if (initial_vertex.i == SCULPT_EXPAND_VERTEX_NONE) {
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active
* vertex in the sculpt session. */
initial_vertex = SCULPT_active_vertex_get(ss);
}
+
+ int initial_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, initial_vertex);
+
copy_v2_v2(ss->expand_cache->initial_mouse, mval);
expand_cache->initial_active_vertex = initial_vertex;
+ expand_cache->initial_active_vertex_i = initial_vertex_i;
expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss);
if (expand_cache->next_face_set == SCULPT_FACE_SET_NONE) {
@@ -1696,7 +1747,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
/* Update and get the active vertex (and face) from the cursor. */
const float mval_fl[2] = {UNPACK2(event->mval)};
- const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl);
+ const PBVHVertRef target_expand_vertex = sculpt_expand_target_vertex_update_and_get(
+ C, ob, mval_fl);
/* Handle the modal keymap state changes. */
ExpandCache *expand_cache = ss->expand_cache;
@@ -1864,10 +1916,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
/* Add new Face Sets IDs to the snapping gset if enabled. */
if (expand_cache->snap) {
const int active_face_set_id = sculpt_expand_active_face_set_id_get(ss, expand_cache);
- if (!BLI_gset_haskey(expand_cache->snap_enabled_face_sets,
- POINTER_FROM_INT(active_face_set_id))) {
- BLI_gset_add(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(active_face_set_id));
- }
+ /* The key may exist, in that case this does nothing. */
+ BLI_gset_add(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(active_face_set_id));
}
/* Update the sculpt data with the current state of the #ExpandCache. */
@@ -1890,6 +1940,8 @@ static void sculpt_expand_delete_face_set_id(int *r_face_sets,
{
const int totface = ss->totfaces;
MeshElemMap *pmap = ss->pmap;
+ const MPoly *polys = BKE_mesh_polys(mesh);
+ const MLoop *loops = BKE_mesh_loops(mesh);
/* Check that all the face sets IDs in the mesh are not equal to `delete_id`
* before attempting to delete it. */
@@ -1924,9 +1976,9 @@ static void sculpt_expand_delete_face_set_id(int *r_face_sets,
while (BLI_LINKSTACK_SIZE(queue)) {
const int f_index = POINTER_AS_INT(BLI_LINKSTACK_POP(queue));
int other_id = delete_id;
- const MPoly *c_poly = &mesh->mpoly[f_index];
+ const MPoly *c_poly = &polys[f_index];
for (int l = 0; l < c_poly->totloop; l++) {
- const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l];
+ const MLoop *c_loop = &loops[c_poly->loopstart + l];
const MeshElemMap *vert_map = &pmap[c_loop->v];
for (int i = 0; i < vert_map->count; i++) {
@@ -2076,7 +2128,7 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
sculpt_expand_ensure_sculptsession_data(ob);
/* Initialize undo. */
- SCULPT_undo_push_begin(ob, "expand");
+ SCULPT_undo_push_begin(ob, op);
sculpt_expand_undo_push(ob, ss->expand_cache);
/* Set the initial element for expand from the event position. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index ce704e619ea..64bc6188bbc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -142,7 +142,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
@@ -161,11 +161,11 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
if (fade > 0.05f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
+ SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
}
}
}
@@ -199,7 +199,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
- if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
continue;
}
@@ -210,12 +210,12 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -317,15 +317,18 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- SCULPT_undo_push_begin(ob, "face set change");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
const int next_face_set = SCULPT_face_set_next_available_get(ss);
if (mode == SCULPT_FACE_SET_MASKED) {
for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (SCULPT_vertex_mask_get(ss, vertex) >= threshold &&
+ SCULPT_vertex_visible_get(ss, vertex)) {
+ SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
}
@@ -337,7 +340,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
* sets and the performance hit of rendering the overlay. */
bool all_visible = true;
for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_visible_get(ss, i)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_visible_get(ss, vertex)) {
all_visible = false;
break;
}
@@ -351,15 +356,19 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_visible_get(ss, i)) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (SCULPT_vertex_visible_get(ss, vertex)) {
+ SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
}
if (mode == SCULPT_FACE_SET_ALL) {
for (int i = 0; i < tot_vert; i++) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
@@ -698,7 +707,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- SCULPT_undo_push_begin(ob, "face set change");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -737,7 +746,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end(ob);
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
+ SCULPT_visibility_sync_all_face_sets_to_verts(ob);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
@@ -847,7 +856,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
const int active_face_set = SCULPT_active_face_set_get(ss);
- SCULPT_undo_push_begin(ob, "Hide area");
+ SCULPT_undo_push_begin(ob, op);
PBVH *pbvh = ob->sculpt->pbvh;
PBVHNode **nodes;
@@ -869,7 +878,9 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
* be synced from face sets to non-manifold vertices. */
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_visible_get(ss, i)) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_visible_get(ss, vertex)) {
hidden_vertex = true;
break;
}
@@ -922,7 +933,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
}
/* Sync face sets visibility and vertex visibility. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
+ SCULPT_visibility_sync_all_face_sets_to_verts(ob);
SCULPT_undo_push_end(ob);
@@ -1085,13 +1096,16 @@ static void sculpt_face_set_grow(Object *ob,
const bool modify_hidden)
{
Mesh *mesh = BKE_mesh_from_object(ob);
+ const MPoly *polys = BKE_mesh_polys(mesh);
+ const MLoop *loops = BKE_mesh_loops(mesh);
+
for (int p = 0; p < mesh->totpoly; p++) {
if (!modify_hidden && prev_face_sets[p] <= 0) {
continue;
}
- const MPoly *c_poly = &mesh->mpoly[p];
+ const MPoly *c_poly = &polys[p];
for (int l = 0; l < c_poly->totloop; l++) {
- const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l];
+ const MLoop *c_loop = &loops[c_poly->loopstart + l];
const MeshElemMap *vert_map = &ss->pmap[c_loop->v];
for (int i = 0; i < vert_map->count; i++) {
const int neighbor_face_index = vert_map->indices[i];
@@ -1113,14 +1127,16 @@ static void sculpt_face_set_shrink(Object *ob,
const bool modify_hidden)
{
Mesh *mesh = BKE_mesh_from_object(ob);
+ const MPoly *polys = BKE_mesh_polys(mesh);
+ const MLoop *loops = BKE_mesh_loops(mesh);
for (int p = 0; p < mesh->totpoly; p++) {
if (!modify_hidden && prev_face_sets[p] <= 0) {
continue;
}
if (abs(prev_face_sets[p]) == active_face_set_id) {
- const MPoly *c_poly = &mesh->mpoly[p];
+ const MPoly *c_poly = &polys[p];
for (int l = 0; l < c_poly->totloop; l++) {
- const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l];
+ const MLoop *c_loop = &loops[c_poly->loopstart + l];
const MeshElemMap *vert_map = &ss->pmap[c_loop->v];
for (int i = 0; i < vert_map->count; i++) {
const int neighbor_face_index = vert_map->indices[i];
@@ -1217,19 +1233,21 @@ static void sculpt_face_set_edit_fair_face_set(Object *ob,
const int totvert = SCULPT_vertex_count_get(ss);
Mesh *mesh = ob->data;
- bool *fair_vertices = MEM_malloc_arrayN(totvert, sizeof(bool), "fair vertices");
+ bool *fair_verts = MEM_malloc_arrayN(totvert, sizeof(bool), "fair vertices");
SCULPT_boundary_info_ensure(ob);
for (int i = 0; i < totvert; i++) {
- fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, i) &&
- SCULPT_vertex_has_face_set(ss, i, active_face_set_id) &&
- SCULPT_vertex_has_unique_face_set(ss, i);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ fair_verts[i] = !SCULPT_vertex_is_boundary(ss, vertex) &&
+ SCULPT_vertex_has_face_set(ss, vertex, active_face_set_id) &&
+ SCULPT_vertex_has_unique_face_set(ss, vertex);
}
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
- BKE_mesh_prefair_and_fair_vertices(mesh, mvert, fair_vertices, fair_order);
- MEM_freeN(fair_vertices);
+ BKE_mesh_prefair_and_fair_verts(mesh, mvert, fair_verts, fair_order);
+ MEM_freeN(fair_verts);
}
static void sculpt_face_set_apply_edit(Object *ob,
@@ -1304,9 +1322,10 @@ static void sculpt_face_set_edit_modify_geometry(bContext *C,
Object *ob,
const int active_face_set,
const eSculptFaceSetEditMode mode,
- const bool modify_hidden)
+ const bool modify_hidden,
+ wmOperator *op)
{
- ED_sculpt_undo_geometry_begin(ob, "edit face set delete geometry");
+ ED_sculpt_undo_geometry_begin(ob, op);
sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden);
ED_sculpt_undo_geometry_end(ob);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -1320,7 +1339,7 @@ static void face_set_edit_do_post_visibility_updates(Object *ob, PBVHNode **node
PBVH *pbvh = ss->pbvh;
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
+ SCULPT_visibility_sync_all_face_sets_to_verts(ob);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
@@ -1336,7 +1355,8 @@ static void face_set_edit_do_post_visibility_updates(Object *ob, PBVHNode **node
static void sculpt_face_set_edit_modify_face_sets(Object *ob,
const int active_face_set,
const eSculptFaceSetEditMode mode,
- const bool modify_hidden)
+ const bool modify_hidden,
+ wmOperator *op)
{
PBVH *pbvh = ob->sculpt->pbvh;
PBVHNode **nodes;
@@ -1346,7 +1366,7 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob,
if (!nodes) {
return;
}
- SCULPT_undo_push_begin(ob, "face set edit");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden);
SCULPT_undo_push_end(ob);
@@ -1357,7 +1377,8 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob,
static void sculpt_face_set_edit_modify_coordinates(bContext *C,
Object *ob,
const int active_face_set,
- const eSculptFaceSetEditMode mode)
+ const eSculptFaceSetEditMode mode,
+ wmOperator *op)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
@@ -1365,7 +1386,7 @@ static void sculpt_face_set_edit_modify_coordinates(bContext *C,
PBVHNode **nodes;
int totnode;
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin(ob, "face set edit");
+ SCULPT_undo_push_begin(ob, op);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update(nodes[i]);
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS);
@@ -1408,15 +1429,15 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
switch (mode) {
case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY:
- sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden);
+ sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden, op);
break;
case SCULPT_FACE_SET_EDIT_GROW:
case SCULPT_FACE_SET_EDIT_SHRINK:
- sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden);
+ sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden, op);
break;
case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS:
case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY:
- sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode);
+ sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode, op);
break;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 95c01d24c6d..161fc563950 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -93,7 +93,7 @@ static void color_filter_task_cb(void *__restrict userdata,
const int mode = data->filter_type;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
@@ -104,7 +104,7 @@ static void color_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f) {
continue;
}
@@ -189,10 +189,10 @@ static void color_filter_task_cb(void *__restrict userdata,
case COLOR_FILTER_SMOOTH: {
fade = clamp_f(fade, -1.0f, 1.0f);
float smooth_color[4];
- SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
+ SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
float col[4];
- SCULPT_vertex_color_get(ss, vd.index, col);
+ SCULPT_vertex_color_get(ss, vd.vertex, col);
if (fade < 0.0f) {
interp_v4_v4v4(smooth_color, smooth_color, col, 0.5f);
@@ -224,11 +224,7 @@ static void color_filter_task_cb(void *__restrict userdata,
}
}
- SCULPT_vertex_color_set(ss, vd.index, final_color);
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
+ SCULPT_vertex_color_set(ss, vd.vertex, final_color);
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_update_color(data->nodes[n]);
@@ -244,7 +240,8 @@ static void sculpt_color_presmooth_init(SculptSession *ss)
}
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_color_get(ss, i, ss->filter_cache->pre_smoothed_color[i]);
+ SCULPT_vertex_color_get(
+ ss, BKE_pbvh_index_to_vertex(ss->pbvh, i), ss->filter_cache->pre_smoothed_color[i]);
}
for (int iteration = 0; iteration < 2; iteration++) {
@@ -253,7 +250,7 @@ static void sculpt_color_presmooth_init(SculptSession *ss)
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, BKE_pbvh_index_to_vertex(ss->pbvh, i), ni) {
float col[4] = {0};
copy_v4_v4(col, ss->filter_cache->pre_smoothed_color[ni.index]);
@@ -349,7 +346,7 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
- SCULPT_undo_push_begin(ob, "color filter");
+ SCULPT_undo_push_begin(ob, op);
BKE_sculpt_color_layer_create_if_needed(ob);
/* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index ea3f56d0859..cba1d3dcdc1 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -103,7 +103,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
switch (mode) {
case MASK_FILTER_SMOOTH:
case MASK_FILTER_SHARPEN: {
- float val = SCULPT_neighbor_mask_average(ss, vd.index);
+ float val = SCULPT_neighbor_mask_average(ss, vd.vertex);
val -= *vd.mask;
@@ -123,7 +123,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
}
case MASK_FILTER_GROW:
max = 0.0f;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
if (vmask_f > max) {
max = vmask_f;
@@ -134,7 +134,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
break;
case MASK_FILTER_SHRINK:
min = 1.0f;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
if (vmask_f < min) {
min = vmask_f;
@@ -162,9 +162,6 @@ static void mask_filter_task_cb(void *__restrict userdata,
if (*vd.mask != prev_val) {
update = true;
}
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
}
BKE_pbvh_vertex_iter_end;
@@ -196,7 +193,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
int num_verts = SCULPT_vertex_count_get(ss);
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin(ob, "Mask Filter");
+ SCULPT_undo_push_begin(ob, op);
for (int i = 0; i < totnode; i++) {
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
@@ -217,7 +214,8 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
for (int j = 0; j < num_verts; j++) {
- prev_mask[j] = SCULPT_vertex_mask_get(ss, j);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, j);
+ prev_mask[j] = SCULPT_vertex_mask_get(ss, vertex);
}
}
@@ -308,9 +306,9 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
zero_v3(avg);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) {
float normalized[3];
- sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.vertex), vd->co);
normalize_v3(normalized);
add_v3_v3(avg, normalized);
total++;
@@ -386,10 +384,6 @@ static void dirty_mask_apply_task_cb(void *__restrict userdata,
mask = fminf(mask, 0.5f) * 2.0f;
}
*vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_update_mask(node);
@@ -415,7 +409,7 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
}
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin(ob, "Dirty Mask");
+ SCULPT_undo_push_begin(ob, op);
for (int i = 0; i < totnode; i++) {
SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index dbed5624adf..e576cfda3af 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -281,7 +281,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
const eSculptMeshFilterType filter_type = data->filter_type;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
/* When using the relax face sets meshes filter,
* each 3 iterations, do a whole mesh relax to smooth the contents of the Face Set. */
@@ -296,7 +296,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) {
/* Surface Smooth can't skip the loop for this vertex as it needs to calculate its
@@ -314,7 +314,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
}
if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
- if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
continue;
}
}
@@ -322,7 +322,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
switch (filter_type) {
case MESH_FILTER_SMOOTH:
fade = clamp_f(fade, -1.0f, 1.0f);
- SCULPT_neighbor_coords_average_interior(ss, avg, vd.index);
+ SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex);
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
sub_v3_v3v3(disp, val, orig_co);
@@ -385,7 +385,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
disp,
vd.co,
ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
+ vd.vertex,
orig_data.co,
ss->filter_cache->surface_smooth_shape_preservation);
break;
@@ -399,10 +399,10 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float disp_sharpen[3] = {0.0f, 0.0f, 0.0f};
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float disp_n[3];
sub_v3_v3v3(
- disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index));
+ disp_n, SCULPT_vertex_co_get(ss, ni.vertex), SCULPT_vertex_co_get(ss, vd.vertex));
mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]);
add_v3_v3(disp_sharpen, disp_n);
}
@@ -412,7 +412,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float disp_avg[3];
float avg_co[3];
- SCULPT_neighbor_coords_average(ss, avg_co, vd.index);
+ SCULPT_neighbor_coords_average(ss, avg_co, vd.vertex);
sub_v3_v3v3(disp_avg, avg_co, vd.co);
mul_v3_v3fl(
disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index]));
@@ -457,7 +457,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
}
copy_v3_v3(vd.co, final_pos);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -473,9 +473,11 @@ static void mesh_filter_enhance_details_init_directions(SculptSession *ss)
filter_cache->detail_directions = MEM_malloc_arrayN(
totvert, sizeof(float[3]), "detail directions");
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float avg[3];
- SCULPT_neighbor_coords_average(ss, avg, i);
- sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
+ SCULPT_neighbor_coords_average(ss, avg, vertex);
+ sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
}
}
@@ -500,7 +502,9 @@ static void mesh_filter_init_limit_surface_co(SculptSession *ss)
filter_cache->limit_surface_co = MEM_malloc_arrayN(
totvert, sizeof(float[3]), "limit surface co");
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_limit_surface_get(ss, vertex, filter_cache->limit_surface_co[i]);
}
}
@@ -520,9 +524,11 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
totvert, sizeof(float[3]), "sharpen detail direction");
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float avg[3];
- SCULPT_neighbor_coords_average(ss, avg, i);
- sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
+ SCULPT_neighbor_coords_average(ss, avg, vertex);
+ sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
filter_cache->sharpen_factor[i] = len_v3(filter_cache->detail_directions[i]);
}
@@ -544,12 +550,14 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
smooth_iterations < filter_cache->sharpen_curvature_smooth_iterations;
smooth_iterations++) {
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float direction_avg[3] = {0.0f, 0.0f, 0.0f};
float sharpen_avg = 0;
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
add_v3_v3(direction_avg, filter_cache->detail_directions[ni.index]);
sharpen_avg += filter_cache->sharpen_factor[ni.index];
total++;
@@ -576,7 +584,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f) {
continue;
}
@@ -584,7 +592,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
SCULPT_surface_smooth_displace_step(ss,
vd.co,
ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
+ vd.vertex,
ss->filter_cache->surface_smooth_current_vertex,
clamp_f(fade, 0.0f, 1.0f));
}
@@ -686,7 +694,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
SCULPT_boundary_info_ensure(ob);
}
- SCULPT_undo_push_begin(ob, "Mesh Filter");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c
index 1beb5d48961..a5885092ee3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_geodesic.c
+++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c
@@ -37,7 +37,6 @@
#include "DEG_depsgraph.h"
#include "WM_api.h"
-#include "WM_message.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
@@ -62,9 +61,9 @@
/* Propagate distance from v1 and v2 to v0. */
static bool sculpt_geodesic_mesh_test_dist_add(
- MVert *mvert, const int v0, const int v1, const int v2, float *dists, GSet *initial_vertices)
+ MVert *mvert, const int v0, const int v1, const int v2, float *dists, GSet *initial_verts)
{
- if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(v0))) {
+ if (BLI_gset_haskey(initial_verts, POINTER_FROM_INT(v0))) {
return false;
}
@@ -97,7 +96,7 @@ static bool sculpt_geodesic_mesh_test_dist_add(
}
static float *SCULPT_geodesic_mesh_create(Object *ob,
- GSet *initial_vertices,
+ GSet *initial_verts,
const float limit_radius)
{
SculptSession *ss = ob->sculpt;
@@ -108,8 +107,10 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
const float limit_radius_sq = limit_radius * limit_radius;
- MEdge *edges = mesh->medge;
MVert *verts = SCULPT_mesh_deformed_mverts_get(ss);
+ const MEdge *edges = BKE_mesh_edges(mesh);
+ const MPoly *polys = BKE_mesh_polys(mesh);
+ const MLoop *loops = BKE_mesh_loops(mesh);
float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances");
BLI_bitmap *edge_tag = BLI_BITMAP_NEW(totedge, "edge tag");
@@ -117,16 +118,15 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
if (!ss->epmap) {
BKE_mesh_edge_poly_map_create(&ss->epmap,
&ss->epmap_mem,
- mesh->medge,
+ edges,
mesh->totedge,
- mesh->mpoly,
+ polys,
mesh->totpoly,
- mesh->mloop,
+ loops,
mesh->totloop);
}
if (!ss->vemap) {
- BKE_mesh_vert_edge_map_create(
- &ss->vemap, &ss->vemap_mem, mesh->medge, mesh->totvert, mesh->totedge);
+ BKE_mesh_vert_edge_map_create(&ss->vemap, &ss->vemap_mem, edges, mesh->totvert, mesh->totedge);
}
/* Both contain edge indices encoded as *void. */
@@ -137,7 +137,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
BLI_LINKSTACK_INIT(queue_next);
for (int i = 0; i < totvert; i++) {
- if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(i))) {
+ if (BLI_gset_haskey(initial_verts, POINTER_FROM_INT(i))) {
dists[i] = 0.0f;
}
else {
@@ -159,7 +159,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
/* This is an O(n^2) loop used to limit the geodesic distance calculation to a radius. When
* this optimization is needed, it is expected for the tool to request the distance to a low
* number of vertices (usually just 1 or 2). */
- GSET_ITER (gs_iter, initial_vertices) {
+ GSET_ITER (gs_iter, initial_verts) {
const int v = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
float *v_co = verts[v].co;
for (int i = 0; i < totvert; i++) {
@@ -193,7 +193,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
SWAP(int, v1, v2);
}
sculpt_geodesic_mesh_test_dist_add(
- verts, v2, v1, SCULPT_GEODESIC_VERTEX_NONE, dists, initial_vertices);
+ verts, v2, v1, SCULPT_GEODESIC_VERTEX_NONE, dists, initial_verts);
}
if (ss->epmap[e].count != 0) {
@@ -202,16 +202,15 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
if (ss->face_sets[poly] <= 0) {
continue;
}
- const MPoly *mpoly = &mesh->mpoly[poly];
+ const MPoly *mpoly = &polys[poly];
for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
- const MLoop *mloop = &mesh->mloop[loop_index + mpoly->loopstart];
+ const MLoop *mloop = &loops[loop_index + mpoly->loopstart];
const int v_other = mloop->v;
if (ELEM(v_other, v1, v2)) {
continue;
}
- if (sculpt_geodesic_mesh_test_dist_add(
- verts, v_other, v1, v2, dists, initial_vertices)) {
+ if (sculpt_geodesic_mesh_test_dist_add(verts, v_other, v1, v2, dists, initial_verts)) {
for (int edge_map_index = 0; edge_map_index < ss->vemap[v_other].count;
edge_map_index++) {
const int e_other = ss->vemap[v_other].indices[edge_map_index];
@@ -258,7 +257,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
/* For sculpt mesh data that does not support a geodesic distances algorithm, fallback to the
* distance to each vertex. In this case, only one of the initial vertices will be used to
* calculate the distance. */
-static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices)
+static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_verts)
{
SculptSession *ss = ob->sculpt;
@@ -267,7 +266,7 @@ static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices
float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances");
int first_affected = SCULPT_GEODESIC_VERTEX_NONE;
GSetIterator gs_iter;
- GSET_ITER (gs_iter, initial_vertices) {
+ GSET_ITER (gs_iter, initial_verts) {
first_affected = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
break;
}
@@ -279,25 +278,26 @@ static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices
return dists;
}
- const float *first_affected_co = SCULPT_vertex_co_get(ss, first_affected);
+ const float *first_affected_co = SCULPT_vertex_co_get(
+ ss, BKE_pbvh_index_to_vertex(ss->pbvh, first_affected));
for (int i = 0; i < totvert; i++) {
- dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, i));
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, vertex));
}
return dists;
}
-float *SCULPT_geodesic_distances_create(Object *ob,
- GSet *initial_vertices,
- const float limit_radius)
+float *SCULPT_geodesic_distances_create(Object *ob, GSet *initial_verts, const float limit_radius)
{
SculptSession *ss = ob->sculpt;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return SCULPT_geodesic_mesh_create(ob, initial_vertices, limit_radius);
+ return SCULPT_geodesic_mesh_create(ob, initial_verts, limit_radius);
case PBVH_BMESH:
case PBVH_GRIDS:
- return SCULPT_geodesic_fallback_create(ob, initial_vertices);
+ return SCULPT_geodesic_fallback_create(ob, initial_verts);
}
BLI_assert(false);
return NULL;
@@ -305,16 +305,17 @@ float *SCULPT_geodesic_distances_create(Object *ob,
float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd,
Object *ob,
- const int vertex,
+ const PBVHVertRef vertex,
const float limit_radius)
{
SculptSession *ss = ob->sculpt;
- GSet *initial_vertices = BLI_gset_int_new("initial_vertices");
+ GSet *initial_verts = BLI_gset_int_new("initial_verts");
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char i = 0; i <= symm; ++i) {
if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
- int v = -1;
+ PBVHVertRef v = {PBVH_REF_NONE};
+
if (i == 0) {
v = vertex;
}
@@ -323,22 +324,23 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd,
flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i);
v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
}
- if (v != -1) {
- BLI_gset_add(initial_vertices, POINTER_FROM_INT(v));
+ if (v.i != PBVH_REF_NONE) {
+ BLI_gset_add(initial_verts, POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ss->pbvh, v)));
}
}
}
- float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius);
- BLI_gset_free(initial_vertices, NULL);
+ float *dists = SCULPT_geodesic_distances_create(ob, initial_verts, limit_radius);
+ BLI_gset_free(initial_verts, NULL);
return dists;
}
-float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius)
+float *SCULPT_geodesic_from_vertex(Object *ob, const PBVHVertRef vertex, const float limit_radius)
{
- GSet *initial_vertices = BLI_gset_int_new("initial_vertices");
- BLI_gset_add(initial_vertices, POINTER_FROM_INT(vertex));
- float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius);
- BLI_gset_free(initial_vertices, NULL);
+ GSet *initial_verts = BLI_gset_int_new("initial_verts");
+ BLI_gset_add(initial_verts,
+ POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ob->sculpt->pbvh, vertex)));
+ float *dists = SCULPT_geodesic_distances_create(ob, initial_verts, limit_radius);
+ BLI_gset_free(initial_verts, NULL);
return dists;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 0693b445fe5..4bc06d68a02 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -59,10 +59,13 @@ typedef struct SculptCursorGeometryInfo {
typedef struct SculptVertexNeighborIter {
/* Storage */
- int *neighbors;
+ PBVHVertRef *neighbors;
+ int *neighbor_indices;
int size;
int capacity;
- int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+
+ PBVHVertRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+ int neighbor_indices_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
/* Internal iterator. */
int num_duplicates;
@@ -70,6 +73,7 @@ typedef struct SculptVertexNeighborIter {
/* Public */
int index;
+ PBVHVertRef vertex;
bool is_duplicate;
} SculptVertexNeighborIter;
@@ -93,7 +97,7 @@ typedef struct {
/* Flood Fill. */
typedef struct {
GSQueue *queue;
- BLI_bitmap *visited_vertices;
+ BLI_bitmap *visited_verts;
} SculptFloodFill;
typedef enum eBoundaryAutomaskMode {
@@ -247,7 +251,7 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
- /* When true, the displacement stored in the proxies will be aplied to the original coordinates
+ /* When true, the displacement stored in the proxies will be applied to the original coordinates
* instead of to the current coordinates. */
bool use_proxies_orco;
@@ -318,7 +322,7 @@ typedef struct SculptThreadedTaskData {
bool mask_by_color_preserve_mask;
/* Index of the vertex that is going to be used as a reference for the colors. */
- int mask_by_color_vertex;
+ PBVHVertRef mask_by_color_vertex;
float *mask_by_color_floodfill;
int face_set;
@@ -485,6 +489,7 @@ typedef struct StrokeCache {
float true_last_location[3];
float location[3];
float last_location[3];
+ float stroke_distance;
/* Used for alternating between deformation in brushes that need to apply different ones to
* achieve certain effects. */
@@ -690,7 +695,8 @@ typedef struct ExpandCache {
* during the execution of Expand by moving the origin. */
float initial_mouse_move[2];
float initial_mouse[2];
- int initial_active_vertex;
+ PBVHVertRef initial_active_vertex;
+ int initial_active_vertex_i;
int initial_active_face_set;
/* Maximum number of vertices allowed in the SculptSession for previewing the falloff using
@@ -845,7 +851,10 @@ void SCULPT_tag_update_overlays(bContext *C);
* (This allows us to ignore the GL depth buffer)
* Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
*/
-bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+bool SCULPT_stroke_get_location(struct bContext *C,
+ float out[3],
+ const float mouse[2],
+ bool force_original);
/**
* Gets the normal, location and active vertex location of the geometry under the cursor. This also
* updates the active vertex and cursor related data of the SculptSession using the mouse position
@@ -858,7 +867,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss,
void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
float SCULPT_raycast_init(struct ViewContext *vc,
- const float mouse[2],
+ const float mval[2],
float ray_start[3],
float ray_end[3],
float ray_normal[3],
@@ -895,14 +904,14 @@ bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cach
void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
-const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
+const float *SCULPT_vertex_co_get(struct SculptSession *ss, PBVHVertRef vertex);
/** Get the normal for a given sculpt vertex; do not modify the result */
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
+void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]);
-float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
-void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4]);
-void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4]);
+float SCULPT_vertex_mask_get(struct SculptSession *ss, PBVHVertRef vertex);
+void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]);
+void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]);
/** Returns true if a color attribute exists in the current sculpt session. */
bool SCULPT_has_colors(const SculptSession *ss);
@@ -910,19 +919,19 @@ bool SCULPT_has_colors(const SculptSession *ss);
/** Returns true if the active color attribute is on loop (ATTR_DOMAIN_CORNER) domain. */
bool SCULPT_has_loop_colors(const struct Object *ob);
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex);
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]);
/**
* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
*/
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, PBVHVertRef vertex);
/**
* Returns the info of the limit surface when multi-res is available,
* otherwise it returns the current coordinate of the vertex.
*/
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, float r_co[3]);
/**
* Returns the pointer to the coordinates that should be edited from a brush tool iterator
@@ -933,7 +942,7 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
PBVHVertexIter *iter);
void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
- int index,
+ PBVHVertRef vertex,
bool include_duplicates,
SculptVertexNeighborIter *iter);
@@ -942,7 +951,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
+ neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i];
/** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
@@ -950,7 +960,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \
neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
@@ -961,7 +972,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
} \
((void)0)
-int SCULPT_active_vertex_get(SculptSession *ss);
+PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss);
const float *SCULPT_active_vertex_co_get(SculptSession *ss);
void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
@@ -981,7 +992,7 @@ void SCULPT_fake_neighbors_free(struct Object *ob);
/* Vertex Info. */
void SCULPT_boundary_info_ensure(Object *object);
/* Boundary Info needs to be initialized in order to use this function. */
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index);
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, PBVHVertRef vertex);
void SCULPT_connected_components_ensure(Object *ob);
@@ -991,10 +1002,10 @@ void SCULPT_connected_components_ensure(Object *ob);
/** \name Sculpt Visibility API
* \{ */
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex);
-void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
+void SCULPT_visibility_sync_all_face_sets_to_verts(struct Object *ob);
void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
/** \} */
@@ -1004,17 +1015,17 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
* \{ */
int SCULPT_active_face_set_get(SculptSession *ss);
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex);
+void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set);
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex);
int SCULPT_face_set_next_available_get(SculptSession *ss);
void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex);
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
@@ -1029,7 +1040,10 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
* Initialize a #SculptOrigVertData for accessing original vertex data;
* handles #BMesh, #Mesh, and multi-resolution.
*/
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node,
+ SculptUndoType type);
/**
* Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
*/
@@ -1097,11 +1111,11 @@ void SCULPT_calc_area_normal_and_center(
void SCULPT_calc_area_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]);
-int SCULPT_nearest_vertex_get(struct Sculpt *sd,
- struct Object *ob,
- const float co[3],
- float max_distance,
- bool use_original);
+PBVHVertRef SCULPT_nearest_vertex_get(struct Sculpt *sd,
+ struct Object *ob,
+ const float co[3],
+ float max_distance,
+ bool use_original);
int SCULPT_plane_point_side(const float co[3], const float plane[4]);
int SCULPT_plane_trim(const struct StrokeCache *cache,
@@ -1180,7 +1194,7 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const float vno[3],
const float fno[3],
float mask,
- int vertex_index,
+ const PBVHVertRef vertex,
int thread_id);
/**
@@ -1211,15 +1225,18 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
struct Object *ob,
struct SculptSession *ss,
SculptFloodFill *flood,
- int index,
+ PBVHVertRef vertex,
float radius);
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_execute(
- struct SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, PBVHVertRef vertex);
+void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex);
+void SCULPT_floodfill_execute(struct SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ PBVHVertRef from_v,
+ PBVHVertRef to_v,
+ bool is_duplicate,
+ void *userdata),
+ void *userdata);
void SCULPT_floodfill_free(SculptFloodFill *flood);
/** \} */
@@ -1269,7 +1286,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
SculptSession *ss,
- int vert);
+ PBVHVertRef vertex);
/* Returns the automasking cache depending on the active tool. Used for code that can run both for
* brushes and filter. */
@@ -1302,9 +1319,9 @@ float *SCULPT_geodesic_distances_create(struct Object *ob,
float limit_radius);
float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
struct Object *ob,
- int vertex,
+ PBVHVertRef vertex,
float limit_radius);
-float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius);
+float *SCULPT_geodesic_from_vertex(Object *ob, PBVHVertRef vertex, float limit_radius);
/** \} */
/* -------------------------------------------------------------------- */
@@ -1338,7 +1355,7 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
/* Public functions. */
-struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss,
+struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct Object *ob,
float cloth_mass,
float cloth_damping,
float cloth_softbody_strength,
@@ -1410,14 +1427,16 @@ BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
*/
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex);
+float SCULPT_neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex);
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex);
/**
* Mask the mesh boundaries smoothing only the mesh surface without using auto-masking.
*/
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
+ float result[3],
+ PBVHVertRef vertex);
void SCULPT_smooth(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask);
@@ -1429,11 +1448,15 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float *disp,
const float co[3],
float (*laplacian_disp)[3],
- int v_index,
+ PBVHVertRef vertex,
const float origco[3],
float alpha);
-void SCULPT_surface_smooth_displace_step(
- SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade);
+void SCULPT_surface_smooth_displace_step(SculptSession *ss,
+ float *co,
+ float (*laplacian_disp)[3],
+ PBVHVertRef vertex,
+ float beta,
+ float fade);
void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
/* Slide/Relax */
@@ -1467,14 +1490,21 @@ void SCULPT_cache_free(StrokeCache *cache);
* \{ */
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_first_node(void);
/**
- * NOTE: `name` must match operator name for
- * redo panels to work.
+ * Pushes an undo step using the operator name. This is necessary for
+ * redo panels to work; operators that do not support that may use
+ * #SCULPT_undo_push_begin_ex instead if so desired.
*/
-void SCULPT_undo_push_begin(struct Object *ob, const char *name);
+void SCULPT_undo_push_begin(struct Object *ob, const struct wmOperator *op);
+
+/**
+ * NOTE: #SCULPT_undo_push_begin is preferred since `name`
+ * must match operator name for redo panels to work.
+ */
+void SCULPT_undo_push_begin_ex(struct Object *ob, const char *name);
void SCULPT_undo_push_end(struct Object *ob);
void SCULPT_undo_push_end_ex(struct Object *ob, const bool use_nested_undo);
@@ -1639,7 +1669,7 @@ void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
*/
struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
- int initial_vertex,
+ PBVHVertRef initial_vertex,
float radius);
void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
/* Main Brush Function. */
@@ -1802,7 +1832,10 @@ void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
/* end sculpt_ops.c */
-#define SCULPT_TOOL_NEEDS_COLOR(tool) ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)
+BLI_INLINE bool SCULPT_tool_is_paint(int tool)
+{
+ return ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR);
+}
#ifdef __cplusplus
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 4593c6a8b60..9556d24f12c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -97,11 +97,14 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
int update_it = data->mask_expand_update_it;
+ PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
+ int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
int vi = vd.index;
float final_mask = *vd.mask;
if (data->mask_expand_use_normals) {
- if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] <
+ if (ss->filter_cache->normal_factor[active_vertex_i] <
ss->filter_cache->normal_factor[vd.index]) {
final_mask = 1.0f;
}
@@ -121,7 +124,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
if (data->mask_expand_create_face_set) {
if (final_mask == 1.0f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set);
+ SCULPT_vertex_face_set_set(ss, vd.vertex, ss->filter_cache->new_face_set);
}
BKE_pbvh_node_mark_redraw(node);
}
@@ -136,9 +139,6 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
}
if (*vd.mask != final_mask) {
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
*vd.mask = final_mask;
BKE_pbvh_node_mark_update_mask(node);
}
@@ -167,10 +167,13 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
if (RNA_boolean_get(op->ptr, "use_cursor")) {
SculptCursorGeometryInfo sgi;
+
const float mval_fl[2] = {UNPACK2(event->mval)};
if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
+ int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, SCULPT_active_vertex_get(ss));
+
/* The cursor is over the mesh, get the update iteration from the updated active vertex. */
- mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
+ mask_expand_update_it = ss->filter_cache->mask_update_it[active_vertex_i];
}
else {
/* When the cursor is outside the mesh, affect the entire connected component. */
@@ -291,13 +294,16 @@ typedef struct MaskExpandFloodFillData {
} MaskExpandFloodFillData;
static bool mask_expand_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
MaskExpandFloodFillData *data = userdata;
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
if (!is_duplicate) {
- int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
- ss->filter_cache->mask_update_it[to_v] = to_it;
+ int to_it = ss->filter_cache->mask_update_it[from_v_i] + 1;
+ ss->filter_cache->mask_update_it[to_v_i] = to_it;
if (to_it > ss->filter_cache->mask_update_last_it) {
ss->filter_cache->mask_update_last_it = to_it;
}
@@ -306,20 +312,20 @@ static bool mask_expand_floodfill_cb(
float current_normal[3], prev_normal[3];
SCULPT_vertex_normal_get(ss, to_v, current_normal);
SCULPT_vertex_normal_get(ss, from_v, prev_normal);
- const float from_edge_factor = ss->filter_cache->edge_factor[from_v];
- ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
- from_edge_factor;
- ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) *
- powf(from_edge_factor, data->edge_sensitivity);
- CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f);
+ const float from_edge_factor = ss->filter_cache->edge_factor[from_v_i];
+ ss->filter_cache->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) *
+ from_edge_factor;
+ ss->filter_cache->normal_factor[to_v_i] = dot_v3v3(data->original_normal, current_normal) *
+ powf(from_edge_factor, data->edge_sensitivity);
+ CLAMP(ss->filter_cache->normal_factor[to_v_i], 0.0f, 1.0f);
}
}
else {
/* PBVH_GRIDS duplicate handling. */
- ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
+ ss->filter_cache->mask_update_it[to_v_i] = ss->filter_cache->mask_update_it[from_v_i];
if (data->use_normals) {
- ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v];
- ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v];
+ ss->filter_cache->edge_factor[to_v_i] = ss->filter_cache->edge_factor[from_v_i];
+ ss->filter_cache->normal_factor[to_v_i] = ss->filter_cache->normal_factor[from_v_i];
}
}
@@ -355,7 +361,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
- SCULPT_undo_push_begin(ob, "Mask Expand");
+ SCULPT_undo_push_begin(ob, op);
if (create_face_set) {
SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS);
@@ -392,13 +398,17 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
else {
ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
for (int i = 0; i < vertex_count; i++) {
- ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, vertex);
}
}
+ int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, SCULPT_active_vertex_get(ss));
+
ss->filter_cache->mask_update_last_it = 1;
ss->filter_cache->mask_update_current_it = 1;
- ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0;
+ ss->filter_cache->mask_update_it[active_vertex_i] = 0;
copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
@@ -417,9 +427,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_normals) {
for (int repeat = 0; repeat < 2; repeat++) {
for (int i = 0; i < vertex_count; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float avg = 0.0f;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += ss->filter_cache->normal_factor[ni.index];
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
index 025f34ab2d7..b9b889ab2ce 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c
@@ -99,7 +99,7 @@ static void mask_init_task_cb(void *__restrict userdata,
*vd.mask = BLI_hash_int_01(vd.index + seed);
break;
case SCULPT_MASK_INIT_RANDOM_PER_FACE_SET: {
- const int face_set = SCULPT_vertex_face_set_get(ss, vd.index);
+ const int face_set = SCULPT_vertex_face_set_get(ss, vd.vertex);
*vd.mask = BLI_hash_int_01(face_set + seed);
break;
}
@@ -131,7 +131,7 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- SCULPT_undo_push_begin(ob, "init mask");
+ SCULPT_undo_push_begin(ob, op);
if (mode == SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART) {
SCULPT_connected_components_ensure(ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index ddc1a0e1db0..1e8731e54c0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -86,7 +86,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
/* Sample the normal and area of the +X and -X axis individually. */
@@ -194,13 +194,13 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index f16763be735..10a2ece73de 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -47,6 +47,7 @@
#include "BKE_image.h"
#include "BKE_kelvinlet.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -129,8 +130,10 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
"layer persistent base");
for (int i = 0; i < totvert; i++) {
- copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
- SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, vertex));
+ SCULPT_vertex_normal_get(ss, vertex, ss->persistent_base[i].no);
ss->persistent_base[i].disp = 0.0f;
}
@@ -213,7 +216,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
* as deleted, then after symmetrize operation all BMesh elements
* are logged as added (as opposed to attempting to store just the
* parts that symmetrize modifies). */
- SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
+ SCULPT_undo_push_begin(ob, op);
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
BM_log_before_all_removed(ss->bm, ss->bm_log);
@@ -240,7 +243,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
break;
case PBVH_FACES:
/* Mesh Symmetrize. */
- ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
+ ED_sculpt_undo_geometry_begin(ob, op);
Mesh *mesh = ob->data;
BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
@@ -392,7 +395,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
bool has_undo = wm->undo_stack != NULL;
/* Undo push is needed to prevent memory leak. */
if (has_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology enable");
+ SCULPT_undo_push_begin_ex(ob, "Dynamic topology enable");
}
SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (has_undo) {
@@ -416,7 +419,7 @@ void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, Report
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
}
@@ -468,7 +471,7 @@ void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
}
@@ -480,7 +483,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
const int mode_flag = OB_MODE_SCULPT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
@@ -508,7 +511,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
* while it works it causes lag when undoing the first undo step, see T71564. */
wmWindowManager *wm = CTX_wm_manager(C);
if (wm->op_undo_depth <= 1) {
- SCULPT_undo_push_begin(ob, op->type->name);
+ SCULPT_undo_push_begin(ob, op);
SCULPT_undo_push_end(ob);
}
}
@@ -543,7 +546,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
- ss->preview_vert_index_count = 0;
+ ss->preview_vert_count = 0;
int totpoints = 0;
/* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
@@ -568,193 +571,50 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
float brush_co[3];
copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
+ BLI_bitmap *visited_verts = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_verts");
/* Assuming an average of 6 edges per vertex in a triangulated mesh. */
- const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
+ const int max_preview_verts = SCULPT_vertex_count_get(ss) * 3 * 2;
- if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ if (ss->preview_vert_list == NULL) {
+ ss->preview_vert_list = MEM_callocN(max_preview_verts * sizeof(PBVHVertRef), "preview lines");
}
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
- BLI_gsqueue_push(not_visited_vertices, &active_v);
+ GSQueue *non_visited_verts = BLI_gsqueue_new(sizeof(PBVHVertRef));
+ PBVHVertRef active_v = SCULPT_active_vertex_get(ss);
+ BLI_gsqueue_push(non_visited_verts, &active_v);
+
+ while (!BLI_gsqueue_is_empty(non_visited_verts)) {
+ PBVHVertRef from_v;
- while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
- int from_v;
- BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ BLI_gsqueue_pop(non_visited_verts, &from_v);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
- ss->preview_vert_index_list[totpoints] = from_v;
+ if (totpoints + (ni.size * 2) < max_preview_verts) {
+ PBVHVertRef to_v = ni.vertex;
+ int to_v_i = ni.index;
+ ss->preview_vert_list[totpoints] = from_v;
totpoints++;
- ss->preview_vert_index_list[totpoints] = to_v;
+ ss->preview_vert_list[totpoints] = to_v;
totpoints++;
- if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ if (BLI_BITMAP_TEST(visited_verts, to_v_i)) {
continue;
}
- BLI_BITMAP_ENABLE(visited_vertices, to_v);
+ BLI_BITMAP_ENABLE(visited_verts, to_v_i);
const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
if (len_squared_v3v3(brush_co, co) < radius * radius) {
- BLI_gsqueue_push(not_visited_vertices, &to_v);
+ BLI_gsqueue_push(non_visited_verts, &to_v);
}
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
- BLI_gsqueue_free(not_visited_vertices);
+ BLI_gsqueue_free(non_visited_verts);
- MEM_freeN(visited_vertices);
+ MEM_freeN(visited_verts);
- ss->preview_vert_index_count = totpoints;
-}
-
-static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data == NULL || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- const MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- const MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- const MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- const MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- const MLoop *c_loop = &loops[c_poly->loopstart + j];
- float srgb_color[4];
- linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
- loopcols[loop_index].r = (char)(srgb_color[0] * 255);
- loopcols[loop_index].g = (char)(srgb_color[1] * 255);
- loopcols[loop_index].b = (char)(srgb_color[2] * 255);
- loopcols[loop_index].a = (char)(srgb_color[3] * 255);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static bool sculpt_colors_poll(bContext *C)
-{
- if (!SCULPT_mode_poll(C)) {
- return false;
- }
-
- Object *ob = CTX_data_active_object(C);
-
- if (!ob->sculpt || !ob->sculpt->pbvh || BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
- return false;
- }
-
- return SCULPT_has_colors(ob->sculpt);
-}
-
-static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sculpt Vertex Color to Vertex Color";
- ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
- ot->idname = "SCULPT_OT_vertex_to_loop_colors";
-
- /* api callbacks */
- ot->poll = sculpt_colors_poll;
- ot->exec = vertex_to_loop_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data == NULL || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- const MLoopCol *loopcols = CustomData_get_layer_n(
- &mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- const MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- const MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- const MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- const MLoop *c_loop = &loops[c_poly->loopstart + j];
- vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
- vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
- vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
- vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
- srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color to Sculpt Vertex Color";
- ot->description = "Copy the active loop color layer to the vertex color";
- ot->idname = "SCULPT_OT_loop_to_vertex_colors";
-
- /* api callbacks */
- ot->poll = sculpt_colors_poll;
- ot->exec = loop_to_vertex_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ss->preview_vert_count = totpoints;
}
static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
@@ -764,7 +624,7 @@ static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent
Object *ob = CTX_data_active_object(C);
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
+ PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
float active_vertex_color[4];
if (!SCULPT_handles_colors_report(ss, op->reports)) {
@@ -882,9 +742,6 @@ static void do_mask_by_color_contiguous_update_nodes_cb(
continue;
}
update_node = true;
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
}
BKE_pbvh_vertex_iter_end;
if (update_node) {
@@ -893,8 +750,11 @@ static void do_mask_by_color_contiguous_update_nodes_cb(
}
static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
MaskByColorContiguousFloodFillData *data = userdata;
float current_color[4];
@@ -902,10 +762,10 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb(
float new_vertex_mask = sculpt_mask_by_color_delta_get(
current_color, data->initial_color, data->threshold, data->invert);
- data->new_mask[to_v] = new_vertex_mask;
+ data->new_mask[to_v_i] = new_vertex_mask;
if (is_duplicate) {
- data->new_mask[to_v] = data->new_mask[from_v];
+ data->new_mask[to_v_i] = data->new_mask[from_v_i];
}
float len = len_v3v3(current_color, data->initial_color);
@@ -914,7 +774,7 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb(
}
static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
+ const PBVHVertRef vertex,
const float threshold,
const bool invert,
const bool preserve_mask)
@@ -991,7 +851,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float col[4];
- SCULPT_vertex_color_get(ss, vd.index, col);
+ SCULPT_vertex_color_get(ss, vd.vertex, col);
const float current_mask = *vd.mask;
const float new_mask = sculpt_mask_by_color_delta_get(active_color, col, threshold, invert);
@@ -1001,18 +861,15 @@ static void do_mask_by_color_task_cb(void *__restrict userdata,
continue;
}
update_node = true;
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
}
BKE_pbvh_vertex_iter_end;
if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
}
}
static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
+ const PBVHVertRef vertex,
const float threshold,
const bool invert,
const bool preserve_mask)
@@ -1064,10 +921,10 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
- SCULPT_undo_push_begin(ob, "Mask by color");
+ SCULPT_undo_push_begin(ob, op);
BKE_sculpt_color_layer_create_if_needed(ob);
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool invert = RNA_boolean_get(op->ptr, "invert");
const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
@@ -1156,8 +1013,6 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_project_line_gesture);
WM_operatortype_append(SCULPT_OT_sample_color);
- WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
- WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
WM_operatortype_append(SCULPT_OT_color_filter);
WM_operatortype_append(SCULPT_OT_mask_by_color);
WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index fa9f24377da..c494c71f1eb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -17,6 +17,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_brush.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
@@ -80,20 +81,16 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float smooth_color[4];
- SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
+ SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
float col[4];
- SCULPT_vertex_color_get(ss, vd.index, col);
+ SCULPT_vertex_color_get(ss, vd.vertex, col);
blend_color_interpolate_float(col, col, smooth_color, fade);
- SCULPT_vertex_color_set(ss, vd.index, col);
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
+ SCULPT_vertex_color_set(ss, vd.vertex, col);
}
BKE_pbvh_vertex_iter_end;
}
@@ -111,7 +108,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
PBVHColorBufferNode *color_buffer;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
color_buffer = BKE_pbvh_node_color_buffer_get(data->nodes[n]);
@@ -121,11 +118,31 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
float brush_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
copy_v3_v3(brush_color,
ss->cache->invert ? BKE_brush_secondary_color_get(ss->scene, brush) :
BKE_brush_color_get(ss->scene, brush));
+
IMB_colormanagement_srgb_to_scene_linear_v3(brush_color, brush_color);
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ switch (brush->gradient_stroke_mode) {
+ case BRUSH_GRADIENT_PRESSURE:
+ BKE_colorband_evaluate(brush->gradient, ss->cache->pressure, brush_color);
+ break;
+ case BRUSH_GRADIENT_SPACING_REPEAT: {
+ float coord = fmod(ss->cache->stroke_distance / brush->gradient_spacing, 1.0);
+ BKE_colorband_evaluate(brush->gradient, coord, brush_color);
+ break;
+ }
+ case BRUSH_GRADIENT_SPACING_CLAMP: {
+ BKE_colorband_evaluate(
+ brush->gradient, ss->cache->stroke_distance / brush->gradient_spacing, brush_color);
+ break;
+ }
+ }
+ }
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -151,7 +168,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
/* Density. */
@@ -182,14 +199,10 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha);
float col[4];
- SCULPT_vertex_color_get(ss, vd.index, col);
+ SCULPT_vertex_color_get(ss, vd.vertex, col);
IMB_blend_color_float(col, orig_data.col, buffer_color, brush->blend);
CLAMP4(col, 0.0f, 1.0f);
- SCULPT_vertex_color_set(ss, vd.index, col);
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
+ SCULPT_vertex_color_set(ss, vd.vertex, col);
}
BKE_pbvh_vertex_iter_end;
}
@@ -221,7 +234,7 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata,
}
float col[4];
- SCULPT_vertex_color_get(ss, vd.index, col);
+ SCULPT_vertex_color_get(ss, vd.vertex, col);
add_v4_v4(swptd->color, col);
swptd->tot_samples++;
@@ -400,7 +413,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float current_disp[3];
@@ -409,7 +422,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]);
float no[3];
- SCULPT_vertex_normal_get(ss, vd.index, no);
+ SCULPT_vertex_normal_get(ss, vd.vertex, no);
switch (brush->smear_deform_type) {
case BRUSH_SMEAR_DEFORM_DRAG:
@@ -427,7 +440,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
madd_v3_v3fl(current_disp, no, -dot_v3v3(current_disp, no));
normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+ mul_v3_v3fl(current_disp, current_disp_norm, bstrength);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float totw = 0.0f;
@@ -442,11 +455,11 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
*/
SculptVertexNeighborIter ni2;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni2) {
- const float *nco = SCULPT_vertex_co_get(ss, ni2.index);
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni2) {
+ const float *nco = SCULPT_vertex_co_get(ss, ni2.vertex);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.vertex, ni) {
if (ni.index == vd.index) {
continue;
}
@@ -454,15 +467,15 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
float vertex_disp[3];
float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co);
/* Weight by how close we are to our target distance from vd.co. */
- float w = (1.0f + fabsf(len_v3(vertex_disp) / ss->cache->bstrength - 1.0f));
+ float w = (1.0f + fabsf(len_v3(vertex_disp) / bstrength - 1.0f));
/* TODO: use cotangents (or at least face areas) here. */
- float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.index), nco);
+ float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.vertex), nco);
if (len > 0.0f) {
- len = ss->cache->bstrength / len;
+ len = bstrength / len;
}
else { /* Coincident point. */
len = 1.0f;
@@ -502,13 +515,9 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
blend_color_mix_float(interp_color, interp_color, accum);
float col[4];
- SCULPT_vertex_color_get(ss, vd.index, col);
+ SCULPT_vertex_color_get(ss, vd.vertex, col);
blend_color_interpolate_float(col, ss->cache->prev_colors[vd.index], interp_color, fade);
- SCULPT_vertex_color_set(ss, vd.index, col);
-
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
- }
+ SCULPT_vertex_color_set(ss, vd.vertex, col);
}
BKE_pbvh_vertex_iter_end;
}
@@ -522,7 +531,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_vertex_color_get(ss, vd.index, ss->cache->prev_colors[vd.index]);
+ SCULPT_vertex_color_get(ss, vd.vertex, ss->cache->prev_colors[vd.index]);
}
BKE_pbvh_vertex_iter_end;
}
@@ -532,7 +541,7 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- if (!SCULPT_has_colors(ss)) {
+ if (!SCULPT_has_colors(ss) || ss->cache->bstrength == 0.0f) {
return;
}
@@ -541,7 +550,9 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
if (!ss->cache->prev_colors) {
ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_color_get(ss, vertex, ss->cache->prev_colors[i]);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index 975a8f21aaf..8a3a3fe7adc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -172,7 +172,15 @@ template<typename ImageBuffer> class PaintingKernel {
const float3 face_normal(0.0f, 0.0f, 0.0f);
const float mask = 0.0f;
const float falloff_strength = SCULPT_brush_strength_factor(
- ss, brush, pixel_pos, sqrtf(test.dist), normal, face_normal, mask, 0, thread_id);
+ ss,
+ brush,
+ pixel_pos,
+ sqrtf(test.dist),
+ normal,
+ face_normal,
+ mask,
+ BKE_pbvh_make_vref(PBVH_REF_NONE),
+ thread_id);
float4 paint_color = brush_color * falloff_strength * brush_strength;
float4 buffer_color;
blend_color_mix_float(buffer_color, color, paint_color);
@@ -383,7 +391,7 @@ static void push_undo(const NodeData &node_data,
continue;
}
int tilex, tiley, tilew, tileh;
- ListBase *undo_tiles = ED_image_paint_tile_list_get();
+ PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
undo_region_tiles(&image_buffer,
tile_undo.region.xmin,
tile_undo.region.ymin,
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 666cdd3fe50..d1418c8dc35 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -156,7 +156,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
float final_pos[3];
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -182,7 +182,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
/* Apply the vertex mask to the displacement. */
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
mul_v3_fl(disp, mask * automask);
/* Accumulate the displacement. */
@@ -196,7 +196,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
copy_v3_v3(target_co, final_pos);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -221,7 +221,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
float max = 0.0f;
/* Grow the factor. */
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
max = MAX2(vmask_f, max);
}
@@ -367,7 +367,7 @@ typedef struct PoseFloodFillData {
int current_face_set;
int next_face_set;
int prev_face_set;
- int next_vertex;
+ PBVHVertRef next_vertex;
bool next_face_set_found;
@@ -397,14 +397,19 @@ typedef struct PoseFloodFillData {
int target_face_set;
} PoseFloodFillData;
-static bool pose_topology_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+static bool pose_topology_floodfill_cb(SculptSession *ss,
+ PBVHVertRef UNUSED(from_v),
+ PBVHVertRef to_v,
+ bool is_duplicate,
+ void *userdata)
{
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
PoseFloodFillData *data = userdata;
const float *co = SCULPT_vertex_co_get(ss, to_v);
if (data->pose_factor) {
- data->pose_factor[to_v] = 1.0f;
+ data->pose_factor[to_v_i] = 1.0f;
}
if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) <
@@ -426,15 +431,19 @@ static bool pose_topology_floodfill_cb(
return false;
}
-static bool pose_face_sets_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+static bool pose_face_sets_floodfill_cb(SculptSession *ss,
+ PBVHVertRef UNUSED(from_v),
+ PBVHVertRef to_v,
+ bool is_duplicate,
+ void *userdata)
{
PoseFloodFillData *data = userdata;
- const int index = to_v;
+ const int index = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+ const PBVHVertRef vertex = to_v;
bool visit_next = false;
- const float *co = SCULPT_vertex_co_get(ss, index);
+ const float *co = SCULPT_vertex_co_get(ss, vertex);
const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry(
co, data->pose_initial_co, data->symm) &&
!is_duplicate;
@@ -448,11 +457,11 @@ static bool pose_face_sets_floodfill_cb(
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
- const int visited_face_set = SCULPT_vertex_face_set_get(ss, index);
+ const int visited_face_set = SCULPT_vertex_face_set_get(ss, vertex);
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(visited_face_set));
}
else if (symmetry_check) {
- data->current_face_set = SCULPT_vertex_face_set_get(ss, index);
+ data->current_face_set = SCULPT_vertex_face_set_get(ss, vertex);
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set));
}
return true;
@@ -466,11 +475,11 @@ static bool pose_face_sets_floodfill_cb(
GSetIterator gs_iter;
GSET_ITER (gs_iter, data->visited_face_sets) {
const int visited_face_set = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
- is_vertex_valid |= SCULPT_vertex_has_face_set(ss, index, visited_face_set);
+ is_vertex_valid |= SCULPT_vertex_has_face_set(ss, vertex, visited_face_set);
}
}
else {
- is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set);
+ is_vertex_valid = SCULPT_vertex_has_face_set(ss, vertex, data->current_face_set);
}
if (!is_vertex_valid) {
@@ -485,11 +494,11 @@ static bool pose_face_sets_floodfill_cb(
/* Fallback origin accumulation. */
if (symmetry_check) {
- add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index));
+ add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, vertex));
data->fallback_count++;
}
- if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, index)) {
+ if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, vertex)) {
return visit_next;
}
@@ -498,15 +507,15 @@ static bool pose_face_sets_floodfill_cb(
bool count_as_boundary = false;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.index);
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
+ int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.vertex);
/* Check if we can get a valid face set for the next iteration from this neighbor. */
- if (SCULPT_vertex_has_unique_face_set(ss, ni.index) &&
+ if (SCULPT_vertex_has_unique_face_set(ss, ni.vertex) &&
!BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(next_face_set_candidate))) {
if (!data->next_face_set_found) {
data->next_face_set = next_face_set_candidate;
- data->next_vertex = ni.index;
+ data->next_vertex = ni.vertex;
data->next_face_set_found = true;
}
count_as_boundary = true;
@@ -516,7 +525,7 @@ static bool pose_face_sets_floodfill_cb(
/* Origin accumulation. */
if (count_as_boundary) {
- add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index));
+ add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, vertex));
data->tot_co++;
}
return visit_next;
@@ -585,7 +594,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
SculptVertexNeighborIter ni;
float avg = 0.0f;
int total = 0;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
avg += data->pose_factor[ni.index];
total++;
}
@@ -660,7 +669,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
float next_chain_segment_target[3];
int totvert = SCULPT_vertex_count_get(ss);
- int nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
+ PBVHVertRef nearest_vertex = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
+ int nearest_vertex_index = BKE_pbvh_vertex_to_index(ss->pbvh, nearest_vertex);
/* Init the buffers used to keep track of the changes in the pose factors as more segments are
* added to the IK chain. */
@@ -745,7 +755,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
int current_face_set = SCULPT_FACE_SET_NONE;
int prev_face_set = SCULPT_FACE_SET_NONE;
- int current_vertex = SCULPT_active_vertex_get(ss);
+ PBVHVertRef current_vertex = SCULPT_active_vertex_get(ss);
for (int s = 0; s < ik_chain->tot_segments; s++) {
@@ -801,15 +811,18 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
}
static bool pose_face_sets_fk_find_masked_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
+ int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
if (!is_duplicate) {
- data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1;
+ data->floodfill_it[to_v_i] = data->floodfill_it[from_v_i] + 1;
}
else {
- data->floodfill_it[to_v] = data->floodfill_it[from_v];
+ data->floodfill_it[to_v_i] = data->floodfill_it[from_v_i];
}
const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v);
@@ -820,9 +833,9 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(to_face_set));
- if (data->floodfill_it[to_v] >= data->masked_face_set_it) {
+ if (data->floodfill_it[to_v_i] >= data->masked_face_set_it) {
data->masked_face_set = to_face_set;
- data->masked_face_set_it = data->floodfill_it[to_v];
+ data->masked_face_set_it = data->floodfill_it[to_v_i];
}
if (data->target_face_set == SCULPT_FACE_SET_NONE) {
@@ -834,11 +847,17 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set);
}
-static bool pose_face_sets_fk_set_weights_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+static bool pose_face_sets_fk_set_weights_floodfill_cb(SculptSession *ss,
+ PBVHVertRef UNUSED(from_v),
+ PBVHVertRef to_v,
+ bool UNUSED(is_duplicate),
+ void *userdata)
{
PoseFloodFillData *data = userdata;
- data->fk_weights[to_v] = 1.0f;
+
+ int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
+
+ data->fk_weights[to_v_i] = 1.0f;
return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set);
}
@@ -849,7 +868,9 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss);
+ int active_vertex_index = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex);
+
const int active_face_set = SCULPT_active_face_set_get(ss);
SculptFloodFill flood;
@@ -857,7 +878,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SCULPT_floodfill_add_initial(&flood, active_vertex);
PoseFloodFillData fdata;
fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration");
- fdata.floodfill_it[active_vertex] = 1;
+ fdata.floodfill_it[active_vertex_index] = 1;
fdata.initial_face_set = active_face_set;
fdata.masked_face_set = SCULPT_FACE_SET_NONE;
fdata.target_face_set = SCULPT_FACE_SET_NONE;
@@ -870,9 +891,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
int origin_count = 0;
float origin_acc[3] = {0.0f};
for (int i = 0; i < totvert; i++) {
- if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
- SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) {
- add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i));
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ if (fdata.floodfill_it[i] != 0 &&
+ SCULPT_vertex_has_face_set(ss, vertex, fdata.initial_face_set) &&
+ SCULPT_vertex_has_face_set(ss, vertex, fdata.masked_face_set)) {
+ add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, vertex));
origin_count++;
}
}
@@ -881,10 +905,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
float target_acc[3] = {0.0f};
if (fdata.target_face_set != fdata.masked_face_set) {
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
if (fdata.floodfill_it[i] != 0 &&
- SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
- SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) {
- add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_has_face_set(ss, vertex, fdata.initial_face_set) &&
+ SCULPT_vertex_has_face_set(ss, vertex, fdata.target_face_set)) {
+ add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, vertex));
target_count++;
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 53babc3d36d..2ef3c28ba0c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -46,26 +46,28 @@
#include <math.h>
#include <stdlib.h>
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index)
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
+ float result[3],
+ PBVHVertRef vertex)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
int neighbor_count = 0;
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, index);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vertex);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
neighbor_count++;
if (is_boundary) {
/* Boundary vertices use only other boundary vertices. */
- if (SCULPT_vertex_is_boundary(ss, ni.index)) {
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
}
else {
/* Interior vertices use all neighbors. */
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
}
@@ -73,13 +75,13 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3],
/* Do not modify corner vertices. */
if (neighbor_count <= 2 && is_boundary) {
- copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
+ copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
return;
}
/* Avoid division by 0 when there are no neighbors. */
if (total == 0) {
- copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
+ copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
return;
}
@@ -134,14 +136,14 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert
/* Generic functions for laplacian smoothing. These functions do not take boundary vertices into
* account. */
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -150,18 +152,18 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int inde
mul_v3_v3fl(result, avg, 1.0f / total);
}
else {
- copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
+ copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
}
}
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
+float SCULPT_neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex)
{
float avg = 0.0f;
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- avg += SCULPT_vertex_mask_get(ss, ni.index);
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
+ avg += SCULPT_vertex_mask_get(ss, ni.vertex);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -169,19 +171,19 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
if (total > 0) {
return avg / total;
}
- return SCULPT_vertex_mask_get(ss, index);
+ return SCULPT_vertex_mask_get(ss, vertex);
}
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index)
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex)
{
float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
float tmp[4] = {0};
- SCULPT_vertex_color_get(ss, ni.index, tmp);
+ SCULPT_vertex_color_get(ss, ni.vertex, tmp);
add_v4_v4(avg, tmp);
total++;
@@ -192,7 +194,7 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index
mul_v4_v4fl(result, avg, 1.0f / total);
}
else {
- SCULPT_vertex_color_get(ss, index, result);
+ SCULPT_vertex_color_get(ss, vertex, result);
}
}
@@ -227,7 +229,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float disp[3];
@@ -235,7 +237,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
SCULPT_clip(sd, ss, vd.co, disp);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -258,9 +260,11 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
totvert, sizeof(float[3]), "details directions");
for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
float avg[3];
- SCULPT_neighbor_coords_average(ss, avg, i);
- sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
+ SCULPT_neighbor_coords_average(ss, avg, vertex);
+ sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
}
}
@@ -309,23 +313,23 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- vd.index,
+ vd.vertex,
thread_id);
if (smooth_mask) {
- float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
+ float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
- SCULPT_neighbor_coords_average_interior(ss, avg, vd.index);
+ SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex);
sub_v3_v3v3(val, avg, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
SCULPT_clip(sd, ss, vd.co, val);
- }
- if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ if (vd.mvert) {
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
+ }
}
}
BKE_pbvh_vertex_iter_end;
@@ -403,13 +407,15 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float *disp,
const float co[3],
float (*laplacian_disp)[3],
- const int v_index,
+ const PBVHVertRef vertex,
const float origco[3],
const float alpha)
{
float laplacian_smooth_co[3];
float weigthed_o[3], weigthed_q[3], d[3];
- SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index);
+ int v_index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex);
+
+ SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, vertex);
mul_v3_v3fl(weigthed_o, origco, alpha);
mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
@@ -422,7 +428,7 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float *co,
float (*laplacian_disp)[3],
- const int v_index,
+ const PBVHVertRef vertex,
const float beta,
const float fade)
{
@@ -430,12 +436,15 @@ void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float b_current_vertex[3];
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
add_v3_v3(b_avg, laplacian_disp[ni.index]);
total++;
}
+
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (total > 0) {
+ int v_index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex);
+
mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / total);
madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta);
mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f));
@@ -460,7 +469,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -474,15 +483,15 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float disp[3];
SCULPT_surface_smooth_laplacian_step(
- ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, orig_data.co, alpha);
+ ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, orig_data.co, alpha);
madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -515,10 +524,10 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
SCULPT_surface_smooth_displace_step(
- ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
+ ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade);
}
BKE_pbvh_vertex_iter_end;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index 48033f3407e..dfaa0bd4daa 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -46,7 +46,7 @@
#include <math.h>
#include <stdlib.h>
-void ED_sculpt_init_transform(struct bContext *C, Object *ob)
+void ED_sculpt_init_transform(struct bContext *C, Object *ob, const char *undo_name)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
@@ -60,7 +60,7 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
- SCULPT_undo_push_begin(ob, "Transform");
+ SCULPT_undo_push_begin_ex(ob, undo_name);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
ss->pivot_rot[3] = 1.0f;
@@ -150,7 +150,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
PBVHNode *node = data->nodes[i];
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
PBVHVertexIter vd;
@@ -179,7 +179,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
add_v3_v3v3(vd.co, start_co, disp);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -221,7 +221,7 @@ static void sculpt_elastic_transform_task_cb(void *__restrict userdata,
float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[i])->co;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
KelvinletParams params;
/* TODO(pablodp606): These parameters can be exposed if needed as transform strength and volume
@@ -253,7 +253,7 @@ static void sculpt_elastic_transform_task_cb(void *__restrict userdata,
copy_v3_v3(proxy[vd.i], final_disp);
if (vd.mvert) {
- BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
}
}
BKE_pbvh_vertex_iter_end;
@@ -289,9 +289,6 @@ static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float
flip_v3_v3(data.elastic_transform_pivot, ss->pivot_pos, symmpass);
flip_v3_v3(data.elastic_transform_pivot_init, ss->init_pivot_pos, symmpass);
- printf(
- "%.2f %.2f %.2f\n", ss->init_pivot_pos[0], ss->init_pivot_pos[1], ss->init_pivot_pos[2]);
-
const int symm_area = SCULPT_get_vertex_symm_area(data.elastic_transform_pivot);
copy_m4_m4(data.elastic_transform_mat, data.transform_mats[symm_area]);
BLI_task_parallel_range(
@@ -354,11 +351,6 @@ void ED_sculpt_end_transform(struct bContext *C, Object *ob)
if (ss->filter_cache) {
SCULPT_filter_cache_free(ss);
}
- /* Force undo push to happen even inside transform operator, since the sculpt
- * undo system works separate from regular undo and this is require to properly
- * finish an undo step also when canceling. */
- const bool use_nested_undo = true;
- SCULPT_undo_push_end_ex(ob, use_nested_undo);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
@@ -426,7 +418,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
RNA_float_get(op->ptr, "mouse_x"),
RNA_float_get(op->ptr, "mouse_y"),
};
- if (SCULPT_stroke_get_location(C, stroke_location, mval)) {
+ if (SCULPT_stroke_get_location(C, stroke_location, mval, false)) {
copy_v3_v3(ss->pivot_pos, stroke_location);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index e82f14b1ca7..a31be07d8af 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -4,6 +4,29 @@
/** \file
* \ingroup edsculpt
* Implements the Sculpt Mode tools.
+ *
+ * Usage Guide
+ * ===========
+ *
+ * The sculpt undo system is a delta-based system. Each undo step stores
+ * the difference with the prior one.
+ *
+ * To use the sculpt undo system, you must call SCULPT_undo_push_begin
+ * inside an operator exec or invoke callback (ED_sculpt_undo_geometry_begin
+ * may be called if you wish to save a non-delta copy of the entire mesh).
+ * This will initialize the sculpt undo stack and set up an undo step.
+ *
+ * At the end of the operator you should call SCULPT_undo_push_end.
+ *
+ * SCULPT_undo_push_end and ED_sculpt_undo_geometry_begin both take a
+ * #wmOperatorType as an argument. There are _ex versions that allow a custom
+ * name; try to avoid using them. These can break the redo panel since it requires
+ * the undo push have the same name as the calling operator.
+ *
+ * NOTE: Sculpt undo steps are not appended to the global undo stack until
+ * the operator finishes. We use BKE_undosys_step_push_init_with_type to build
+ * a tentative undo step with is appended later when the operator ends.
+ * Operators must have the OPTYPE_UNDO flag set for this to work properly.
*/
#include <stddef.h>
@@ -30,6 +53,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -144,6 +168,9 @@ struct PartialUpdateData {
PBVH *pbvh;
bool rebuild;
char *modified_grids;
+ bool *modified_hidden_verts;
+ bool *modified_mask_verts;
+ bool *modified_color_verts;
};
/**
@@ -167,8 +194,39 @@ static void update_cb_partial(PBVHNode *node, void *userdata)
}
}
else {
- if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
- update_cb(node, &(data->rebuild));
+ if (BKE_pbvh_node_has_vert_with_normal_update_tag(data->pbvh, node)) {
+ BKE_pbvh_node_mark_update(node);
+ }
+ int verts_num;
+ const int *vert_indices;
+ BKE_pbvh_node_num_verts(data->pbvh, node, NULL, &verts_num);
+ BKE_pbvh_node_get_verts(data->pbvh, node, &vert_indices, NULL);
+ if (data->modified_mask_verts != NULL) {
+ for (int i = 0; i < verts_num; i++) {
+ if (data->modified_mask_verts[vert_indices[i]]) {
+ BKE_pbvh_node_mark_update_mask(node);
+ break;
+ }
+ }
+ }
+ if (data->modified_color_verts != NULL) {
+ for (int i = 0; i < verts_num; i++) {
+ if (data->modified_color_verts[vert_indices[i]]) {
+ BKE_pbvh_node_mark_update_color(node);
+ break;
+ }
+ }
+ }
+ if (data->modified_hidden_verts != NULL) {
+ for (int i = 0; i < verts_num; i++) {
+ if (data->modified_hidden_verts[vert_indices[i]]) {
+ if (data->rebuild) {
+ BKE_pbvh_node_mark_update_visibility(node);
+ }
+ BKE_pbvh_node_fully_hidden_set(node, 0);
+ break;
+ }
+ }
}
}
}
@@ -196,7 +254,7 @@ static bool sculpt_undo_restore_deformed(
static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, SculptUndoNode *unode)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
@@ -263,20 +321,20 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
- BKE_pbvh_vert_mark_update(ss->pbvh, index[i]);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i]));
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
- BKE_pbvh_vert_mark_update(ss->pbvh, index[i]);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i]));
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
swap_v3_v3(mvert[index[i]].co, unode->co[i]);
- BKE_pbvh_vert_mark_update(ss->pbvh, index[i]);
+ BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i]));
}
}
}
@@ -305,22 +363,22 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
return true;
}
-static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode)
+static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode, bool *modified_vertices)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
- if (unode->maxvert) {
- MVert *mvert = ss->mvert;
+ bool *hide_vert = BKE_pbvh_get_vert_hide_for_write(ss->pbvh);
+ if (unode->maxvert) {
for (int i = 0; i < unode->totvert; i++) {
- MVert *v = &mvert[unode->index[i]];
- if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
+ const int vert_index = unode->index[i];
+ if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != hide_vert[vert_index]) {
BLI_BITMAP_FLIP(unode->vert_hidden, i);
- v->flag ^= ME_HIDE;
- BKE_pbvh_vert_mark_update(ss->pbvh, unode->index[i]);
+ hide_vert[vert_index] = !hide_vert[vert_index];
+ modified_vertices[vert_index] = true;
}
}
}
@@ -335,10 +393,10 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode)
return true;
}
-static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode)
+static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode, bool *modified_vertices)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
SculptSession *ss = ob->sculpt;
bool modified = false;
@@ -360,17 +418,17 @@ static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode)
if (modified) {
for (int i = 0; i < unode->totvert; i++) {
- BKE_pbvh_vert_mark_update(ss->pbvh, unode->index[i]);
+ modified_vertices[unode->index[i]] = true;
}
}
return modified;
}
-static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
+static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *modified_vertices)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
float *vmask;
@@ -385,7 +443,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
for (int i = 0; i < unode->totvert; i++) {
if (vmask[index[i]] != unode->mask[i]) {
SWAP(float, vmask[index[i]], unode->mask[i]);
- BKE_pbvh_vert_mark_update(ss->pbvh, index[i]);
+ modified_vertices[index[i]] = true;
}
}
}
@@ -416,7 +474,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Mesh *me = BKE_object_get_original_mesh(ob);
int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
for (int i = 0; i < me->totpoly; i++) {
@@ -569,8 +627,6 @@ static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry,
CustomData_copy(
&geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
- BKE_mesh_update_customdata_pointers(mesh, false);
-
BKE_mesh_runtime_clear_cache(mesh);
}
@@ -665,7 +721,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
SculptUndoNode *unode;
@@ -699,7 +755,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask, false);
- SCULPT_visibility_sync_all_face_sets_to_vertices(ob);
+ SCULPT_visibility_sync_all_face_sets_to_verts(ob);
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
@@ -731,6 +787,12 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
+ /* The PBVH already keeps track of which vertices need updated normals, but it doesn't keep track
+ * of other updated. In order to tell the corresponding PBVH nodes to update, keep track of which
+ * elements were updated for specific layers. */
+ bool *modified_hidden_verts = NULL;
+ bool *modified_mask_verts = NULL;
+ bool *modified_color_verts = NULL;
char *undo_modified_grids = NULL;
bool use_multires_undo = false;
@@ -763,13 +825,19 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
break;
case SCULPT_UNDO_HIDDEN:
- if (sculpt_undo_restore_hidden(C, unode)) {
+ if (modified_hidden_verts == NULL) {
+ modified_hidden_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__);
+ }
+ if (sculpt_undo_restore_hidden(C, unode, modified_hidden_verts)) {
rebuild = true;
update_visibility = true;
}
break;
case SCULPT_UNDO_MASK:
- if (sculpt_undo_restore_mask(C, unode)) {
+ if (modified_mask_verts == NULL) {
+ modified_mask_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__);
+ }
+ if (sculpt_undo_restore_mask(C, unode, modified_mask_verts)) {
update = true;
update_mask = true;
}
@@ -777,7 +845,10 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_FACE_SETS:
break;
case SCULPT_UNDO_COLOR:
- if (sculpt_undo_restore_color(C, unode)) {
+ if (modified_color_verts == NULL) {
+ modified_color_verts = MEM_calloc_arrayN(ss->totvert, sizeof(bool), __func__);
+ }
+ if (sculpt_undo_restore_color(C, unode, modified_color_verts)) {
update = true;
}
@@ -828,6 +899,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
.rebuild = rebuild,
.pbvh = ss->pbvh,
.modified_grids = undo_modified_grids,
+ .modified_hidden_verts = modified_hidden_verts,
+ .modified_mask_verts = modified_mask_verts,
+ .modified_color_verts = modified_color_verts,
};
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw);
@@ -855,7 +929,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
if (tag_update) {
Mesh *mesh = ob->data;
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(mesh);
BKE_sculptsession_free_deformMats(ss);
}
@@ -873,6 +947,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
+ MEM_SAFE_FREE(modified_hidden_verts);
+ MEM_SAFE_FREE(modified_mask_verts);
+ MEM_SAFE_FREE(modified_color_verts);
MEM_SAFE_FREE(undo_modified_grids);
}
@@ -944,7 +1021,7 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
SculptUndoNode *unode;
unode = lb->first;
@@ -961,7 +1038,7 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
}
#endif
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
@@ -969,7 +1046,13 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return NULL;
}
- return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ LISTBASE_FOREACH (SculptUndoNode *, unode, &usculpt->nodes) {
+ if (unode->node == node && unode->type == type) {
+ return unode;
+ }
+ }
+
+ return NULL;
}
SculptUndoNode *SCULPT_undo_get_first_node()
@@ -1081,8 +1164,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->co = MEM_callocN(alloc_size, "SculptUndoNode.co");
usculpt->undo_size += alloc_size;
- /* FIXME: Should explain why this is allocated here, to be freed in
- * `SCULPT_undo_push_end_ex()`? */
+ /* Needed for original data lookup. */
alloc_size = sizeof(*unode->no) * (size_t)allvert;
unode->no = MEM_callocN(alloc_size, "SculptUndoNode.no");
usculpt->undo_size += alloc_size;
@@ -1185,6 +1267,11 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
PBVH *pbvh = ob->sculpt->pbvh;
PBVHNode *node = unode->node;
+ const bool *hide_vert = BKE_pbvh_get_vert_hide(pbvh);
+ if (hide_vert == NULL) {
+ return;
+ }
+
if (unode->grids) {
/* Already stored during allocation. */
}
@@ -1196,7 +1283,7 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
for (int i = 0; i < allvert; i++) {
- BLI_BITMAP_SET(unode->vert_hidden, i, mvert[vert_indices[i]].flag & ME_HIDE);
+ BLI_BITMAP_SET(unode->vert_hidden, i, hide_vert[vert_indices[i]]);
}
}
}
@@ -1381,7 +1468,7 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
- if ((unode = SCULPT_undo_get_node(node))) {
+ if ((unode = SCULPT_undo_get_node(node, type))) {
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
@@ -1480,7 +1567,12 @@ static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
attr->was_set = true;
}
-void SCULPT_undo_push_begin(Object *ob, const char *name)
+void SCULPT_undo_push_begin(Object *ob, const wmOperator *op)
+{
+ SCULPT_undo_push_begin_ex(ob, op->type->name);
+}
+
+void SCULPT_undo_push_begin_ex(Object *ob, const char *name)
{
UndoStack *ustack = ED_undo_stack_get();
@@ -1576,11 +1668,12 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
*/
if (!layer) {
layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
- eAttrDomain domain = layer ? BKE_id_attribute_domain(&me->id, layer) : ATTR_DOMAIN_NUM;
-
- if (layer && ED_geometry_attribute_convert(
- me, attr->name, layer->type, domain, attr->type, attr->domain)) {
- layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ if (layer) {
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ if (ED_geometry_attribute_convert(
+ me, attr->name, layer->type, domain, attr->type, attr->domain)) {
+ layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ }
}
}
@@ -1589,7 +1682,7 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata;
int totelem = attr->domain == ATTR_DOMAIN_POINT ? me->totvert : me->totloop;
- CustomData_add_layer_named(cdata, attr->type, CD_DEFAULT, NULL, totelem, attr->name);
+ CustomData_add_layer_named(cdata, attr->type, CD_SET_DEFAULT, NULL, totelem, attr->name);
layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
}
@@ -1722,7 +1815,7 @@ static void sculpt_undosys_step_decode(
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob && (ob->type == OB_MESH)) {
if (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT)) {
/* Pass. */
@@ -1768,9 +1861,15 @@ static void sculpt_undosys_step_free(UndoStep *us_p)
sculpt_undo_free_list(&us->data.nodes);
}
-void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name)
+void ED_sculpt_undo_geometry_begin(struct Object *ob, const wmOperator *op)
+{
+ SCULPT_undo_push_begin(ob, op);
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY);
+}
+
+void ED_sculpt_undo_geometry_begin_ex(struct Object *ob, const char *name)
{
- SCULPT_undo_push_begin(ob, name);
+ SCULPT_undo_push_begin_ex(ob, name);
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY);
}
@@ -1883,7 +1982,7 @@ void ED_sculpt_undo_push_multires_mesh_begin(bContext *C, const char *str)
Object *object = CTX_data_active_object(C);
- SCULPT_undo_push_begin(object, str);
+ SCULPT_undo_push_begin_ex(object, str);
SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY);
geometry_unode->geometry_clear_pbvh = false;
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 8e1f4f4d495..8b9776cf94d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -9,7 +9,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
-#include "BLI_math.h"
+#include "BLI_math_base_safe.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
@@ -22,6 +22,7 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
+#include "BKE_image.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
@@ -30,6 +31,7 @@
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -42,6 +44,9 @@
#include "UI_view2d.h"
+/* When set, the UV element is on the boundary of the graph.
+ * i.e. Instead of a 2-dimensional laplace operator, use a 1-dimensional version.
+ * Visually, UV elements on the graph boundary appear as borders of the UV Island. */
#define MARK_BOUNDARY 1
typedef struct UvAdjacencyElement {
@@ -49,16 +54,17 @@ typedef struct UvAdjacencyElement {
UvElement *element;
/* uv pointer for convenience. Caution, this points to the original UVs! */
float *uv;
- /* general use flag (Used to check if Element is boundary here) */
- char flag;
+ /* Are we on locked in place? */
+ bool is_locked;
+ /* Are we on the boundary? */
+ bool is_boundary;
} UvAdjacencyElement;
typedef struct UvEdge {
uint uv1;
uint uv2;
- /* general use flag
- * (Used to check if edge is boundary here, and propagates to adjacency elements) */
- char flag;
+ /* Are we in the interior? */
+ bool is_interior;
} UvEdge;
typedef struct UVInitialStrokeElement {
@@ -90,13 +96,13 @@ typedef struct UvSculptData {
* to their coincident UV's */
UvAdjacencyElement *uv;
- /* ...Is what it says */
+ /* Total number of unique UVs. */
int totalUniqueUvs;
/* Edges used for adjacency info, used with laplacian smoothing */
UvEdge *uvedges;
- /* need I say more? */
+ /* Total number of #UvEdge. */
int totalUvEdges;
/* data for initial stroke, used by tools like grab */
@@ -116,8 +122,25 @@ typedef struct UvSculptData {
/* store invert flag here */
char invert;
+
+ /* Is constrain to image bounds active? */
+ bool constrain_to_bounds;
+
+ /* Base for constrain_to_bounds. */
+ float uv_base_offset[2];
} UvSculptData;
+static void apply_sculpt_data_constraints(UvSculptData *sculptdata, float uv[2])
+{
+ if (!sculptdata->constrain_to_bounds) {
+ return;
+ }
+ float u = sculptdata->uv_base_offset[0];
+ float v = sculptdata->uv_base_offset[1];
+ uv[0] = clamp_f(uv[0], u, u + 1.0f);
+ uv[1] = clamp_f(uv[1], v, v + 1.0f);
+}
+
/*********** Improved Laplacian Relaxation Operator ************************/
/* original code by Raul Fernandez Hernandez "farsthary" *
* adapted to uv smoothing by Antony Riakiatakis *
@@ -170,17 +193,14 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em,
}
for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- float dist;
- /* This is supposed to happen only if "Pin Edges" is on,
- * since we have initialization on stroke start.
- * If ever uv brushes get their own mode we should check for toolsettings option too. */
- if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
+ if (sculptdata->uv[i].is_locked) {
continue;
}
sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ float dist = dot_v2v2(diff, diff);
+ if (dist <= radius) {
UvElement *element;
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
@@ -196,6 +216,8 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em,
0.5f * (tmp_uvdata[i].b[1] +
tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter));
+ apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv);
+
for (element = sculptdata->uv[i].element; element; element = element->next) {
MLoopUV *luv;
BMLoop *l;
@@ -211,9 +233,16 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em,
}
}
- MEM_freeN(tmp_uvdata);
+ MEM_SAFE_FREE(tmp_uvdata);
}
+/* Legacy version which only does laplacian relaxation.
+ * Probably a little faster as it caches UvEdges.
+ * Mostly preserved for comparison with `HC_relaxation_iteration_uv`.
+ * Once the HC method has been merged into `relaxation_iteration_uv`,
+ * all the `HC_*` and `laplacian_*` specific functions can probably be removed.
+ */
+
static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
UvSculptData *sculptdata,
const float mouse_coord[2],
@@ -233,14 +262,19 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
/* counting neighbors */
for (i = 0; i < sculptdata->totalUvEdges; i++) {
UvEdge *tmpedge = sculptdata->uvedges + i;
- tmp_uvdata[tmpedge->uv1].ncounter++;
- tmp_uvdata[tmpedge->uv2].ncounter++;
-
- add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
- add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
+ bool code1 = sculptdata->uv[sculptdata->uvedges[i].uv1].is_boundary;
+ bool code2 = sculptdata->uv[sculptdata->uvedges[i].uv2].is_boundary;
+ if (code1 || (code1 == code2)) {
+ tmp_uvdata[tmpedge->uv2].ncounter++;
+ add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
+ }
+ if (code2 || (code1 == code2)) {
+ tmp_uvdata[tmpedge->uv1].ncounter++;
+ add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
+ }
}
- /* Original Lacplacian algorithm included removal of normal component of translation.
+ /* Original Laplacian algorithm included removal of normal component of translation.
* here it is not needed since we translate along the UV plane always. */
for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
@@ -248,17 +282,14 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
}
for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- float dist;
- /* This is supposed to happen only if "Pin Edges" is on,
- * since we have initialization on stroke start.
- * If ever uv brushes get their own mode we should check for toolsettings option too. */
- if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
+ if (sculptdata->uv[i].is_locked) {
continue;
}
sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ float dist = dot_v2v2(diff, diff);
+ if (dist <= radius) {
UvElement *element;
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
@@ -268,6 +299,8 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] +
strength * tmp_uvdata[i].p[1];
+ apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv);
+
for (element = sculptdata->uv[i].element; element; element = element->next) {
MLoopUV *luv;
BMLoop *l;
@@ -283,7 +316,154 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
}
}
- MEM_freeN(tmp_uvdata);
+ MEM_SAFE_FREE(tmp_uvdata);
+}
+
+static void add_weighted_edge(float (*delta_buf)[3],
+ const UvElement *storage,
+ const UvElement *ele_next,
+ const UvElement *ele_prev,
+ const MLoopUV *luv_next,
+ const MLoopUV *luv_prev,
+ const float weight)
+{
+ float delta[2];
+ sub_v2_v2v2(delta, luv_next->uv, luv_prev->uv);
+
+ bool code1 = (ele_prev->flag & MARK_BOUNDARY);
+ bool code2 = (ele_next->flag & MARK_BOUNDARY);
+ if (code1 || (code1 == code2)) {
+ int index_next = ele_next - storage;
+ delta_buf[index_next][0] -= delta[0] * weight;
+ delta_buf[index_next][1] -= delta[1] * weight;
+ delta_buf[index_next][2] += fabsf(weight);
+ }
+ if (code2 || (code1 == code2)) {
+ int index_prev = ele_prev - storage;
+ delta_buf[index_prev][0] += delta[0] * weight;
+ delta_buf[index_prev][1] += delta[1] * weight;
+ delta_buf[index_prev][2] += fabsf(weight);
+ }
+}
+
+static float tri_weight_v3(int method, const float *v1, const float *v2, const float *v3)
+{
+ switch (method) {
+ case UV_SCULPT_TOOL_RELAX_LAPLACIAN:
+ case UV_SCULPT_TOOL_RELAX_HC:
+ return 1.0f;
+ case UV_SCULPT_TOOL_RELAX_COTAN:
+ return cotangent_tri_weight_v3(v1, v2, v3);
+ default:
+ BLI_assert_unreachable();
+ }
+ return 0.0f;
+}
+
+static void relaxation_iteration_uv(BMEditMesh *em,
+ UvSculptData *sculptdata,
+ const float mouse_coord[2],
+ const float alpha,
+ const float radius_squared,
+ const float aspect_ratio,
+ const int method)
+{
+ if (method == UV_SCULPT_TOOL_RELAX_HC) {
+ HC_relaxation_iteration_uv(em, sculptdata, mouse_coord, alpha, radius_squared, aspect_ratio);
+ return;
+ }
+ if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) {
+ laplacian_relaxation_iteration_uv(
+ em, sculptdata, mouse_coord, alpha, radius_squared, aspect_ratio);
+ return;
+ }
+
+ struct UvElement **head_table = BM_uv_element_map_ensure_head_table(sculptdata->elementMap);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BLI_assert(cd_loop_uv_offset >= 0);
+
+ const int total_uvs = sculptdata->elementMap->total_uvs;
+ float(*delta_buf)[3] = (float(*)[3])MEM_callocN(total_uvs * sizeof(float[3]), __func__);
+
+ const UvElement *storage = sculptdata->elementMap->storage;
+ for (int j = 0; j < total_uvs; j++) {
+ const UvElement *ele_curr = storage + j;
+ const BMFace *efa = ele_curr->l->f;
+ const UvElement *ele_next = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->next);
+ const UvElement *ele_prev = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->prev);
+
+ const float *v_curr_co = ele_curr->l->v->co;
+ const float *v_prev_co = ele_prev->l->v->co;
+ const float *v_next_co = ele_next->l->v->co;
+
+ const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(ele_curr->l, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(ele_next->l, cd_loop_uv_offset);
+ const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(ele_prev->l, cd_loop_uv_offset);
+
+ const UvElement *head_curr = head_table[ele_curr - sculptdata->elementMap->storage];
+ const UvElement *head_next = head_table[ele_next - sculptdata->elementMap->storage];
+ const UvElement *head_prev = head_table[ele_prev - sculptdata->elementMap->storage];
+
+ /* If the mesh is triangulated with no boundaries, only one edge is required. */
+ const float weight_curr = tri_weight_v3(method, v_curr_co, v_prev_co, v_next_co);
+ add_weighted_edge(delta_buf, storage, head_next, head_prev, luv_next, luv_prev, weight_curr);
+
+ /* Triangulated with a boundary? We need the incoming edges to solve the boundary. */
+ const float weight_prev = tri_weight_v3(method, v_prev_co, v_curr_co, v_next_co);
+ add_weighted_edge(delta_buf, storage, head_next, head_curr, luv_next, luv_curr, weight_prev);
+
+ if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) {
+ /* Laplacian method has zero weights on virtual edges. */
+ continue;
+ }
+
+ /* Meshes with quads (or other n-gons) need "virtual" edges too. */
+ const float weight_next = tri_weight_v3(method, v_next_co, v_curr_co, v_prev_co);
+ add_weighted_edge(delta_buf, storage, head_prev, head_curr, luv_prev, luv_curr, weight_next);
+ }
+
+ Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
+ for (int i = 0; i < sculptdata->totalUniqueUvs; i++) {
+ UvAdjacencyElement *adj_el = &sculptdata->uv[i];
+ if (adj_el->is_locked) {
+ continue; /* Locked UVs can't move. */
+ }
+
+ /* Is UV within brush's influence? */
+ float diff[2];
+ sub_v2_v2v2(diff, adj_el->uv, mouse_coord);
+ diff[1] /= aspect_ratio;
+ const float dist_squared = len_squared_v2(diff);
+ if (dist_squared > radius_squared) {
+ continue;
+ }
+ const float strength = alpha * BKE_brush_curve_strength_clamped(
+ brush, sqrtf(dist_squared), sqrtf(radius_squared));
+
+ const float *delta_sum = delta_buf[adj_el->element - storage];
+
+ {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(adj_el->element->l, cd_loop_uv_offset);
+ BLI_assert(adj_el->uv == luv->uv); /* Only true for head. */
+ adj_el->uv[0] = luv->uv[0] + strength * safe_divide(delta_sum[0], delta_sum[2]);
+ adj_el->uv[1] = luv->uv[1] + strength * safe_divide(delta_sum[1], delta_sum[2]);
+ apply_sculpt_data_constraints(sculptdata, adj_el->uv);
+ }
+
+ /* Copy UV co-ordinates to all UvElements. */
+ UvElement *tail = adj_el->element;
+ while (tail) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(tail->l, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, adj_el->uv);
+ tail = tail->next;
+ if (tail && tail->separate) {
+ break;
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(delta_buf);
}
static void uv_sculpt_stroke_apply(bContext *C,
@@ -327,17 +507,15 @@ static void uv_sculpt_stroke_apply(bContext *C,
int i;
alpha *= invert;
for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
- float dist, diff[2];
- /* This is supposed to happen only if "Lock Borders" is on,
- * since we have initialization on stroke start.
- * If ever uv brushes get their own mode we should check for toolsettings option too. */
- if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
+ if (sculptdata->uv[i].is_locked) {
continue;
}
+ float diff[2];
sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ float dist = dot_v2v2(diff, diff);
+ if (dist <= radius) {
UvElement *element;
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
@@ -346,6 +524,8 @@ static void uv_sculpt_stroke_apply(bContext *C,
sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f;
+ apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv);
+
for (element = sculptdata->uv[i].element; element; element = element->next) {
MLoopUV *luv;
BMLoop *l;
@@ -363,16 +543,11 @@ static void uv_sculpt_stroke_apply(bContext *C,
}
/*
- * Smooth Tool
+ * Relax Tool
*/
else if (tool == UV_SCULPT_TOOL_RELAX) {
- uint method = toolsettings->uv_relax_method;
- if (method == UV_SCULPT_TOOL_RELAX_HC) {
- HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
- }
- else {
- laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
- }
+ relaxation_iteration_uv(
+ em, sculptdata, co, alpha, radius, aspectRatio, toolsettings->uv_relax_method);
}
/*
@@ -392,6 +567,8 @@ static void uv_sculpt_stroke_apply(bContext *C,
sculptdata->uv[uvindex].uv[1] =
sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1];
+ apply_sculpt_data_constraints(sculptdata, sculptdata->uv[uvindex].uv);
+
for (element = sculptdata->uv[uvindex].element; element; element = element->next) {
MLoopUV *luv;
BMLoop *l;
@@ -405,32 +582,32 @@ static void uv_sculpt_stroke_apply(bContext *C,
copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv);
}
}
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_re_solve();
+ }
}
}
static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_end(false);
+ }
UvSculptData *data = op->customdata;
if (data->timer) {
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
}
- if (data->elementMap) {
- BM_uv_element_map_free(data->elementMap);
- }
- if (data->uv) {
- MEM_freeN(data->uv);
- }
- if (data->uvedges) {
- MEM_freeN(data->uvedges);
- }
+ BM_uv_element_map_free(data->elementMap);
+ data->elementMap = NULL;
+ MEM_SAFE_FREE(data->uv);
+ MEM_SAFE_FREE(data->uvedges);
if (data->initial_stroke) {
- if (data->initial_stroke->initialSelection) {
- MEM_freeN(data->initial_stroke->initialSelection);
- }
- MEM_freeN(data->initial_stroke);
+ MEM_SAFE_FREE(data->initial_stroke->initialSelection);
+ MEM_SAFE_FREE(data->initial_stroke);
}
- MEM_freeN(data);
+ MEM_SAFE_FREE(data);
op->customdata = NULL;
}
@@ -441,7 +618,7 @@ static int uv_element_offset_from_face_get(
if (!element || (doIslands && element->island != island_index)) {
return -1;
}
- return element - map->buf;
+ return element - map->storage;
}
static uint uv_edge_hash(const void *key)
@@ -461,6 +638,17 @@ static bool uv_edge_compare(const void *a, const void *b)
return true;
}
+static void set_element_flag(UvElement *element, const int flag)
+{
+ while (element) {
+ element->flag |= flag;
+ element = element->next;
+ if (!element || element->separate) {
+ break;
+ }
+ }
+}
+
static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
@@ -475,7 +663,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
BKE_curvemapping_init(ts->uvsculpt->paint.brush->curve);
if (data) {
- int counter = 0, i;
ARegion *region = CTX_wm_region(C);
float co[2];
BMFace *efa;
@@ -489,8 +676,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
int island_index = 0;
- /* Holds, for each UvElement in elementMap, a pointer to its unique UV. */
- int *uniqueUv;
data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ?
UV_SCULPT_TOOL_RELAX :
ts->uvsculpt->paint.brush->uv_sculpt_tool;
@@ -498,23 +683,12 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
data->uvsculpt = &ts->uvsculpt->paint;
- if (do_island_optimization) {
- /* We will need island information */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, true);
- }
- else {
- data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, true);
- }
- }
- else {
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, false);
- }
- else {
- data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, false);
- }
- }
+ /* Winding was added to island detection in 5197aa04c6bd
+ * However the sculpt tools can flip faces, potentially creating orphaned islands.
+ * See T100132 */
+ bool use_winding = false;
+ data->elementMap = BM_uv_element_map_create(
+ bm, scene, false, use_winding, do_island_optimization);
if (!data->elementMap) {
uv_sculpt_stroke_exit(C, op);
@@ -535,27 +709,22 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
}
/* Count 'unique' UV's */
- for (i = 0; i < data->elementMap->totalUVs; i++) {
- if (data->elementMap->buf[i].separate &&
- (!do_island_optimization || data->elementMap->buf[i].island == island_index)) {
- counter++;
- }
+ int unique_uvs = data->elementMap->total_unique_uvs;
+ if (do_island_optimization) {
+ unique_uvs = data->elementMap->island_total_unique_uvs[island_index];
}
/* Allocate the unique uv buffers */
- data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs");
- uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs,
- "uv_brush_unique_uv_map");
+ data->uv = MEM_callocN(sizeof(*data->uv) * unique_uvs, "uv_brush_unique_uvs");
+ /* Holds, for each UvElement in elementMap, an index of its unique UV. */
+ int *uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->total_uvs,
+ "uv_brush_unique_uv_map");
edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
/* we have at most totalUVs edges */
- edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges");
+ edges = MEM_callocN(sizeof(*edges) * data->elementMap->total_uvs, "uv_brush_all_edges");
if (!data->uv || !uniqueUv || !edgeHash || !edges) {
- if (edges) {
- MEM_freeN(edges);
- }
- if (uniqueUv) {
- MEM_freeN(uniqueUv);
- }
+ MEM_SAFE_FREE(edges);
+ MEM_SAFE_FREE(uniqueUv);
if (edgeHash) {
BLI_ghash_free(edgeHash, NULL, NULL);
}
@@ -563,12 +732,12 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
return NULL;
}
- data->totalUniqueUvs = counter;
- /* So that we can use this as index for the UvElements */
- counter = -1;
+ data->totalUniqueUvs = unique_uvs;
+ /* Index for the UvElements. */
+ int counter = -1;
/* initialize the unique UVs */
- for (i = 0; i < bm->totvert; i++) {
- UvElement *element = data->elementMap->vert[i];
+ for (int i = 0; i < bm->totvert; i++) {
+ UvElement *element = data->elementMap->vertex[i];
for (; element; element = element->next) {
if (element->separate) {
if (do_island_optimization && (element->island != island_index)) {
@@ -584,13 +753,18 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
counter++;
data->uv[counter].element = element;
- data->uv[counter].flag = 0;
data->uv[counter].uv = luv->uv;
+ if (data->tool != UV_SCULPT_TOOL_GRAB) {
+ if (luv->flag & MLOOPUV_PINNED) {
+ data->uv[counter].is_locked = true;
+ }
+ }
}
/* Pointer arithmetic to the rescue, as always :). */
- uniqueUv[element - data->elementMap->buf] = counter;
+ uniqueUv[element - data->elementMap->storage] = counter;
}
}
+ BLI_assert(counter + 1 == unique_uvs);
/* Now, on to generate our uv connectivity data */
counter = 0;
@@ -600,7 +774,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
data->elementMap, efa, l, island_index, do_island_optimization);
int offset2, itmp2 = uv_element_offset_from_face_get(
data->elementMap, efa, l->next, island_index, do_island_optimization);
- char *flag;
/* Skip edge if not found(unlikely) or not on valid island */
if (itmp1 == -1 || itmp2 == -1) {
@@ -610,7 +783,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
offset1 = uniqueUv[itmp1];
offset2 = uniqueUv[itmp2];
- edges[counter].flag = 0;
/* Using an order policy, sort UV's according to address space.
* This avoids having two different UvEdges with the same UV's on different positions. */
if (offset1 < offset2) {
@@ -621,58 +793,65 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
edges[counter].uv1 = offset2;
edges[counter].uv2 = offset1;
}
- /* Hack! Set the value of the key to its flag.
- * Now we can set the flag when an edge exists twice :) */
- flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
- if (flag) {
- *flag = 1;
+ UvEdge *prev_edge = BLI_ghash_lookup(edgeHash, &edges[counter]);
+ if (prev_edge) {
+ prev_edge->is_interior = true;
+ edges[counter].is_interior = true;
}
else {
- /* Hack mentioned */
- BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
+ BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter]);
}
counter++;
}
}
- MEM_freeN(uniqueUv);
+ MEM_SAFE_FREE(uniqueUv);
/* Allocate connectivity data, we allocate edges once */
- data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash),
+ data->uvedges = MEM_callocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash),
"uv_brush_edge_connectivity_data");
if (!data->uvedges) {
BLI_ghash_free(edgeHash, NULL, NULL);
- MEM_freeN(edges);
+ MEM_SAFE_FREE(edges);
uv_sculpt_stroke_exit(C, op);
return NULL;
}
/* fill the edges with data */
- i = 0;
- GHASH_ITER (gh_iter, edgeHash) {
- data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
+ {
+ int i = 0;
+ GHASH_ITER (gh_iter, edgeHash) {
+ data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
+ }
+ data->totalUvEdges = BLI_ghash_len(edgeHash);
}
- data->totalUvEdges = BLI_ghash_len(edgeHash);
/* cleanup temporary stuff */
BLI_ghash_free(edgeHash, NULL, NULL);
- MEM_freeN(edges);
+ MEM_SAFE_FREE(edges);
/* transfer boundary edge property to UV's */
- if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) {
- for (i = 0; i < data->totalUvEdges; i++) {
- if (!data->uvedges[i].flag) {
- data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
- data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
+ for (int i = 0; i < data->totalUvEdges; i++) {
+ if (!data->uvedges[i].is_interior) {
+ data->uv[data->uvedges[i].uv1].is_boundary = true;
+ data->uv[data->uvedges[i].uv2].is_boundary = true;
+ if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) {
+ data->uv[data->uvedges[i].uv1].is_locked = true;
+ data->uv[data->uvedges[i].uv2].is_locked = true;
}
+ set_element_flag(data->uv[data->uvedges[i].uv1].element, MARK_BOUNDARY);
+ set_element_flag(data->uv[data->uvedges[i].uv2].element, MARK_BOUNDARY);
}
}
+ SpaceImage *sima = CTX_wm_space_image(C);
+ data->constrain_to_bounds = (sima->flag & SI_CLIP_UV);
+ BKE_image_find_nearest_tile_with_offset(sima->image, co, data->uv_base_offset);
+
/* Allocate initial selection for grab tool */
if (data->tool == UV_SCULPT_TOOL_GRAB) {
float radius, radius_root;
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
- SpaceImage *sima;
int width, height;
float aspectRatio;
float alpha, zoomx, zoomy;
@@ -681,7 +860,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
alpha = BKE_brush_alpha_get(scene, brush);
radius = BKE_brush_size_get(scene, brush);
- sima = CTX_wm_space_image(C);
ED_space_image_get_size(sima, &width, &height);
ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
@@ -706,16 +884,16 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
copy_v2_v2(data->initial_stroke->init_coord, co);
counter = 0;
-
- for (i = 0; i < data->totalUniqueUvs; i++) {
- float dist, diff[2];
- if (data->uv[i].flag & MARK_BOUNDARY) {
+ for (int i = 0; i < data->totalUniqueUvs; i++) {
+ if (data->uv[i].is_locked) {
continue;
}
+ float diff[2];
sub_v2_v2v2(diff, data->uv[i].uv, co);
diff[1] /= aspectRatio;
- if ((dist = dot_v2v2(diff, diff)) <= radius) {
+ float dist = dot_v2v2(diff, diff);
+ if (dist <= radius) {
float strength;
strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
@@ -727,6 +905,9 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
}
data->initial_stroke->totalInitialSelected = counter;
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_begin(scene, obedit);
+ }
}
}
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 2a8a2be8b65..08b795db0c3 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -340,7 +340,8 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
AUD_DeviceSpecs specs;
AUD_Container container;
AUD_Codec codec;
- const char *result;
+ int result;
+ char error_message[1024] = {'\0'};
sound_bake_animation_exec(C, op);
@@ -372,7 +373,9 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
codec,
bitrate,
NULL,
- NULL);
+ NULL,
+ error_message,
+ sizeof(error_message));
}
else {
result = AUD_mixdown(scene_eval->sound_scene,
@@ -385,13 +388,15 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
codec,
bitrate,
NULL,
- NULL);
+ NULL,
+ error_message,
+ sizeof(error_message));
}
BKE_sound_reset_scene_specs(scene_eval);
- if (result) {
- BKE_report(op->reports, RPT_ERROR, result);
+ if (!result) {
+ BKE_report(op->reports, RPT_ERROR, error_message);
return OPERATOR_CANCELLED;
}
#else /* WITH_AUDASPACE */
diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt
index 841bd5cf91b..b9e27c4de49 100644
--- a/source/blender/editors/space_action/CMakeLists.txt
+++ b/source/blender/editors/space_action/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 7bdf2478862..eb56c6c4b54 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -206,7 +206,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
@@ -617,7 +617,7 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene)
uint pos_id = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 87a271543d1..23c92cbdaa0 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -158,8 +158,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
/* get data to filter, from Action or Dopesheet */
/* XXX: what is sel doing here?!
* Commented it, was breaking things (eg. the "auto preview range" tool). */
- filter = (ANIMFILTER_DATA_VISIBLE |
- ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -178,10 +177,12 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
/* Find gp-frame which is less than or equal to current-frame. */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- const float framenum = (float)gpf->framenum;
- *min = min_ff(*min, framenum);
- *max = max_ff(*max, framenum);
- found = true;
+ if (!onlySel || (gpf->flag & GP_FRAME_SELECT)) {
+ const float framenum = (float)gpf->framenum;
+ *min = min_ff(*min, framenum);
+ *max = max_ff(*max, framenum);
+ found = true;
+ }
}
}
else if (ale->datatype == ALE_MASKLAY) {
@@ -498,7 +499,7 @@ static short copy_action_keys(bAnimContext *ac)
ANIM_fcurves_copybuf_free();
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -511,13 +512,13 @@ static short copy_action_keys(bAnimContext *ac)
return ok;
}
-static short paste_action_keys(bAnimContext *ac,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
- bool flip)
+static eKeyPasteError paste_action_keys(bAnimContext *ac,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
ListBase anim_data = {NULL, NULL};
- int filter, ok = 0;
+ int filter;
/* filter data
* - First time we try to filter more strictly, allowing only selected channels
@@ -525,15 +526,15 @@ static short paste_action_keys(bAnimContext *ac,
* - Second time, we loosen things up if nothing was found the first time, allowing
* users to just paste keyframes back into the original curve again T31670.
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
}
/* paste keyframes */
- ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
+ const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
/* clean up */
ANIM_animdata_freelist(&anim_data);
@@ -555,7 +556,8 @@ static int actkeys_copy_exec(bContext *C, wmOperator *op)
/* copy keyframes */
if (ac.datatype == ANIMCONT_GPENCIL) {
if (ED_gpencil_anim_copybuf_copy(&ac) == false) {
- /* Nothing got copied - An error about this should be been logged already */
+ /* check if anything ended up in the buffer */
+ BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
return OPERATOR_CANCELLED;
}
}
@@ -565,7 +567,11 @@ static int actkeys_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- if (copy_action_keys(&ac)) {
+ /* Both copy function needs to be evaluated to account for mixed selection */
+ const short kf_empty = copy_action_keys(&ac);
+ const bool gpf_ok = ED_gpencil_anim_copybuf_copy(&ac);
+
+ if (kf_empty && !gpf_ok) {
BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
return OPERATOR_CANCELLED;
}
@@ -597,6 +603,8 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
const bool flipped = RNA_boolean_get(op->ptr, "flipped");
+ bool gpframes_inbuf = false;
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
@@ -608,7 +616,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
/* paste keyframes */
if (ac.datatype == ANIMCONT_GPENCIL) {
if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false) {
- /* An error occurred - Reports should have been fired already */
+ BKE_report(op->reports, RPT_ERROR, "No data in buffer to paste");
return OPERATOR_CANCELLED;
}
}
@@ -620,14 +628,31 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
+ /* Both paste function needs to be evaluated to account for mixed selection */
+ const eKeyPasteError kf_empty = paste_action_keys(&ac, offset_mode, merge_mode, flipped);
/* non-zero return means an error occurred while trying to paste */
- if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) {
- return OPERATOR_CANCELLED;
+ gpframes_inbuf = ED_gpencil_anim_copybuf_paste(&ac, offset_mode);
+
+ /* Only report an error if nothing was pasted, i.e. when both FCurve and GPencil failed. */
+ if (!gpframes_inbuf) {
+ switch (kf_empty) {
+ case KEYFRAME_PASTE_OK:
+ /* FCurve paste was ok, so it's all good. */
+ break;
+
+ case KEYFRAME_PASTE_NOWHERE_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
+ return OPERATOR_CANCELLED;
+
+ case KEYFRAME_PASTE_NOTHING_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No data in buffer to paste");
+ return OPERATOR_CANCELLED;
+ }
}
}
/* Grease Pencil needs extra update to refresh the added keyframes. */
- if (ac.datatype == ANIMCONT_GPENCIL) {
+ if (ac.datatype == ANIMCONT_GPENCIL || gpframes_inbuf) {
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
}
/* set notifier that keyframes have changed */
@@ -697,94 +722,86 @@ static const EnumPropertyItem prop_actkeys_insertkey_types[] = {
{0, NULL, 0, NULL, NULL},
};
-/* this function is responsible for inserting new keyframes */
-static void insert_action_keys(bAnimContext *ac, short mode)
+static void insert_gpencil_key(bAnimContext *ac,
+ bAnimListElem *ale,
+ const eGP_GetFrame_Mode add_frame_mode,
+ bGPdata **gpd_old)
{
- ListBase anim_data = {NULL, NULL};
- ListBase nla_cache = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
+ Scene *scene = ac->scene;
+ bGPdata *gpd = (bGPdata *)ale->id;
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
+ /* Check if the gpd changes to tag only once. */
+ if (gpd != *gpd_old) {
+ BKE_gpencil_tag(gpd);
+ *gpd_old = gpd;
+ }
+}
+
+static void insert_fcurve_key(bAnimContext *ac,
+ bAnimListElem *ale,
+ const AnimationEvalContext anim_eval_context,
+ eInsertKeyFlags flag,
+ ListBase *nla_cache)
+{
+ FCurve *fcu = (FCurve *)ale->key_data;
ReportList *reports = ac->reports;
Scene *scene = ac->scene;
ToolSettings *ts = scene->toolsettings;
- eInsertKeyFlags flag;
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- if (mode == 2) {
- filter |= ANIMFILTER_SEL;
- }
- else if (mode == 3) {
- filter |= ANIMFILTER_ACTGROUPED;
+ /* Read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL:
+ * Typically, this means that we have enough info to try resolving the path.
+ *
+ * - ale->owner != NULL:
+ * If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner) {
+ insert_keyframe(ac->bmain,
+ reports,
+ ale->id,
+ NULL,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ &anim_eval_context,
+ ts->keyframe_type,
+ nla_cache,
+ flag);
}
+ else {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* Init keyframing flag. */
- flag = ANIM_get_keyframing_flags(scene, true);
-
- /* insert keyframes */
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(ac->depsgraph,
- (float)CFRA);
- for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* Read value from property the F-Curve represents, or from the curve only?
- * - ale->id != NULL:
- * Typically, this means that we have enough info to try resolving the path.
- *
- * - ale->owner != NULL:
- * If this is set, then the path may not be resolvable from the ID alone,
- * so it's easier for now to just read the F-Curve directly.
- * (TODO: add the full-blown PointerRNA relative parsing case here...)
- */
- if (ale->id && !ale->owner) {
- insert_keyframe(ac->bmain,
- reports,
- ale->id,
- NULL,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- &anim_eval_context,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
- else {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-
- /* adjust current frame for NLA-scaling */
- float cfra = anim_eval_context.eval_time;
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
- }
-
- const float curval = evaluate_fcurve(fcu, cfra);
- insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ /* adjust current frame for NLA-scaling */
+ float cfra = anim_eval_context.eval_time;
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
}
- ale->update |= ANIM_UPDATE_DEFAULT;
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
}
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-/* this function is for inserting new grease pencil frames */
-static void insert_gpencil_keys(bAnimContext *ac, short mode)
+/* this function is responsible for inserting new keyframes */
+static void insert_action_keys(bAnimContext *ac, short mode)
{
ListBase anim_data = {NULL, NULL};
+ ListBase nla_cache = {NULL, NULL};
bAnimListElem *ale;
int filter;
Scene *scene = ac->scene;
ToolSettings *ts = scene->toolsettings;
+ eInsertKeyFlags flag;
+
eGP_GetFrame_Mode add_frame_mode;
+ bGPdata *gpd_old = NULL;
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
@@ -792,30 +809,43 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode)
if (mode == 2) {
filter |= ANIMFILTER_SEL;
}
+ else if (mode == 3) {
+ filter |= ANIMFILTER_ACTGROUPED;
+ }
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* add a copy or a blank frame? */
+ /* Init keyframing flag. */
+ flag = ANIM_get_keyframing_flags(scene, true);
+
+ /* GPLayers specific flags */
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- add_frame_mode = GP_GETFRAME_ADD_COPY; /* XXX: actframe may not be what we want? */
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
}
else {
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- /* Insert gp frames. */
- bGPdata *gpd_old = NULL;
+ /* insert keyframes */
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ ac->depsgraph, (float)scene->r.cfra);
for (ale = anim_data.first; ale; ale = ale->next) {
- bGPdata *gpd = (bGPdata *)ale->id;
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
- /* Check if the gpd changes to tag only once. */
- if (gpd != gpd_old) {
- BKE_gpencil_tag(gpd);
- gpd_old = gpd;
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ insert_gpencil_key(ac, ale, add_frame_mode, &gpd_old);
+ break;
+
+ case ANIMTYPE_FCURVE:
+ insert_fcurve_key(ac, ale, anim_eval_context, flag, &nla_cache);
+ break;
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be inserted into this animation type.");
}
}
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
+
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -841,12 +871,7 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
mode = RNA_enum_get(op->ptr, "type");
/* insert keyframes */
- if (ac.datatype == ANIMCONT_GPENCIL) {
- insert_gpencil_keys(&ac, mode);
- }
- else {
- insert_action_keys(&ac, mode);
- }
+ insert_action_keys(&ac, mode);
/* set notifier that keyframes have changed */
if (ac.datatype == ANIMCONT_GPENCIL) {
@@ -886,14 +911,8 @@ static bool duplicate_action_keys(bAnimContext *ac)
bool changed = false;
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and delete selected keys */
@@ -968,14 +987,8 @@ static bool delete_action_keys(bAnimContext *ac)
bool changed_final = false;
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and delete selected keys */
@@ -993,7 +1006,7 @@ static bool delete_action_keys(bAnimContext *ac)
AnimData *adt = ale->adt;
/* delete selected keyframes only */
- changed = delete_fcurve_keys(fcu);
+ changed = BKE_fcurve_delete_keys_selected(fcu);
/* Only delete curve too if it won't be doing anything anymore */
if (BKE_fcurve_is_empty(fcu)) {
@@ -1063,7 +1076,7 @@ static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_SEL | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and clean curves */
@@ -1139,8 +1152,8 @@ static void sample_action_keys(bAnimContext *ac)
int filter;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -1238,7 +1251,7 @@ static void setexpo_action_keys(bAnimContext *ac, short mode)
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_SEL | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through setting mode per F-Curve */
@@ -1352,7 +1365,8 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op)
/* set handle type */
ANIM_animdata_keyframe_callback(&ac,
(ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS),
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY),
ANIM_editkeyframes_ipo(mode));
/* set notifier that keyframe properties have changed */
@@ -1401,7 +1415,8 @@ static int actkeys_easing_exec(bContext *C, wmOperator *op)
/* set handle type */
ANIM_animdata_keyframe_callback(&ac,
(ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS),
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY),
ANIM_editkeyframes_easing(mode));
/* set notifier that keyframe properties have changed */
@@ -1444,8 +1459,8 @@ static void sethandles_action_keys(bAnimContext *ac, short mode)
KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting flags for handles
@@ -1458,7 +1473,7 @@ static void sethandles_action_keys(bAnimContext *ac, short mode)
/* any selected keyframes for editing? */
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
/* change type of selected handles */
- ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1527,8 +1542,8 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
KeyframeEditFunc set_cb = ANIM_editkeyframes_keytype(mode);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting BezTriple interpolation
@@ -1536,32 +1551,19 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
* Currently that's not necessary here.
*/
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
-
- ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
- }
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* this function is responsible for setting the keyframe type for Grease Pencil frames */
-static void setkeytype_gpencil_keys(bAnimContext *ac, short mode)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ ED_gpencil_layer_frames_keytype_set(ale->data, mode);
+ ale->update |= ANIM_UPDATE_DEPS;
+ break;
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ case ANIMTYPE_FCURVE:
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
+ ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
+ break;
- /* loop through each layer */
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_layer_frames_keytype_set(ale->data, mode);
- ale->update |= ANIM_UPDATE_DEPS;
+ default:
+ BLI_assert_msg(false, "Keytype cannot be set into this animation type.");
}
}
@@ -1590,12 +1592,7 @@ static int actkeys_keytype_exec(bContext *C, wmOperator *op)
mode = RNA_enum_get(op->ptr, "type");
/* set handle type */
- if (ac.datatype == ANIMCONT_GPENCIL) {
- setkeytype_gpencil_keys(&ac, mode);
- }
- else {
- setkeytype_action_keys(&ac, mode);
- }
+ setkeytype_action_keys(&ac, mode);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1653,19 +1650,44 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
/* init edit data */
/* loop over action data, averaging values */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
- }
- else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
+ switch (ale->datatype) {
+ case ALE_GPFRAME: {
+ bGPDlayer *gpl = ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* only if selected */
+ if (!(gpf->flag & GP_FRAME_SELECT)) {
+ continue;
+ }
+ /* store average time in float 1 (only do rounding at last step) */
+ ked.f1 += gpf->framenum;
+
+ /* increment number of items */
+ ked.i1++;
+ }
+ break;
+ }
+
+ case ALE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
+ }
+ break;
+ }
+
+ default:
+ BLI_assert_msg(false, "Cannot jump to keyframe into this animation type.");
}
}
@@ -1674,8 +1696,8 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
/* set the new current frame value, based on the average time */
if (ked.i1) {
Scene *scene = ac.scene;
- CFRA = round_fl_to_int(ked.f1 / ked.i1);
- SUBFRA = 0.0f;
+ scene->r.cfra = round_fl_to_int(ked.f1 / ked.i1);
+ scene->r.subframe = 0.0f;
}
/* set notifier that things have changed */
@@ -1742,8 +1764,8 @@ static void snap_action_keys(bAnimContext *ac, short mode)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
}
else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
}
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -1768,11 +1790,11 @@ static void snap_action_keys(bAnimContext *ac, short mode)
}
else if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -1876,14 +1898,8 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
}
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* mirror keyframes */
@@ -1898,11 +1914,11 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
}
else if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index aff888818e0..ed9d86e1a4e 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -235,13 +235,7 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
KeyframeEditFunc test_cb, sel_cb;
/* determine type-based settings */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
- ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -416,7 +410,7 @@ static void box_select_elem(
break;
}
- if (ale->type == ANIMTYPE_SUMMARY && ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ale->type == ANIMTYPE_SUMMARY) {
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
@@ -428,8 +422,10 @@ static void box_select_elem(
ANIM_animdata_freelist(&anim_data);
}
- ANIM_animchannel_keyframes_loop(
- &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ ANIM_animchannel_keyframes_loop(
+ &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ }
}
}
}
@@ -658,7 +654,7 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
break;
}
- if (ale->type == ANIMTYPE_SUMMARY && ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ale->type == ANIMTYPE_SUMMARY) {
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
@@ -670,8 +666,10 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
ANIM_animdata_freelist(&anim_data);
}
- ANIM_animchannel_keyframes_loop(
- &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ ANIM_animchannel_keyframes_loop(
+ &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ }
}
}
}
@@ -921,7 +919,7 @@ static const EnumPropertyItem prop_column_select_types[] = {
/* ------------------- */
/* Selects all visible keyframes between the specified markers */
-/* TODO(campbell): this is almost an _exact_ duplicate of a function of the same name in
+/* TODO(@campbellbarton): this is almost an _exact_ duplicate of a function of the same name in
* graph_select.c should de-duplicate. */
static void markers_selectkeys_between(bAnimContext *ac)
{
@@ -946,28 +944,36 @@ static void markers_selectkeys_between(bAnimContext *ac)
ked.f2 = max;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys in-between */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ ED_gpencil_layer_frames_select_box(ale->data, min, max, SELECT_ADD);
+ ale->update |= ANIM_UPDATE_DEPS;
+ break;
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
- }
- else if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_layer_frames_select_box(ale->data, min, max, SELECT_ADD);
- ale->update |= ANIM_UPDATE_DEPS;
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD);
- }
- else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ case ANIMTYPE_MASKLAYER:
+ ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD);
+ break;
+
+ case ANIMTYPE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
+ break;
+ }
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
}
}
@@ -1000,11 +1006,16 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
}
}
else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
+ if (ale->datatype == ALE_GPFRAME) {
+ ED_gpencil_layer_make_cfra_list(ale->data, &ked.list, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
+ }
}
}
ANIM_animdata_freelist(&anim_data);
@@ -1015,7 +1026,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
BLI_addtail(&ked.list, ce);
- ce->cfra = (float)CFRA;
+ ce->cfra = (float)scene->r.cfra;
break;
case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
@@ -1033,12 +1044,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1144,7 +1150,7 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1200,7 +1206,7 @@ static void select_moreless_action_keys(bAnimContext *ac, short mode)
build_cb = ANIM_editkeyframes_buildselmap(mode);
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -1346,41 +1352,44 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
if (leftright == ACTKEYS_LRSEL_LEFT) {
ked.f1 = MINAFRAMEF;
- ked.f2 = (float)(CFRA + 0.1f);
+ ked.f2 = (float)(scene->r.cfra + 0.1f);
}
else {
- ked.f1 = (float)(CFRA - 0.1f);
+ ked.f1 = (float)(scene->r.cfra - 0.1f);
ked.f2 = MAXFRAMEF;
}
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
- ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ ED_gpencil_layer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
+ break;
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
- }
- else if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_layer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
- ale->update |= ANIM_UPDATE_DEPS;
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
- }
- else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ case ANIMTYPE_MASKLAYER:
+ ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
+ break;
+
+ case ANIMTYPE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
+ break;
+ }
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
}
}
@@ -1393,8 +1402,8 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
TimeMarker *marker;
for (marker = markers->first; marker; marker = marker->next) {
- if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < CFRA)) ||
- ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= CFRA))) {
+ if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < scene->r.cfra)) ||
+ ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= scene->r.cfra))) {
marker->flag |= SELECT;
}
else {
@@ -1464,7 +1473,7 @@ static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wm
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
- if (x < CFRA) {
+ if (x < scene->r.cfra) {
RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT);
}
else {
@@ -1539,29 +1548,29 @@ static void actkeys_mselect_single(bAnimContext *ac,
ED_mask_select_frame(ale->data, selx, select_mode);
}
else {
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) &&
- (ale->datatype == ALE_ALL)) {
+ if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
ListBase anim_data = {NULL, NULL};
int filter;
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_select_frame(ale->data, selx, select_mode);
- ale->update |= ANIM_UPDATE_DEPS;
+ /* Loop over all keys that are represented by this summary key. */
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
+ if (ale2->type == ANIMTYPE_GPLAYER) {
+ ED_gpencil_select_frame(ale2->data, selx, select_mode);
+ ale2->update |= ANIM_UPDATE_DEPS;
}
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_mask_select_frame(ale->data, selx, select_mode);
+ else if (ale2->type == ANIMTYPE_MASKLAYER) {
+ ED_mask_select_frame(ale2->data, selx, select_mode);
}
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
- else {
+
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
}
}
@@ -1588,35 +1597,29 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-
- /* set frame for validation callback to refer to */
- if (adt) {
- ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
- }
- else {
- ked.f1 = selx;
- }
-
/* select elements with frame number matching cfra */
if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_select_frame(ale->key_data, selx, select_mode);
+ ED_gpencil_select_frame(ale->data, selx, select_mode);
ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_mask_select_frame(ale->key_data, selx, select_mode);
+ ED_mask_select_frame(ale->data, selx, select_mode);
}
else {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* set frame for validation callback to refer to */
+ if (adt) {
+ ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.f1 = selx;
+ }
+
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
}
}
@@ -1645,29 +1648,28 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
ED_mask_select_frames(ale->data, select_mode);
}
else {
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) &&
- (ale->datatype == ALE_ALL)) {
+ if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
ListBase anim_data = {NULL, NULL};
int filter;
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_select_frames(ale->data, select_mode);
- ale->update |= ANIM_UPDATE_DEPS;
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
+ if (ale2->type == ANIMTYPE_GPLAYER) {
+ ED_gpencil_select_frames(ale2->data, select_mode);
+ ale2->update |= ANIM_UPDATE_DEPS;
}
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_mask_select_frames(ale->data, select_mode);
+ else if (ale2->type == ANIMTYPE_MASKLAYER) {
+ ED_mask_select_frames(ale2->data, select_mode);
}
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
- else {
+
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
ANIM_animchannel_keyframes_loop(NULL, ac->ads, ale, NULL, select_cb, NULL);
}
}
@@ -1734,6 +1736,12 @@ static int mouse_action_keys(bAnimContext *ac,
fcu->flag |= FCURVE_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
}
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
+ bGPDlayer *gpl = ale->data;
+
+ ED_gpencil_set_active_channel(gpd, gpl);
+ }
}
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
@@ -1745,13 +1753,7 @@ static int mouse_action_keys(bAnimContext *ac,
bGPdata *gpd = (bGPdata *)ale->id;
bGPDlayer *gpl = ale->data;
- gpl->flag |= GP_LAYER_SELECT;
- /* Update other layer status. */
- if (BKE_gpencil_layer_active_get(gpd) != gpl) {
- BKE_gpencil_layer_active_set(gpd, gpl);
- BKE_gpencil_layer_autolock_set(gpd, false);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
+ ED_gpencil_set_active_channel(gpd, gpl);
}
}
else if (ac->datatype == ANIMCONT_MASK) {
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 09163842587..fc0588dbab5 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -90,7 +90,6 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
BLI_addtail(&saction->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
- region->flag = RGN_FLAG_HIDDEN;
/* main region */
region = MEM_callocN(sizeof(ARegion), "main region for action");
@@ -98,9 +97,9 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
BLI_addtail(&saction->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
- region->v2d.tot.xmin = (float)(SFRA - 10);
+ region->v2d.tot.xmin = (float)(scene->r.sfra - 10);
region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
- region->v2d.tot.xmax = (float)(EFRA + 10);
+ region->v2d.tot.xmax = (float)(scene->r.efra + 10);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -308,7 +307,7 @@ static void action_header_region_draw(const bContext *C, ARegion *region)
static void action_channel_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -402,7 +401,7 @@ static void saction_channel_region_message_subscribe(const wmRegionMessageSubscr
static void action_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -500,14 +499,14 @@ static void saction_main_region_message_subscribe(const wmRegionMessageSubscribe
static void action_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- /* only handle these events in GPencil mode for performance considerations */
- if (saction->mode == SACTCONT_GPENCIL) {
+ /* only handle these events for containers in which GPencil frames are displayed */
+ if (ELEM(saction->mode, SACTCONT_GPENCIL, SACTCONT_DOPESHEET, SACTCONT_TIMELINE)) {
if (wmn->action == NA_EDITED) {
ED_area_tag_redraw(area);
}
@@ -561,8 +560,8 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
Scene *scene = wmn->reference;
- region->v2d.tot.xmin = (float)(SFRA - 4);
- region->v2d.tot.xmax = (float)(EFRA + 4);
+ region->v2d.tot.xmin = (float)(scene->r.sfra - 4);
+ region->v2d.tot.xmax = (float)(scene->r.efra + 4);
break;
}
}
@@ -654,7 +653,7 @@ static void action_header_region_listener(const wmRegionListenerParams *params)
{
ScrArea *area = params->area;
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
@@ -729,7 +728,7 @@ static void action_buttons_area_draw(const bContext *C, ARegion *region)
static void action_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index d53fe2efb03..3d964a95bc0 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -163,6 +163,7 @@ void ED_spacemacros_init(void)
ED_operatormacros_sequencer();
ED_operatormacros_paint();
ED_operatormacros_gpencil();
+ ED_operatormacros_nla();
/* Register dropboxes (can use macros). */
ED_dropboxes_ui();
diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt
index e2f1df74446..d0ad510f5cf 100644
--- a/source/blender/editors/space_buttons/CMakeLists.txt
+++ b/source/blender/editors/space_buttons/CMakeLists.txt
@@ -9,8 +9,8 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
+ ../../bmesh
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
@@ -35,7 +35,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
add_definitions(-DWITH_POINT_CLOUD)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
endif()
blender_add_lib(bf_editor_space_buttons "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 5780b0c9df7..5f535cbccd1 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -258,11 +258,9 @@ static bool buttons_context_path_data(ButsContextPath *path, int type)
if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (ELEM(type, -1, OB_GPENCIL))) {
return true;
}
-#ifdef WITH_NEW_CURVES_TYPE
if (RNA_struct_is_a(ptr->type, &RNA_Curves) && (ELEM(type, -1, OB_CURVES))) {
return true;
}
-#endif
#ifdef WITH_POINT_CLOUD
if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (ELEM(type, -1, OB_POINTCLOUD))) {
return true;
@@ -645,7 +643,7 @@ static bool buttons_shading_context(const bContext *C, int mainb)
{
wmWindow *window = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE)) {
return true;
@@ -661,7 +659,7 @@ static int buttons_shading_new_context(const bContext *C, int flag)
{
wmWindow *window = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (flag & (1 << BCONTEXT_MATERIAL)) {
return BCONTEXT_MATERIAL;
@@ -830,9 +828,7 @@ const char *buttons_context_dir[] = {
"line_style",
"collection",
"gpencil",
-#ifdef WITH_NEW_CURVES_TYPE
"curves",
-#endif
#ifdef WITH_POINT_CLOUD
"pointcloud",
#endif
@@ -926,12 +922,10 @@ int /*eContextResult*/ buttons_context(const bContext *C,
set_pointer_type(path, result, &RNA_LightProbe);
return CTX_RESULT_OK;
}
-#ifdef WITH_NEW_CURVES_TYPE
if (CTX_data_equals(member, "curves")) {
set_pointer_type(path, result, &RNA_Curves);
return CTX_RESULT_OK;
}
-#endif
#ifdef WITH_POINT_CLOUD
if (CTX_data_equals(member, "pointcloud")) {
set_pointer_type(path, result, &RNA_PointCloud);
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index a5cb9170f98..46692d29094 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -281,7 +281,7 @@ static void buttons_texture_users_from_context(ListBase *users,
brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
linestyle = BKE_linestyle_active_from_view_layer(view_layer);
- ob = OBACT(view_layer);
+ ob = BKE_view_layer_active_object_get(view_layer);
}
/* fill users */
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 052af39319c..2bee60557b7 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -507,7 +507,7 @@ static void buttons_main_region_layout(const bContext *C, ARegion *region)
static void buttons_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -645,7 +645,7 @@ static void buttons_area_redraw(ScrArea *area, short buttons)
static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
SpaceProperties *sbuts = area->spacedata.first;
/* context changes */
@@ -778,6 +778,9 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
sbuts->preview = 1;
}
break;
+ case NC_WORKSPACE:
+ buttons_area_redraw(area, BCONTEXT_TOOL);
+ break;
case NC_SPACE:
if (wmn->data == ND_SPACE_PROPERTIES) {
ED_area_tag_redraw(area);
@@ -975,8 +978,7 @@ void ED_spacetype_buttons(void)
/* regions: navigation bar */
art = MEM_callocN(sizeof(ARegionType), "spacetype nav buttons region");
art->regionid = RGN_TYPE_NAV_BAR;
- art->prefsizex = AREAMINX - 3; /* XXX Works and looks best,
- * should we update AREAMINX accordingly? */
+ art->prefsizex = AREAMINX;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_NAVBAR;
art->init = buttons_navigation_bar_region_init;
art->draw = buttons_navigation_bar_region_draw;
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index eddf1780d8b..8cb5299df6d 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -13,7 +13,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# dna_type_offsets.h
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index 858fa229992..8f876f6a8a3 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -111,7 +111,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *region, Scene *scene)
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
@@ -313,7 +313,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *region)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
MovieTrackingDopesheetChannel *channel;
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 7800ce797aa..b9bd97260ef 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -131,7 +131,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip
{
float x;
int *points, totseg, i, a;
- float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *act_object = BKE_tracking_object_get_active(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
@@ -149,7 +149,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* track */
if (act_track || act_plane_track) {
@@ -241,18 +241,20 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip
ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_DPI_FAC);
pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* solver keyframes */
immUniformColor4ub(175, 255, 0, 255);
- draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos);
- draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos);
+ draw_keyframe(
+ act_object->keyframe1 + clip->start_frame - 1, scene->r.cfra, sfra, framelen, 2, pos);
+ draw_keyframe(
+ act_object->keyframe2 + clip->start_frame - 1, scene->r.cfra, sfra, framelen, 2, pos);
immUnbindProgram();
/* movie clip animation */
if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) {
- ED_mask_draw_frames(sc->mask_info.mask, region, CFRA, sfra, efra);
+ ED_mask_draw_frames(sc->mask_info.mask, region, scene->r.cfra, sfra, efra);
}
}
@@ -284,7 +286,7 @@ static void draw_movieclip_muted(ARegion *region, int width, int height, float z
int x, y;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &x, &y);
@@ -362,7 +364,7 @@ static void draw_stabilization_border(
GPU_matrix_scale_2f(zoomx, zoomy);
GPU_matrix_mul(sc->stabmat);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -519,7 +521,7 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
const uint position_attribute = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw path outline. */
if (!tiny) {
@@ -736,7 +738,7 @@ static void draw_marker_areas(SpaceClip *sc,
* just always go with dashed shader. */
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -863,7 +865,7 @@ static void draw_marker_areas(SpaceClip *sc,
BLI_assert(pos == shdr_pos);
UNUSED_VARS_NDEBUG(pos);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
static float get_shortest_pattern_side(MovieTrackingMarker *marker)
@@ -1175,17 +1177,9 @@ static void draw_plane_marker_image(Scene *scene,
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
if (ibuf) {
- uchar *display_buffer;
void *cache_handle;
-
- if (image->flag & IMA_VIEW_AS_RENDER) {
- display_buffer = IMB_display_buffer_acquire(
- ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
- }
- else {
- display_buffer = IMB_display_buffer_acquire(
- ibuf, NULL, &scene->display_settings, &cache_handle);
- }
+ uchar *display_buffer = IMB_display_buffer_acquire(
+ ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
if (display_buffer) {
float frame_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
@@ -1216,10 +1210,10 @@ static void draw_plane_marker_image(Scene *scene,
imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
/* Use 3D image for correct display of planar tracked images. */
- immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR);
immBindTexture("image", texture);
- immUniform1f("alpha", plane_track->image_opacity);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, plane_track->image_opacity);
immBegin(GPU_PRIM_TRI_FAN, 4);
@@ -1284,7 +1278,7 @@ static void draw_plane_marker_ex(SpaceClip *sc,
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1364,7 +1358,7 @@ static void draw_plane_marker_ex(SpaceClip *sc,
/* Draw sliders. */
if (is_selected_track) {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (draw_outline) {
immUniformThemeColor(TH_MARKER_OUTLINE);
@@ -1531,7 +1525,7 @@ static void draw_tracking_tracks(SpaceClip *sc,
uint position = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* markers outline and non-selected areas */
track = tracksbase->first;
@@ -1726,7 +1720,7 @@ static void draw_distortion(SpaceClip *sc,
uint position = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* grid */
if (sc->flag & SC_SHOW_GRID) {
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 0b4eec4a835..9a690f36aab 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -102,6 +102,16 @@ bool ED_space_clip_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_clip_maskedit_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_clip_maskedit_poll(C)) {
+ return false;
+ }
+
+ const SpaceClip *space_clip = CTX_wm_space_clip(C);
+ return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_clip_maskedit_mask_poll(bContext *C)
{
if (ED_space_clip_maskedit_poll(C)) {
@@ -117,6 +127,16 @@ bool ED_space_clip_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_space_clip_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_clip_maskedit_mask_poll(C)) {
+ return false;
+ }
+
+ const SpaceClip *space_clip = CTX_wm_space_clip(C);
+ return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1026,7 +1046,7 @@ static int prefetch_get_start_frame(const bContext *C)
{
Scene *scene = CTX_data_scene(C);
- return SFRA;
+ return scene->r.sfra;
}
static int prefetch_get_final_frame(const bContext *C)
@@ -1037,10 +1057,10 @@ static int prefetch_get_final_frame(const bContext *C)
int end_frame;
/* check whether all the frames from prefetch range are cached */
- end_frame = EFRA;
+ end_frame = scene->r.efra;
if (clip->len) {
- end_frame = min_ii(end_frame, SFRA + clip->len - 1);
+ end_frame = min_ii(end_frame, scene->r.sfra + clip->len - 1);
}
return end_frame;
diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c
index 7236e7bcee0..5e3171d03c9 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -259,7 +259,7 @@ void clip_draw_graph(SpaceClip *sc, ARegion *region, Scene *scene)
if (clip) {
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_point_size(3.0f);
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index d07cf09ffa6..67565a88bab 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -629,8 +629,8 @@ static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
NULL);
/* set extents of view to start/end frames */
- v2d->cur.xmin = (float)SFRA;
- v2d->cur.xmax = (float)EFRA;
+ v2d->cur.xmin = (float)scene->r.sfra;
+ v2d->cur.xmax = (float)scene->r.efra;
if (userdata.min < userdata.max) {
v2d->cur.ymin = userdata.min;
@@ -675,8 +675,8 @@ void ED_clip_graph_center_current_frame(Scene *scene, ARegion *region)
float extra = BLI_rctf_size_x(&v2d->cur) / 2.0f;
/* set extents of view to start/end frames */
- v2d->cur.xmin = (float)CFRA - extra;
- v2d->cur.xmax = (float)CFRA + extra;
+ v2d->cur.xmin = (float)scene->r.cfra - extra;
+ v2d->cur.xmax = (float)scene->r.cfra + extra;
}
static int center_current_frame_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 7f9cf61b748..2efd6b6b473 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -251,6 +251,9 @@ void CLIP_OT_slide_plane_marker(struct wmOperatorType *ot);
void CLIP_OT_keyframe_insert(struct wmOperatorType *ot);
void CLIP_OT_keyframe_delete(struct wmOperatorType *ot);
+void CLIP_OT_new_image_from_plane_marker(struct wmOperatorType *ot);
+void CLIP_OT_update_image_from_plane_marker(struct wmOperatorType *ot);
+
/* tracking_select.c */
void CLIP_OT_select(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index f5bf850791a..f276c2acd1a 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1061,9 +1061,9 @@ static void change_frame_apply(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
/* set the new frame number */
- CFRA = RNA_int_get(op->ptr, "frame");
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
+ scene->r.cfra = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
+ scene->r.subframe = 0.0f;
/* do updates */
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
@@ -1084,7 +1084,7 @@ static int frame_from_event(bContext *C, const wmEvent *event)
int framenr = 0;
if (region->regiontype == RGN_TYPE_WINDOW) {
- float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
framenr = sfra + event->mval[0] / framelen;
}
@@ -1399,7 +1399,7 @@ static void do_sequence_proxy(void *pjv,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
- int sfra = SFRA, efra = EFRA;
+ int sfra = scene->r.sfra, efra = scene->r.efra;
ProxyThread *handles;
int tot_thread = BLI_task_scheduler_num_threads();
int width, height;
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 01f2b24c8a4..04b87cb4c83 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -614,11 +614,11 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)scene->r.sfra, v2d->cur.ymax);
+ immRectf(pos, (float)scene->r.efra, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
GPU_blend(GPU_BLEND_NONE);
@@ -628,10 +628,10 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
GPU_line_width(1.0f);
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymax);
immEnd();
immUnbindProgram();
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 5f52e1a3071..f8bf1893d89 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -314,7 +314,7 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
static void clip_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
const Scene *scene = params->scene;
/* context changes */
@@ -515,6 +515,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_keyframe_insert);
WM_operatortype_append(CLIP_OT_keyframe_delete);
+ WM_operatortype_append(CLIP_OT_new_image_from_plane_marker);
+ WM_operatortype_append(CLIP_OT_update_image_from_plane_marker);
+
/* ** clip_graph_ops.c ** */
/* graph editing */
@@ -808,8 +811,8 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
int width, height;
bool show_cursor = false;
- /* if tracking is in progress, we should synchronize framenr from clipuser
- * so latest tracked frame would be shown */
+ /* If tracking is in progress, we should synchronize the frame from the clip-user
+ * (#MovieClipUser.framenr) so latest tracked frame would be shown. */
if (clip && clip->tracking_context) {
BKE_autotrack_context_sync_user(clip->tracking_context, &sc->user);
}
@@ -860,6 +863,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
sc->mask_info.draw_flag,
sc->mask_info.draw_type,
sc->mask_info.overlay_mode,
+ sc->mask_info.blend_factor,
mask_width,
mask_height,
aspx,
@@ -915,7 +919,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
static void clip_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -1114,7 +1118,7 @@ static void clip_header_region_draw(const bContext *C, ARegion *region)
static void clip_header_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -1156,7 +1160,7 @@ static void clip_tools_region_draw(const bContext *C, ARegion *region)
static void clip_props_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -1208,7 +1212,7 @@ static void clip_properties_region_draw(const bContext *C, ARegion *region)
static void clip_properties_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index ca224b04da5..cba4157d044 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -16,6 +16,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_movieclip.h"
#include "BKE_report.h"
#include "BKE_tracking.h"
@@ -33,6 +34,9 @@
#include "BLT_translation.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "clip_intern.h"
#include "tracking_ops_intern.h"
@@ -1267,7 +1271,8 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
}
delta = pos == 1 ? 1 : -1;
- while (sc->user.framenr + delta >= SFRA && sc->user.framenr + delta <= EFRA) {
+ while (sc->user.framenr + delta >= scene->r.sfra &&
+ sc->user.framenr + delta <= scene->r.efra) {
int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr + delta);
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
@@ -1286,7 +1291,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
delta = pos == 3 ? 1 : -1;
framenr += delta;
- while (framenr + delta >= SFRA && framenr + delta <= EFRA) {
+ while (framenr + delta >= scene->r.sfra && framenr + delta <= scene->r.efra) {
MovieReconstructedCamera *cam = BKE_tracking_camera_get_reconstructed(
tracking, object, framenr);
@@ -1300,8 +1305,8 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
}
}
- if (CFRA != sc->user.framenr) {
- CFRA = sc->user.framenr;
+ if (scene->r.cfra != sc->user.framenr) {
+ scene->r.cfra = sc->user.framenr;
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2212,3 +2217,144 @@ void CLIP_OT_keyframe_delete(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image from plane track marker
+ * \{ */
+
+static ImBuf *sample_plane_marker_image_for_operator(bContext *C)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ const int clip_frame_number = ED_space_clip_get_clip_frame_number(space_clip);
+
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = tracking->act_plane_track;
+ const MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
+ clip_frame_number);
+
+ ImBuf *frame_ibuf = ED_space_clip_get_buffer(space_clip);
+ if (frame_ibuf == NULL) {
+ return NULL;
+ }
+
+ ImBuf *plane_ibuf = BKE_tracking_get_plane_imbuf(frame_ibuf, plane_marker);
+
+ IMB_freeImBuf(frame_ibuf);
+
+ return plane_ibuf;
+}
+
+static bool new_image_from_plane_marker_poll(bContext *C)
+{
+ if (!ED_space_clip_tracking_poll(C)) {
+ return false;
+ }
+
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ const MovieTracking *tracking = &clip->tracking;
+
+ if (tracking->act_plane_track == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static int new_image_from_plane_marker_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = tracking->act_plane_track;
+
+ ImBuf *plane_ibuf = sample_plane_marker_image_for_operator(C);
+ if (plane_ibuf == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ plane_track->image = BKE_image_add_from_imbuf(CTX_data_main(C), plane_ibuf, plane_track->name);
+
+ IMB_freeImBuf(plane_ibuf);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_new_image_from_plane_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Image from Plane Marker";
+ ot->description = "Create new image from the content of the plane marker";
+ ot->idname = "CLIP_OT_new_image_from_plane_marker";
+
+ /* api callbacks */
+ ot->poll = new_image_from_plane_marker_poll;
+ ot->exec = new_image_from_plane_marker_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static bool update_image_from_plane_marker_poll(bContext *C)
+{
+ if (!ED_space_clip_tracking_poll(C)) {
+ return false;
+ }
+
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ const MovieTracking *tracking = &clip->tracking;
+
+ if (tracking->act_plane_track == NULL || tracking->act_plane_track->image == NULL) {
+ return false;
+ }
+
+ const Image *image = tracking->act_plane_track->image;
+ return image->type == IMA_TYPE_IMAGE && ELEM(image->source, IMA_SRC_FILE, IMA_SRC_GENERATED);
+}
+
+static int update_image_from_plane_marker_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = tracking->act_plane_track;
+
+ ImBuf *plane_ibuf = sample_plane_marker_image_for_operator(C);
+ if (plane_ibuf == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_image_replace_imbuf(plane_track->image, plane_ibuf);
+
+ IMB_freeImBuf(plane_ibuf);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, plane_track->image);
+
+ BKE_image_partial_update_mark_full_update(plane_track->image);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_update_image_from_plane_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Image from Plane Marker";
+ ot->description =
+ "Update current image used by plane marker from the content of the plane marker";
+ ot->idname = "CLIP_OT_update_image_from_plane_marker";
+
+ /* api callbacks */
+ ot->poll = update_image_from_plane_marker_poll;
+ ot->exec = update_image_from_plane_marker_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
index d3b818fba43..315c17a6d74 100644
--- a/source/blender/editors/space_clip/tracking_ops_orient.c
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -72,7 +72,7 @@ static Object *get_orientation_object(bContext *C)
object = get_camera_with_movieclip(scene, clip);
}
else {
- object = OBACT(view_layer);
+ object = BKE_view_layer_active_object_get(view_layer);
}
if (object != NULL && object->parent != NULL) {
@@ -94,7 +94,7 @@ static bool set_orientation_poll(bContext *C)
if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
return true;
}
- return OBACT(view_layer) != NULL;
+ return BKE_view_layer_active_object_get(view_layer) != NULL;
}
}
return false;
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index d5223d57490..f6fd2980c19 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -131,10 +131,10 @@ static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwa
if (sequence) {
if (backwards) {
- tmj->efra = SFRA;
+ tmj->efra = scene->r.sfra;
}
else {
- tmj->efra = EFRA;
+ tmj->efra = scene->r.efra;
}
tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
}
diff --git a/source/blender/editors/space_console/CMakeLists.txt b/source/blender/editors/space_console/CMakeLists.txt
index 841c21f12e7..345ab8b0970 100644
--- a/source/blender/editors/space_console/CMakeLists.txt
+++ b/source/blender/editors/space_console/CMakeLists.txt
@@ -9,7 +9,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 140dc4c1d40..6710d4ce0e7 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -150,7 +150,7 @@ static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int c
/* cursor */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_CONSOLE_CURSOR);
immRectf(pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight);
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 17fbef23eac..ef22b1b9f0b 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -413,16 +413,8 @@ static int console_insert_invoke(bContext *C, wmOperator *op, const wmEvent *eve
}
char str[BLI_UTF8_MAX + 1];
- size_t len;
-
- if (event->utf8_buf[0]) {
- len = BLI_str_utf8_size_safe(event->utf8_buf);
- memcpy(str, event->utf8_buf, len);
- }
- else {
- /* in theory, ghost can set value to extended ascii here */
- len = BLI_str_utf8_from_unicode(event->ascii, str, sizeof(str) - 1);
- }
+ const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
+ memcpy(str, event->utf8_buf, len);
str[len] = '\0';
RNA_string_set(op->ptr, "text", str);
}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index c69b73e377d..417c65eb01a 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -20,6 +20,7 @@
#include "ED_space_api.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -154,7 +155,7 @@ static void id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_get_local_ID(drag, 0);
/* copy drag path to properties */
- char *text = RNA_path_full_ID_py(G_MAIN, id);
+ char *text = RNA_path_full_ID_py(id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
@@ -256,7 +257,7 @@ static void console_main_region_listener(const wmRegionListenerParams *params)
{
ScrArea *area = params->area;
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index b8c28e354da..792b9120e7b 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -15,7 +15,6 @@ set(INC
../../render
../../windowmanager
../../../../intern/atomic
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 87595ecdb88..1829f19bfd6 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -86,12 +86,12 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
bool rename(StringRefNull new_name) override;
/** Add drag support for catalog items. */
- std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
/** Add dropping support for catalog items. */
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
-class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController {
+class AssetCatalogDragController : public ui::AbstractViewItemDragController {
AssetCatalogTreeItem &catalog_item_;
public:
@@ -103,7 +103,7 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController
void on_drag_start() override;
};
-class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
+class AssetCatalogDropController : public ui::AbstractViewItemDropController {
AssetCatalogTreeItem &catalog_item_;
public:
@@ -142,7 +142,7 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
void build_row(uiLayout &row) override;
- struct DropController : public ui::AbstractTreeViewItemDropController {
+ struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@@ -150,13 +150,13 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
- struct DropController : public ui::AbstractTreeViewItemDropController {
+ struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@@ -164,7 +164,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
/* ---------------------------------------------------------------------- */
@@ -272,11 +272,11 @@ void AssetCatalogTreeViewItem::build_row(uiLayout &row)
return;
}
- uiButTreeRow *tree_row_but = tree_row_button();
+ uiButViewItem *view_item_but = view_item_button();
PointerRNA *props;
props = UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ (uiBut *)view_item_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
}
@@ -305,7 +305,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
0,
&props);
RNA_string_set(&props, "catalog_id", catalog_id_str_buffer);
- uiItemO(&column, "Rename", ICON_NONE, "UI_OT_tree_view_item_rename");
+ uiItemO(&column, "Rename", ICON_NONE, "UI_OT_view_item_rename");
/* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
* in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
@@ -333,14 +333,14 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
return true;
}
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogDropController>(
static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
-std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
+std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
return std::make_unique<AssetCatalogDragController>(
@@ -351,7 +351,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem
AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
- : ui::AbstractTreeViewItemDropController(tree_view), catalog_item_(catalog_item)
+ : ui::AbstractViewItemDropController(tree_view), catalog_item_(catalog_item)
{
}
@@ -422,10 +422,10 @@ bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
return drop_asset_catalog_into_catalog(
- drag, tree_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
+ drag, get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
return drop_assets_into_catalog(C,
- tree_view<AssetCatalogTreeView>(),
+ get_view<AssetCatalogTreeView>(),
drag,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
@@ -512,14 +512,14 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
::AssetLibrary &AssetCatalogDropController::get_asset_library() const
{
- return *tree_view<AssetCatalogTreeView>().asset_library_;
+ return *get_view<AssetCatalogTreeView>().asset_library_;
}
/* ---------------------------------------------------------------------- */
AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
- : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
+ : ui::AbstractViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
@@ -538,7 +538,7 @@ void *AssetCatalogDragController::create_drag_data() const
void AssetCatalogDragController::on_drag_start()
{
- AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
+ AssetCatalogTreeView &tree_view_ = get_view<AssetCatalogTreeView>();
tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
@@ -551,15 +551,15 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
PointerRNA *props;
UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
+ (uiBut *)view_item_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
props = UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ (uiBut *)view_item_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
/* No parent path to use the root level. */
RNA_string_set(props, "parent_path", nullptr);
}
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewAllItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
@@ -567,7 +567,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllI
}
AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
- : ui::AbstractTreeViewItemDropController(tree_view)
+ : ui::AbstractViewItemDropController(tree_view)
{
}
@@ -579,7 +579,7 @@ bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
}
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
- drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ drag, *get_view<AssetCatalogTreeView>().asset_library_);
if (drag_catalog->path.parent() == "") {
*r_disabled_hint = "Catalog is already placed at the highest level";
return false;
@@ -592,7 +592,7 @@ std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDr
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
- drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ drag, *get_view<AssetCatalogTreeView>().asset_library_);
return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
TIP_("to the top level of the tree");
@@ -604,14 +604,14 @@ bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSE
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
return AssetCatalogDropController::drop_asset_catalog_into_catalog(
drag,
- tree_view<AssetCatalogTreeView>(),
+ get_view<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewUnassignedItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
@@ -619,7 +619,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnas
}
AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
- : ui::AbstractTreeViewItemDropController(tree_view)
+ : ui::AbstractViewItemDropController(tree_view)
{
}
@@ -647,7 +647,7 @@ bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::drop_assets_into_catalog(
- C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
+ C, get_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::asset_browser
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 0e2b98ca349..93eb5938301 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -202,7 +202,7 @@ static void file_draw_string(int sx,
}
const uiStyle *style = UI_style_get();
- fs = style->widgetlabel;
+ fs = style->widget;
BLI_strncpy(fname, string, FILE_MAXFILE);
UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0');
@@ -245,7 +245,7 @@ static void file_draw_string_multiline(int sx,
}
const uiStyle *style = UI_style_get();
- int font_id = style->widgetlabel.uifont_id;
+ int font_id = style->widget.uifont_id;
int len = strlen(string);
rcti textbox;
@@ -378,7 +378,7 @@ static void file_draw_preview(const SpaceFile *sfile,
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
}
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexTiled_scaling(&state,
(float)xco,
(float)yco,
@@ -463,7 +463,7 @@ static void file_draw_preview(const SpaceFile *sfile,
if (show_outline) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float border_color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
float bgcolor[4];
UI_GetThemeColor4fv(TH_BACK, bgcolor);
@@ -581,7 +581,7 @@ static void draw_background(FileLayout *layout, View2D *v2d)
int sy;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float col_alternating[4];
UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating);
immUniformThemeColorBlend(TH_BACK, TH_ROW_ALTERNATE, col_alternating[3]);
@@ -631,7 +631,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
uint color = GPU_vertformat_attr_add(
format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
immBegin(GPU_PRIM_LINES, vertex_len);
sx = (int)v2d->tot.xmin;
@@ -660,7 +660,7 @@ static void draw_columnheader_background(const FileLayout *layout, const View2D
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShade(TH_BACK, 11);
immRectf(pos,
@@ -712,7 +712,7 @@ static void draw_columnheader_columns(const FileSelectParams *params,
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShade(TH_BACK, -10);
immBegin(GPU_PRIM_LINES, 2);
immVertex2f(pos, sx - 1, sy - divider_pad);
@@ -727,7 +727,7 @@ static void draw_columnheader_columns(const FileSelectParams *params,
/* Vertical separator lines line */
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShade(TH_BACK, -10);
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, v2d->cur.xmin, sy);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 62bdd583bc1..59d9a15fbab 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1793,7 +1793,7 @@ static bool file_execute(bContext *C, SpaceFile *sfile)
}
ED_file_change_dir(C);
}
- /* opening file - sends events now, so things get handled on windowqueue level */
+ /* Opening file, sends events now, so things get handled on window-queue level. */
else if (sfile->op) {
wmOperator *op = sfile->op;
char filepath[FILE_MAX];
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 183af0c14f5..24e1faaf4c9 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -485,6 +485,7 @@ static int groupname_to_code(const char *group);
static uint64_t groupname_to_filter_id(const char *group);
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
+static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry);
/* ********** Sort helpers ********** */
@@ -1025,13 +1026,6 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
return is_filtered_lib_type(file, root, filter) && is_filtered_file_relpath(file, filter);
}
-static bool is_filtered_asset_library(FileListInternEntry *file,
- const char *root,
- FileListFilter *filter)
-{
- return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter);
-}
-
static bool is_filtered_main(FileListInternEntry *file,
const char *UNUSED(dir),
FileListFilter *filter)
@@ -1048,6 +1042,17 @@ static bool is_filtered_main_assets(FileListInternEntry *file,
is_filtered_asset(file, filter);
}
+static bool is_filtered_asset_library(FileListInternEntry *file,
+ const char *root,
+ FileListFilter *filter)
+{
+ if (filelist_intern_entry_is_main_file(file)) {
+ return is_filtered_main_assets(file, root, filter);
+ }
+
+ return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter);
+}
+
void filelist_tag_needs_filtering(FileList *filelist)
{
filelist->flags |= FL_NEED_FILTERING;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e42e1e98660..c569a2b57a6 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -1385,3 +1385,24 @@ ScrArea *ED_fileselect_handler_area_find_any_with_op(const wmWindow *win)
return NULL;
}
+
+void ED_fileselect_ensure_default_filepath(struct bContext *C,
+ struct wmOperator *op,
+ const char *extension)
+{
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
+ struct Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+
+ if (blendfile_path[0] == '\0') {
+ BLI_strncpy(filepath, DATA_("untitled"), sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), extension);
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 310c688383b..30e13235f45 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -443,7 +443,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
if (STREQ(tfsm->path, fsm_iter->path)) {
icon = tfsm->icon;
if (tfsm->name[0] && (!name || !name[0])) {
- name = tfsm->name;
+ name = DATA_(tfsm->name);
}
break;
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index a462476aae0..b5cad0f6ff8 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -426,7 +426,7 @@ static void file_reset_filelist_showing_main_data(ScrArea *area, SpaceFile *sfil
static void file_listener(const wmSpaceTypeListenerParams *listener_params)
{
ScrArea *area = listener_params->area;
- wmNotifier *wmn = listener_params->notifier;
+ const wmNotifier *wmn = listener_params->notifier;
SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
/* context changes */
@@ -514,7 +514,7 @@ static void file_main_region_init(wmWindowManager *wm, ARegion *region)
static void file_main_region_listener(const wmRegionListenerParams *listener_params)
{
ARegion *region = listener_params->region;
- wmNotifier *wmn = listener_params->notifier;
+ const wmNotifier *wmn = listener_params->notifier;
/* context changes */
switch (wmn->category) {
@@ -820,7 +820,7 @@ static void file_execution_region_draw(const bContext *C, ARegion *region)
static void file_ui_region_listener(const wmRegionListenerParams *listener_params)
{
ARegion *region = listener_params->region;
- wmNotifier *wmn = listener_params->notifier;
+ const wmNotifier *wmn = listener_params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt
index ebcbf59be5f..39878debc39 100644
--- a/source/blender/editors/space_graph/CMakeLists.txt
+++ b/source/blender/editors/space_graph/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index bc2705df314..2d3b43ec728 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -41,6 +41,7 @@
#include "WM_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "ED_anim_api.h"
@@ -225,15 +226,15 @@ static void graph_panel_properties(const bContext *C, Panel *panel)
/* color settings */
col = uiLayoutColumn(layout, true);
- uiItemR(col, &fcu_ptr, "color_mode", 0, "Display Color", ICON_NONE);
+ uiItemR(col, &fcu_ptr, "color_mode", 0, IFACE_("Display Color"), ICON_NONE);
if (fcu->color_mode == FCURVE_COLOR_CUSTOM) {
- uiItemR(col, &fcu_ptr, "color", 0, "Color", ICON_NONE);
+ uiItemR(col, &fcu_ptr, "color", 0, IFACE_("Color"), ICON_NONE);
}
/* smoothing setting */
col = uiLayoutColumn(layout, true);
- uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "Handle Smoothing", ICON_NONE);
+ uiItemR(col, &fcu_ptr, "auto_smoothing", 0, IFACE_("Handle Smoothing"), ICON_NONE);
MEM_freeN(ale);
}
@@ -277,7 +278,7 @@ static void graphedit_activekey_update_cb(bContext *UNUSED(C),
/* make sure F-Curve and its handles are still valid after this editing */
sort_time_fcurve(fcu);
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* update callback for active keyframe properties - handle-editing wrapper */
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index a946ce22139..41a8368152d 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -80,7 +80,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm,
GPU_line_width(1.0f);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -107,7 +107,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm,
/* set size of vertices (non-adjustable for now) */
GPU_point_size(2.0f);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* for now, point color is fixed, and is white */
immUniformColor3f(1.0f, 1.0f, 1.0f);
@@ -408,7 +408,7 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu)
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint color = GPU_vertformat_attr_add(
format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
GPU_line_smooth(true);
}
@@ -540,7 +540,7 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor((fcu->flag & FCURVE_SELECTED) ? TH_TEXT_HI : TH_TEXT);
@@ -1045,7 +1045,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
if (BKE_fcurve_is_protected(fcu)) {
/* Protected curves (non editable) are drawn with dotted lines. */
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
immUniform1i("colors_len", 0); /* Simple dashes. */
immUniform1f("dash_width", 4.0f);
@@ -1190,7 +1190,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1268,7 +1268,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
immUnbindProgram();
/* GPU_PRIM_POINTS do not survive dashed line geometry shader... */
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* x marks the spot .................................................... */
/* -> outer frame */
@@ -1310,7 +1310,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1348,7 +1348,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
int filter;
/* build list of curves to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY);
filter |= ((sel) ? (ANIMFILTER_SEL) : (ANIMFILTER_UNSEL));
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -1393,7 +1393,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
size_t items;
/* build list of channels to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index cfc4fcf8dad..64a3c603e73 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -109,8 +109,8 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
eInsertKeyFlags flag = 0;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
if (mode & GRAPHKEYS_INSERTKEY_SEL) {
filter |= ANIMFILTER_SEL;
}
@@ -156,10 +156,10 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
x = sipo->cursorTime;
}
else if (adt) {
- x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ x = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- x = (float)CFRA;
+ x = (float)scene->r.cfra;
}
/* Normalize units of cursor's value. */
@@ -178,7 +178,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
}
else {
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
- ac->depsgraph, (float)CFRA);
+ ac->depsgraph, (float)scene->r.cfra);
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
@@ -211,12 +211,12 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
/* Adjust current frame for NLA-mapping. */
- float cfra = (float)CFRA;
+ float cfra = (float)scene->r.cfra;
if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) {
cfra = sipo->cursorTime;
}
else if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
const float curval = evaluate_fcurve_only_curve(fcu, cfra);
@@ -457,7 +457,8 @@ static short copy_graph_keys(bAnimContext *ac)
* - First time we try to filter more strictly, allowing only selected channels
* to allow copying animation between channels.
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -472,13 +473,13 @@ static short copy_graph_keys(bAnimContext *ac)
return ok;
}
-static short paste_graph_keys(bAnimContext *ac,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
- bool flip)
+static eKeyPasteError paste_graph_keys(bAnimContext *ac,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
ListBase anim_data = {NULL, NULL};
- int filter, ok = 0;
+ int filter;
/* Filter data
* - First time we try to filter more strictly, allowing only selected channels
@@ -486,15 +487,15 @@ static short paste_graph_keys(bAnimContext *ac,
* - Second time, we loosen things up if nothing was found the first time, allowing
* users to just paste keyframes back into the original curve again T31670.
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
}
/* Paste keyframes. */
- ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
+ const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
/* Clean up. */
ANIM_animdata_freelist(&anim_data);
@@ -554,9 +555,18 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
/* Ac.reports by default will be the global reports list, which won't show warnings. */
ac.reports = op->reports;
- /* Paste keyframes - non-zero return means an error occurred while trying to paste. */
- if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) {
- return OPERATOR_CANCELLED;
+ const eKeyPasteError kf_empty = paste_graph_keys(&ac, offset_mode, merge_mode, flipped);
+ switch (kf_empty) {
+ case KEYFRAME_PASTE_OK:
+ break;
+
+ case KEYFRAME_PASTE_NOWHERE_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
+ return OPERATOR_CANCELLED;
+
+ case KEYFRAME_PASTE_NOTHING_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No data in buffer to paste");
+ return OPERATOR_CANCELLED;
}
/* Set notifier that keyframes have changed. */
@@ -631,8 +641,8 @@ static bool duplicate_graph_keys(bAnimContext *ac)
bool changed = false;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and delete selected keys. */
@@ -702,8 +712,8 @@ static bool delete_graph_keys(bAnimContext *ac)
bool changed_final = false;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and delete selected keys. */
@@ -713,7 +723,7 @@ static bool delete_graph_keys(bAnimContext *ac)
bool changed;
/* Delete selected keyframes only. */
- changed = delete_fcurve_keys(fcu);
+ changed = BKE_fcurve_delete_keys_selected(fcu);
if (changed) {
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -785,8 +795,8 @@ static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
int filter;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and clean curves. */
@@ -862,8 +872,8 @@ static void bake_graph_curves(bAnimContext *ac, int start, int end)
int filter;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -949,8 +959,8 @@ static void unbake_graph_curves(bAnimContext *ac, int start, int end)
bAnimListElem *ale;
/* Filter data. */
- const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -1096,12 +1106,12 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
}
/* Determine extents of the baking. */
- sbi.cfra = start = CFRA;
- end = CFRA + sbi.length - 1;
+ sbi.cfra = start = scene->r.cfra;
+ end = scene->r.cfra + sbi.length - 1;
/* Filter anim channels. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Loop through all selected F-Curves, replacing its data with the sound samples. */
@@ -1267,8 +1277,8 @@ static void sample_graph_keys(bAnimContext *ac)
int filter;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -1364,8 +1374,8 @@ static void setexpo_graph_keys(bAnimContext *ac, short mode)
int filter;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting mode per F-Curve. */
@@ -1469,8 +1479,8 @@ static void setipo_graph_keys(bAnimContext *ac, short mode)
KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting BezTriple interpolation
@@ -1478,7 +1488,7 @@ static void setipo_graph_keys(bAnimContext *ac, short mode)
* Currently that's not necessary here.
*/
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
}
@@ -1547,8 +1557,8 @@ static void seteasing_graph_keys(bAnimContext *ac, short mode)
KeyframeEditFunc set_cb = ANIM_editkeyframes_easing(mode);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting BezTriple easing.
@@ -1556,7 +1566,7 @@ static void seteasing_graph_keys(bAnimContext *ac, short mode)
* Currently that's not necessary here.
*/
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
}
@@ -1625,8 +1635,8 @@ static void sethandles_graph_keys(bAnimContext *ac, short mode)
KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting flags for handles.
@@ -1639,7 +1649,7 @@ static void sethandles_graph_keys(bAnimContext *ac, short mode)
/* Any selected keyframes for editing? */
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
/* Change type of selected handles. */
- ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1945,7 +1955,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
/* Step 1: extract only the rotation f-curves. */
const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -2056,7 +2066,8 @@ static KeyframeEditData sum_selected_keyframes(bAnimContext *ac)
memset(&ked, 0, sizeof(KeyframeEditData));
/* Loop over action data, averaging values. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -2119,8 +2130,8 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
/* Animation Mode - Affects current frame (int) */
- CFRA = round_fl_to_int(sum_time / num_keyframes);
- SUBFRA = 0.0f;
+ scene->r.cfra = round_fl_to_int(sum_time / num_keyframes);
+ scene->r.subframe = 0.0f;
}
sipo->cursorVal = sum_value / (float)num_keyframes;
@@ -2240,8 +2251,8 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
float cursor_value = 0.0f;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Init custom data for iterating over keyframes. */
@@ -2284,11 +2295,11 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* Perform snapping. */
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -2361,8 +2372,8 @@ static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = {
static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten)
{
/* Filter data. */
- const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -2523,8 +2534,8 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
edit_cb = ANIM_editkeyframes_mirror(mode);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Mirror keyframes. */
@@ -2544,11 +2555,11 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* Perform actual mirroring. */
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -2620,8 +2631,8 @@ static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Smooth keyframes. */
@@ -2720,7 +2731,8 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
type = RNA_enum_get(op->ptr, "type");
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
if (RNA_boolean_get(op->ptr, "only_active")) {
/* FIXME: enforce in this case only a single channel to get handled? */
filter |= ANIMFILTER_ACTIVE;
@@ -2875,14 +2887,14 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* Filter data. */
if (RNA_boolean_get(op->ptr, "only_active")) {
/* This should be the default (for buttons) - Just paste to the active FCurve. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_ACTIVE |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
}
else {
/* This is only if the operator gets called from a hotkey or search -
* Paste to all visible curves. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
}
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -3065,7 +3077,8 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
/* NOTE: We might need a scene update to evaluate the driver flags. */
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Find invalid drivers. */
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 128925d4591..8deea21318c 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -72,21 +72,21 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
/* 1) frame is rounded to the nearest int, since frames are ints */
- CFRA = round_fl_to_int(frame);
+ scene->r.cfra = round_fl_to_int(frame);
if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
/* Clip to preview range
* NOTE: Preview range won't go into negative values,
* so only clamping once should be fine.
*/
- CLAMP(CFRA, PSFRA, PEFRA);
+ CLAMP(scene->r.cfra, PSFRA, PEFRA);
}
else {
/* Prevent negative frames */
- FRAMENUMBER_MIN_CLAMP(CFRA);
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
}
- SUBFRA = 0.0f;
+ scene->r.subframe = 0.0f;
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
}
@@ -234,14 +234,16 @@ static int graphview_curves_hide_exec(bContext *C, wmOperator *op)
/* get list of all channels that selection may need to be flushed to
* - hierarchy must not affect what we have access to here...
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
/* filter data
* - of the remaining visible curves, we want to hide the ones that are
* selected/unselected (depending on "unselected" prop)
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_NODUPLIS);
if (unselected) {
filter |= ANIMFILTER_UNSEL;
}
@@ -275,7 +277,8 @@ static int graphview_curves_hide_exec(bContext *C, wmOperator *op)
/* unhide selected */
if (unselected) {
/* turn off requirement for visible */
- filter = ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_LIST_CHANNELS;
+ filter = ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY;
/* flushing has been done */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -344,13 +347,15 @@ static int graphview_curves_reveal_exec(bContext *C, wmOperator *op)
/* get list of all channels that selection may need to be flushed to
* - hierarchy must not affect what we have access to here...
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
/* filter data
* - just go through all visible channels, ensuring that everything is set to be curve-visible
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index e71c5114b0a..0ce3e1a797a 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -172,7 +172,8 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
* - if the option to only show keyframes that belong to selected F-Curves is enabled,
* include the 'only selected' flag...
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
if (sipo->flag &
SIPO_SELCUVERTSONLY) { /* FIXME: this should really be check for by the filtering code... */
filter |= ANIMFILTER_SEL;
@@ -342,7 +343,8 @@ void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channel
KeyframeEditFunc test_cb, sel_cb;
/* determine type-based settings */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -498,7 +500,8 @@ static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rec
static int initialize_animdata_selection_filter(const SpaceGraph *sipo)
{
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
if (sipo->flag & SIPO_SELCUVERTSONLY) {
filter |= ANIMFILTER_FOREDIT | ANIMFILTER_SELEDIT;
}
@@ -1125,7 +1128,7 @@ static const EnumPropertyItem prop_column_select_types[] = {
/* ------------------- */
/* Selects all visible keyframes between the specified markers */
-/* TODO(campbell): this is almost an _exact_ duplicate of a function of the same name in
+/* TODO(@campbellbarton): this is almost an _exact_ duplicate of a function of the same name in
* action_select.c should de-duplicate. */
static void markers_selectkeys_between(bAnimContext *ac)
{
@@ -1150,7 +1153,8 @@ static void markers_selectkeys_between(bAnimContext *ac)
ked.f2 = max;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys in-between */
@@ -1189,7 +1193,8 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
/* build list of columns */
switch (mode) {
case GRAPHKEYS_COLUMNSEL_KEYS: /* list of selected keys */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1204,7 +1209,7 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
BLI_addtail(&ked.list, ce);
- ce->cfra = (float)CFRA;
+ ce->cfra = (float)scene->r.cfra;
break;
case GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
@@ -1222,7 +1227,8 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1314,7 +1320,8 @@ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1372,7 +1379,8 @@ static void select_moreless_graph_keys(bAnimContext *ac, short mode)
memset(&ked, 0, sizeof(KeyframeEditData));
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1513,15 +1521,15 @@ static void graphkeys_select_leftright(bAnimContext *ac, short leftright, short
if (leftright == GRAPHKEYS_LRSEL_LEFT) {
ked.f1 = MINAFRAMEF;
- ked.f2 = (float)(CFRA + 0.1f);
+ ked.f2 = (float)(scene->r.cfra + 0.1f);
}
else {
- ked.f1 = (float)(CFRA - 0.1f);
+ ked.f1 = (float)(scene->r.cfra - 0.1f);
ked.f2 = MAXFRAMEF;
}
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys */
@@ -1597,7 +1605,7 @@ static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, const
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
- if (x < CFRA) {
+ if (x < scene->r.cfra) {
RNA_enum_set(op->ptr, "mode", GRAPHKEYS_LRSEL_LEFT);
}
else {
@@ -1797,7 +1805,8 @@ static int mouse_graph_keys(bAnimContext *ac,
* otherwise the active flag won't be set T26452. */
if (!run_modal && (nvi->fcu->flag & FCURVE_SELECTED) && something_was_selected) {
/* NOTE: Sync the filter flags with findnearest_fcurve_vert. */
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
}
@@ -1873,7 +1882,8 @@ static int graphkeys_mselect_column(bAnimContext *ac,
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 313f6ca1561..f3d92911155 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -48,8 +48,8 @@
/* Used to obtain a list of animation channels for the operators to work on. */
#define OPERATOR_DATA_FILTER \
- (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | \
- ANIMFILTER_NODUPLIS)
+ (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY | \
+ ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS)
/* This data type is only used for modal operation. */
typedef struct tGraphSliderOp {
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index d8baa4c643d..82067661d57 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -81,7 +81,8 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area)
bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE |
+ ANIMFILTER_FCURVESONLY);
size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* We take the first F-Curve only, since some other ones may have had 'active' flag set
@@ -131,7 +132,7 @@ bool graphop_visible_keyframes_poll(bContext *C)
/* loop over the visible (selection doesn't matter) F-Curves, and see if they're suitable
* stopping on the first successful match
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
return found;
@@ -183,7 +184,8 @@ bool graphop_editable_keyframes_poll(bContext *C)
/* loop over the editable F-Curves, and see if they're suitable
* stopping on the first successful match
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
CTX_wm_operator_poll_msg_set(C, "There is no animation data to operate on");
@@ -286,7 +288,8 @@ bool graphop_selected_fcurve_poll(bContext *C)
/* Get the editable + selected F-Curves, and as long as we got some, we can return.
* NOTE: curve-visible flag isn't included,
* otherwise selecting a curve via list to edit is too cumbersome. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
return false;
diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c
index 18465018d35..f80c7c17c3a 100644
--- a/source/blender/editors/space_graph/graph_view.c
+++ b/source/blender/editors/space_graph/graph_view.c
@@ -56,7 +56,8 @@ void get_graph_keyframe_extents(bAnimContext *ac,
int filter;
/* Get data to filter, from Dopesheet. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
if (sipo->flag & SIPO_SELCUVERTSONLY) {
filter |= ANIMFILTER_SEL;
}
@@ -398,8 +399,8 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
}
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 43621d74e79..3594c65c1cb 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -90,7 +90,6 @@ static SpaceLink *graph_create(const ScrArea *UNUSED(area), const Scene *scene)
BLI_addtail(&sipo->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
- region->flag = RGN_FLAG_HIDDEN;
/* main region */
region = MEM_callocN(sizeof(ARegion), "main region for graphedit");
@@ -225,7 +224,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *region)
if (((sipo->flag & SIPO_NODRAWCURSOR) == 0)) {
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* horizontal component of value-cursor (value line before the current frame line) */
float y = sipo->cursorVal;
@@ -394,7 +393,7 @@ static void graph_buttons_region_draw(const bContext *C, ARegion *region)
static void graph_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -530,7 +529,7 @@ static void graph_region_message_subscribe(const wmRegionMessageSubscribeParams
static void graph_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* context changes */
@@ -626,7 +625,7 @@ static void graph_refresh_fcurve_colors(const bContext *C)
* - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
* mismatch between channel-colors and the drawn curves
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* loop over F-Curves, assigning colors */
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 39fb41245bf..4284d0f76af 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -16,7 +16,6 @@ set(INC
../../render
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -28,7 +27,7 @@ set(SRC
image_edit.c
image_ops.c
image_sequence.c
- image_undo.c
+ image_undo.cc
space_image.c
image_intern.h
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index d0c21f85472..bc367a99d6b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -869,7 +869,8 @@ void uiTemplateImage(uiLayout *layout,
uiItemS(col);
uiItemR(col, &imaptr, "generated_type", UI_ITEM_R_EXPAND, IFACE_("Type"), ICON_NONE);
- if (ima->gen_type == IMA_GENTYPE_BLANK) {
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ if (base_tile->gen_type == IMA_GENTYPE_BLANK) {
uiItemR(col, &imaptr, "generated_color", 0, NULL, ICON_NONE);
}
}
@@ -921,7 +922,7 @@ void uiTemplateImage(uiLayout *layout,
}
}
- /* Colorspace and alpha */
+ /* Color-space and alpha. */
{
uiItemS(layout);
@@ -1211,6 +1212,11 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i
ofs += BLI_strncpy_rlen(str + ofs, TIP_(" + Z"), len - ofs);
}
+ eGPUTextureFormat texture_format = IMB_gpu_get_texture_format(
+ ibuf, ima->flag & IMA_HIGH_BITDEPTH, ibuf->planes >= 8);
+ const char *texture_format_description = GPU_texture_format_description(texture_format);
+ ofs += BLI_snprintf_rlen(str + ofs, len - ofs, TIP_(", %s"), texture_format_description);
+
uiItemL(col, str, ICON_NONE);
}
@@ -1218,7 +1224,7 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
/* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
Scene *scene = CTX_data_scene(C);
- const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL);
+ const int framenr = BKE_image_user_frame_get(iuser, scene->r.cfra, NULL);
char str[MAX_IMAGE_INFO_LEN];
int duration = 0;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 048c7345b97..b55bac0bc2f 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -98,7 +98,7 @@ static void draw_render_info(
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_FACE_SELECT);
GPU_line_width(1.0f);
@@ -158,7 +158,7 @@ void ED_image_draw_info(Scene *scene,
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* noisy, high contrast make impossible to read if lower alpha is used. */
immUniformColor4ub(0, 0, 0, 190);
@@ -338,7 +338,7 @@ void ED_image_draw_info(Scene *scene,
/* BLF uses immediate mode too, so we must reset our vertex format */
pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (channels == 4) {
rcti color_rect_half;
@@ -381,7 +381,7 @@ void ED_image_draw_info(Scene *scene,
/* draw outline */
pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3ub(128, 128, 128);
imm_draw_box_wire_2d(pos, color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
immUnbindProgram();
@@ -448,7 +448,7 @@ void draw_image_sample_line(SpaceImage *sima)
uint shdr_dashed_pos = GPU_vertformat_attr_add(
format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -515,7 +515,8 @@ void draw_image_cache(const bContext *C, ARegion *region)
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
Image *image = ED_space_image(sima);
- float x, cfra = CFRA, sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float x, cfra = scene->r.cfra, sfra = scene->r.sfra, efra = scene->r.efra,
+ framelen = region->winx / (efra - sfra + 1);
Mask *mask = NULL;
if (!ED_space_image_show_cache(sima)) {
@@ -556,7 +557,7 @@ void draw_image_cache(const bContext *C, ARegion *region)
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_CFRAME);
immRecti(pos, x, region_bottom, x + ceilf(framelen), region_bottom + 8 * UI_DPI_FAC);
immUnbindProgram();
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index e851b99d3ba..d17602ecd05 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -18,8 +18,10 @@
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "IMB_imbuf_types.h"
@@ -212,13 +214,7 @@ void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
}
else if (sima->image && sima->image->type == IMA_TYPE_R_RESULT && scene) {
/* not very important, just nice */
- *r_width = (scene->r.xsch * scene->r.size) / 100;
- *r_height = (scene->r.ysch * scene->r.size) / 100;
-
- if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) {
- *r_width *= BLI_rctf_size_x(&scene->r.border);
- *r_height *= BLI_rctf_size_y(&scene->r.border);
- }
+ BKE_render_resolution(&scene->r, true, r_width, r_height);
}
/* I know a bit weak... but preview uses not actual image size */
// XXX else if (image_preview_active(sima, r_width, r_height));
@@ -476,13 +472,23 @@ bool ED_space_image_maskedit_poll(bContext *C)
if (sima) {
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
return ED_space_image_check_show_maskedit(sima, obedit);
}
return false;
}
+bool ED_space_image_maskedit_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_image_maskedit_poll(C)) {
+ return false;
+ }
+
+ const SpaceImage *space_image = CTX_wm_space_image(C);
+ return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_image_paint_curve(const bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -508,6 +514,16 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_space_image_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_image_maskedit_mask_poll(C)) {
+ return false;
+ }
+
+ const SpaceImage *space_image = CTX_wm_space_image(C);
+ return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_image_cursor_poll(bContext *C)
{
return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index fa49e996c2a..78aaf957a87 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -45,6 +45,7 @@
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -197,10 +198,17 @@ static ImageUser *image_user_from_context(const bContext *C)
return (sima) ? &sima->iuser : NULL;
}
-static ImageUser image_user_from_active_tile(Image *ima)
+static ImageUser image_user_from_context_and_active_tile(const bContext *C, Image *ima)
{
+ /* Try to get image user from context if available, otherwise use default. */
+ ImageUser *iuser_context = image_user_from_context(C);
ImageUser iuser;
- BKE_imageuser_default(&iuser);
+ if (iuser_context) {
+ iuser = *iuser_context;
+ }
+ else {
+ BKE_imageuser_default(&iuser);
+ }
/* Use the file associated with the active tile. Otherwise use the first tile. */
if (ima && ima->source == IMA_SRC_TILED) {
@@ -233,7 +241,7 @@ static bool image_from_context_has_data_poll(bContext *C)
static bool image_from_context_has_data_poll_active_tile(bContext *C)
{
Image *ima = image_from_context(C);
- ImageUser iuser = image_user_from_active_tile(ima);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
return BKE_image_has_ibuf(ima, &iuser);
}
@@ -964,7 +972,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
static bool image_view_selected_poll(bContext *C)
{
- return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
+ return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_maskedit_poll(C)));
}
void IMAGE_OT_view_selected(wmOperatorType *ot)
@@ -1602,7 +1610,7 @@ static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *
}
}
else if (ima->source == IMA_SRC_TILED) {
- ImageUser iuser = image_user_from_active_tile(ima);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
BKE_image_user_file_path(&iuser, ima, filepath);
}
@@ -1823,7 +1831,7 @@ static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOp
}
static bool save_image_op(
- Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, ImageSaveOptions *opts)
+ Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
{
WM_cursor_wait(true);
@@ -2391,7 +2399,7 @@ bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
if (image_has_valid_path(ima)) {
ImageSaveOptions opts;
Scene *scene = CTX_data_scene(C);
- if (!BKE_image_save_options_init(&opts, bmain, scene, ima, NULL, false, false)) {
+ if (BKE_image_save_options_init(&opts, bmain, scene, ima, NULL, false, false)) {
bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
ok = ok && saved_successfully;
}
@@ -2698,7 +2706,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
static int image_flip_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImageUser iuser = image_user_from_active_tile(ima);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2716,7 +2724,7 @@ static int image_flip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
@@ -2819,7 +2827,7 @@ void IMAGE_OT_flip(wmOperatorType *ot)
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImageUser iuser = image_user_from_active_tile(ima);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2837,7 +2845,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
@@ -2943,7 +2951,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Image *ima = image_from_context(C);
- ImageUser iuser = image_user_from_active_tile(ima);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
if (!RNA_property_is_set(op->ptr, prop)) {
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
@@ -2957,7 +2965,7 @@ static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
static int image_scale_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImageUser iuser = image_user_from_active_tile(ima);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2982,7 +2990,7 @@ static int image_scale_exec(bContext *C, wmOperator *op)
RNA_property_int_set_array(op->ptr, prop, size);
}
- ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
IMB_scaleImBuf(ibuf, size[0], size[1]);
@@ -3464,10 +3472,10 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = image_from_context(C);
+ ImageUser *iuser = image_user_from_context(C);
- if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
+ if (!BKE_image_clear_renderslot(ima, iuser, ima->render_slot)) {
return OPERATOR_CANCELLED;
}
@@ -3532,10 +3540,10 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot)
static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = image_from_context(C);
+ ImageUser *iuser = image_user_from_context(C);
- if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
+ if (!BKE_image_remove_renderslot(ima, iuser, ima->render_slot)) {
return OPERATOR_CANCELLED;
}
@@ -3580,9 +3588,9 @@ static void change_frame_apply(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
/* set the new frame number */
- CFRA = RNA_int_get(op->ptr, "frame");
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
+ scene->r.cfra = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
+ scene->r.subframe = 0.0f;
/* do updates */
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
@@ -3603,7 +3611,7 @@ static int frame_from_event(bContext *C, const wmEvent *event)
int framenr = 0;
if (region->regiontype == RGN_TYPE_WINDOW) {
- float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
framenr = sfra + event->mval[0] / framelen;
}
@@ -3725,38 +3733,52 @@ static int render_border_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Render *re = RE_GetSceneRender(scene);
- RenderData *rd;
- rctf border;
+ SpaceImage *sima = CTX_wm_space_image(C);
if (re == NULL) {
/* Shouldn't happen, but better be safe close to the release. */
return OPERATOR_CANCELLED;
}
- rd = RE_engine_get_render_data(re);
- if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
- BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
- return OPERATOR_CANCELLED;
- }
+ /* Get information about the previous render, or current scene if no render yet. */
+ int width, height;
+ BKE_render_resolution(&scene->r, false, &width, &height);
+ const RenderData *rd = ED_space_image_has_buffer(sima) ? RE_engine_get_render_data(re) :
+ &scene->r;
- /* get rectangle from operator */
+ /* Get rectangle from the operator. */
+ rctf border;
WM_operator_properties_border_to_rctf(op, &border);
UI_view2d_region_to_view_rctf(&region->v2d, &border, &border);
- /* actually set border */
+ /* Adjust for cropping. */
+ if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
+ border.xmin = rd->border.xmin + border.xmin * (rd->border.xmax - rd->border.xmin);
+ border.xmax = rd->border.xmin + border.xmax * (rd->border.xmax - rd->border.xmin);
+ border.ymin = rd->border.ymin + border.ymin * (rd->border.ymax - rd->border.ymin);
+ border.ymax = rd->border.ymin + border.ymax * (rd->border.ymax - rd->border.ymin);
+ }
+
CLAMP(border.xmin, 0.0f, 1.0f);
CLAMP(border.ymin, 0.0f, 1.0f);
CLAMP(border.xmax, 0.0f, 1.0f);
CLAMP(border.ymax, 0.0f, 1.0f);
- scene->r.border = border;
- /* drawing a border surrounding the entire camera view switches off border rendering
- * or the border covers no pixels */
+ /* Drawing a border surrounding the entire camera view switches off border rendering
+ * or the border covers no pixels. */
if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
(border.xmin == border.xmax || border.ymin == border.ymax)) {
scene->r.mode &= ~R_BORDER;
}
else {
+ /* Snap border to pixel boundaries, so drawing a border within a pixel selects that pixel. */
+ border.xmin = floorf(border.xmin * width) / width;
+ border.xmax = ceilf(border.xmax * width) / width;
+ border.ymin = floorf(border.ymin * height) / height;
+ border.ymax = ceilf(border.ymax * height) / height;
+
+ /* Set border. */
+ scene->r.border = border;
scene->r.mode |= R_BORDER;
}
@@ -3825,15 +3847,16 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
{
- float color[4];
- RNA_float_get_array(ptr, "color", color);
- int gen_type = RNA_enum_get(ptr, "generated_type");
- int width = RNA_int_get(ptr, "width");
- int height = RNA_int_get(ptr, "height");
+ RNA_float_get_array(ptr, "color", tile->gen_color);
+ tile->gen_type = RNA_enum_get(ptr, "generated_type");
+ tile->gen_x = RNA_int_get(ptr, "width");
+ tile->gen_y = RNA_int_get(ptr, "height");
bool is_float = RNA_boolean_get(ptr, "float");
- int planes = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
- return BKE_image_fill_tile(ima, tile, width, height, color, gen_type, planes, is_float);
+ tile->gen_flag = is_float ? IMA_GEN_FLOAT : 0;
+ tile->gen_depth = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
+
+ return BKE_image_fill_tile(ima, tile);
}
static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.cc
index a7a8bde1115..065641c4051 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.cc
@@ -22,6 +22,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_map.hh"
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -82,14 +83,31 @@ void ED_image_paint_tile_lock_end(void)
*
* \{ */
-static ImBuf *imbuf_alloc_temp_tile(void)
+static ImBuf *imbuf_alloc_temp_tile()
{
return IMB_allocImBuf(
ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect);
}
-typedef struct PaintTile {
- struct PaintTile *next, *prev;
+struct PaintTileKey {
+ int x_tile, y_tile;
+ Image *image;
+ ImBuf *ibuf;
+ /* Copied from iuser.tile in PaintTile. */
+ int iuser_tile;
+
+ uint64_t hash() const
+ {
+ return blender::get_default_hash_4(x_tile, y_tile, image, ibuf);
+ }
+ bool operator==(const PaintTileKey &other) const
+ {
+ return x_tile == other.x_tile && y_tile == other.y_tile && image == other.image &&
+ ibuf == other.ibuf && iuser_tile == other.iuser_tile;
+ }
+};
+
+struct PaintTile {
Image *image;
ImBuf *ibuf;
/* For 2D image painting the ImageUser uses most of the values.
@@ -99,14 +117,14 @@ typedef struct PaintTile {
ImageUser iuser;
union {
float *fp;
- uint *uint;
+ uint32_t *uint;
void *pt;
} rect;
- ushort *mask;
+ uint16_t *mask;
bool valid;
bool use_float;
int x_tile, y_tile;
-} PaintTile;
+};
static void ptile_free(PaintTile *ptile)
{
@@ -119,23 +137,25 @@ static void ptile_free(PaintTile *ptile)
MEM_freeN(ptile);
}
-static void ptile_free_list(ListBase *paint_tiles)
-{
- for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
- ptile_next = ptile->next;
- ptile_free(ptile);
+struct PaintTileMap {
+ blender::Map<PaintTileKey, PaintTile *> map;
+
+ ~PaintTileMap()
+ {
+ for (PaintTile *ptile : map.values()) {
+ ptile_free(ptile);
+ }
}
- BLI_listbase_clear(paint_tiles);
-}
+};
-static void ptile_invalidate_list(ListBase *paint_tiles)
+static void ptile_invalidate_map(PaintTileMap *paint_tile_map)
{
- LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
+ for (PaintTile *ptile : paint_tile_map->map.values()) {
ptile->valid = false;
}
}
-void *ED_image_paint_tile_find(ListBase *paint_tiles,
+void *ED_image_paint_tile_find(PaintTileMap *paint_tile_map,
Image *image,
ImBuf *ibuf,
ImageUser *iuser,
@@ -144,28 +164,32 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
ushort **r_mask,
bool validate)
{
- LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
- if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
- if (ptile->image == image && ptile->ibuf == ibuf && ptile->iuser.tile == iuser->tile) {
- if (r_mask) {
- /* allocate mask if requested. */
- if (!ptile->mask) {
- ptile->mask = MEM_callocN(sizeof(ushort) * square_i(ED_IMAGE_UNDO_TILE_SIZE),
- "UndoImageTile.mask");
- }
- *r_mask = ptile->mask;
- }
- if (validate) {
- ptile->valid = true;
- }
- return ptile->rect.pt;
- }
+ PaintTileKey key;
+ key.ibuf = ibuf;
+ key.image = image;
+ key.iuser_tile = iuser->tile;
+ key.x_tile = x_tile;
+ key.y_tile = y_tile;
+ PaintTile **pptile = paint_tile_map->map.lookup_ptr(key);
+ if (pptile == nullptr) {
+ return nullptr;
+ }
+ PaintTile *ptile = *pptile;
+ if (r_mask) {
+ /* allocate mask if requested. */
+ if (!ptile->mask) {
+ ptile->mask = static_cast<uint16_t *>(
+ MEM_callocN(sizeof(uint16_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE), "UndoImageTile.mask"));
}
+ *r_mask = ptile->mask;
}
- return NULL;
+ if (validate) {
+ ptile->valid = true;
+ }
+ return ptile->rect.pt;
}
-void *ED_image_paint_tile_push(ListBase *paint_tiles,
+void *ED_image_paint_tile_push(PaintTileMap *paint_tile_map,
Image *image,
ImBuf *ibuf,
ImBuf **tmpibuf,
@@ -177,37 +201,43 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
bool use_thread_lock,
bool find_prev)
{
- const bool has_float = (ibuf->rect_float != NULL);
+ if (use_thread_lock) {
+ BLI_spin_lock(&paint_tiles_lock);
+ }
+ const bool has_float = (ibuf->rect_float != nullptr);
/* check if tile is already pushed */
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
if (find_prev) {
void *data = ED_image_paint_tile_find(
- paint_tiles, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
+ paint_tile_map, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
if (data) {
+ if (use_thread_lock) {
+ BLI_spin_unlock(&paint_tiles_lock);
+ }
return data;
}
}
- if (*tmpibuf == NULL) {
+ if (*tmpibuf == nullptr) {
*tmpibuf = imbuf_alloc_temp_tile();
}
- PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile");
+ PaintTile *ptile = static_cast<PaintTile *>(MEM_callocN(sizeof(PaintTile), "PaintTile"));
ptile->image = image;
ptile->ibuf = ibuf;
ptile->iuser = *iuser;
- ptile->iuser.scene = NULL;
+ ptile->iuser.scene = nullptr;
ptile->x_tile = x_tile;
ptile->y_tile = y_tile;
/* add mask explicitly here */
if (r_mask) {
- *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * square_i(ED_IMAGE_UNDO_TILE_SIZE),
- "PaintTile.mask");
+ *r_mask = ptile->mask = static_cast<uint16_t *>(
+ MEM_callocN(sizeof(uint16_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE), "PaintTile.mask"));
}
ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
@@ -234,13 +264,24 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
}
else {
- SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect);
+ SWAP(uint32_t *, ptile->rect.uint, (*tmpibuf)->rect);
}
- if (use_thread_lock) {
- BLI_spin_lock(&paint_tiles_lock);
+ PaintTileKey key = {};
+ key.ibuf = ibuf;
+ key.image = image;
+ key.iuser_tile = iuser->tile;
+ key.x_tile = x_tile;
+ key.y_tile = y_tile;
+ PaintTile *existing_tile = nullptr;
+ paint_tile_map->map.add_or_modify(
+ key,
+ [&](PaintTile **pptile) { *pptile = ptile; },
+ [&](PaintTile **pptile) { existing_tile = *pptile; });
+ if (existing_tile) {
+ ptile_free(ptile);
+ ptile = existing_tile;
}
- BLI_addtail(paint_tiles, ptile);
if (use_thread_lock) {
BLI_spin_unlock(&paint_tiles_lock);
@@ -248,20 +289,20 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
return ptile->rect.pt;
}
-static void ptile_restore_runtime_list(ListBase *paint_tiles)
+static void ptile_restore_runtime_map(PaintTileMap *paint_tile_map)
{
ImBuf *tmpibuf = imbuf_alloc_temp_tile();
- LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
+ for (PaintTile *ptile : paint_tile_map->map.values()) {
Image *image = ptile->image;
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, NULL);
- const bool has_float = (ibuf->rect_float != NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, nullptr);
+ const bool has_float = (ibuf->rect_float != nullptr);
if (has_float) {
SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
}
else {
- SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ SWAP(uint32_t *, ptile->rect.uint, tmpibuf->rect);
}
IMB_rectcpy(ibuf,
@@ -277,7 +318,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
}
else {
- SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ SWAP(uint32_t *, ptile->rect.uint, tmpibuf->rect);
}
/* Force OpenGL reload (maybe partial update will operate better?) */
@@ -291,7 +332,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- BKE_image_release_ibuf(image, ibuf, NULL);
+ BKE_image_release_ibuf(image, ibuf, nullptr);
}
IMB_freeImBuf(tmpibuf);
@@ -303,35 +344,38 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
/** \name Image Undo Tile
* \{ */
-static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
+static uint32_t index_from_xy(uint32_t tile_x, uint32_t tile_y, const uint32_t tiles_dims[2])
{
BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
return (tile_y * tiles_dims[0]) + tile_x;
}
-typedef struct UndoImageTile {
+struct UndoImageTile {
union {
float *fp;
- uint *uint;
+ uint32_t *uint_ptr;
void *pt;
} rect;
int users;
-} UndoImageTile;
+};
static UndoImageTile *utile_alloc(bool has_float)
{
- UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile");
+ UndoImageTile *utile = static_cast<UndoImageTile *>(
+ MEM_callocN(sizeof(*utile), "ImageUndoTile"));
if (has_float) {
- utile->rect.fp = MEM_mallocN(sizeof(float[4]) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ utile->rect.fp = static_cast<float *>(
+ MEM_mallocN(sizeof(float[4]) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__));
}
else {
- utile->rect.uint = MEM_mallocN(sizeof(uint) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ utile->rect.uint_ptr = static_cast<uint32_t *>(
+ MEM_mallocN(sizeof(uint32_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__));
}
return utile;
}
static void utile_init_from_imbuf(
- UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
+ UndoImageTile *utile, const uint32_t x, const uint32_t y, const ImBuf *ibuf, ImBuf *tmpibuf)
{
const bool has_float = ibuf->rect_float;
@@ -339,7 +383,7 @@ static void utile_init_from_imbuf(
SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
}
else {
- SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ SWAP(uint32_t *, utile->rect.uint_ptr, tmpibuf->rect);
}
IMB_rectcpy(tmpibuf, ibuf, 0, 0, x, y, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
@@ -348,7 +392,7 @@ static void utile_init_from_imbuf(
SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
}
else {
- SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ SWAP(uint32_t *, utile->rect.uint_ptr, tmpibuf->rect);
}
}
@@ -357,13 +401,13 @@ static void utile_restore(
{
const bool has_float = ibuf->rect_float;
float *prev_rect_float = tmpibuf->rect_float;
- uint *prev_rect = tmpibuf->rect;
+ uint32_t *prev_rect = tmpibuf->rect;
if (has_float) {
tmpibuf->rect_float = utile->rect.fp;
}
else {
- tmpibuf->rect = utile->rect.uint;
+ tmpibuf->rect = utile->rect.uint_ptr;
}
IMB_rectcpy(ibuf, tmpibuf, x, y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
@@ -378,7 +422,7 @@ static void utile_decref(UndoImageTile *utile)
BLI_assert(utile->users >= 0);
if (utile->users == 0) {
MEM_freeN(utile->rect.pt);
- MEM_freeN(utile);
+ MEM_delete(utile);
}
}
@@ -388,7 +432,7 @@ static void utile_decref(UndoImageTile *utile)
/** \name Image Undo Buffer
* \{ */
-typedef struct UndoImageBuf {
+struct UndoImageBuf {
struct UndoImageBuf *next, *prev;
/**
@@ -401,23 +445,21 @@ typedef struct UndoImageBuf {
UndoImageTile **tiles;
/** Can calculate these from dims, just for convenience. */
- uint tiles_len;
- uint tiles_dims[2];
+ uint32_t tiles_len;
+ uint32_t tiles_dims[2];
- uint image_dims[2];
+ uint32_t image_dims[2];
/** Store variables from the image. */
struct {
short source;
bool use_float;
- char gen_type;
} image_state;
-
-} UndoImageBuf;
+};
static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
{
- UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__);
+ UndoImageBuf *ubuf = static_cast<UndoImageBuf *>(MEM_callocN(sizeof(*ubuf), __func__));
ubuf->image_dims[0] = ibuf->x;
ubuf->image_dims[1] = ibuf->y;
@@ -426,12 +468,12 @@ static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
- ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__);
+ ubuf->tiles = static_cast<UndoImageTile **>(
+ MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__));
BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
- ubuf->image_state.gen_type = image->gen_type;
ubuf->image_state.source = image->source;
- ubuf->image_state.use_float = ibuf->rect_float != NULL;
+ ubuf->image_state.use_float = ibuf->rect_float != nullptr;
return ubuf;
}
@@ -447,7 +489,7 @@ static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
- BLI_assert(ubuf->tiles[i] == NULL);
+ BLI_assert(ubuf->tiles[i] == nullptr);
UndoImageTile *utile = utile_alloc(has_float);
utile->users = 1;
utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
@@ -467,7 +509,7 @@ static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
{
/* We could have both float and rect buffers,
* in this case free the float buffer if it's unused. */
- if ((ibuf->rect_float != NULL) && (ubuf->image_state.use_float == false)) {
+ if ((ibuf->rect_float != nullptr) && (ubuf->image_state.use_float == false)) {
imb_freerectfloatImBuf(ibuf);
}
@@ -507,7 +549,7 @@ static void ubuf_free(UndoImageBuf *ubuf)
/** \name Image Undo Handle
* \{ */
-typedef struct UndoImageHandle {
+struct UndoImageHandle {
struct UndoImageHandle *next, *prev;
/** Each undo handle refers to a single image which may have multiple buffers. */
@@ -522,8 +564,7 @@ typedef struct UndoImageHandle {
* List of #UndoImageBuf's to support multiple buffers per image.
*/
ListBase buffers;
-
-} UndoImageHandle;
+};
static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
{
@@ -533,8 +574,8 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
/* Tiles only added to second set of tiles. */
Image *image = uh->image_ref.ptr;
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, &uh->iuser, NULL);
- if (UNLIKELY(ibuf == NULL)) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &uh->iuser, nullptr);
+ if (UNLIKELY(ibuf == nullptr)) {
CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
continue;
}
@@ -557,20 +598,20 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
if (changed) {
BKE_image_mark_dirty(image, ibuf);
- /* TODO(jbakker): only mark areas that are actually updated to improve performance. */
+ /* TODO(@jbakker): only mark areas that are actually updated to improve performance. */
BKE_image_partial_update_mark_full_update(image);
if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ ibuf->userflags |= IB_RECT_INVALID; /* Force recreate of char `rect` */
}
if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
DEG_id_tag_update(&image->id, 0);
}
- BKE_image_release_ibuf(image, ibuf, NULL);
+ BKE_image_release_ibuf(image, ibuf, nullptr);
}
IMB_freeImBuf(tmpibuf);
@@ -604,16 +645,16 @@ static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh,
return ubuf;
}
}
- return NULL;
+ return nullptr;
}
static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
{
- BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL);
+ BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == nullptr);
UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf);
BLI_addtail(&uh->buffers, ubuf);
- ubuf->post = NULL;
+ ubuf->post = nullptr;
return ubuf;
}
@@ -621,7 +662,7 @@ static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *
static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
{
UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
- if (ubuf == NULL) {
+ if (ubuf == nullptr) {
ubuf = uhandle_add_ubuf(uh, image, ibuf);
}
return ubuf;
@@ -636,7 +677,7 @@ static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles,
return uh;
}
}
- return NULL;
+ return nullptr;
}
static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
@@ -646,16 +687,16 @@ static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *imag
return uh;
}
}
- return NULL;
+ return nullptr;
}
static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageUser *iuser)
{
- BLI_assert(uhandle_lookup(undo_handles, image, iuser->tile) == NULL);
- UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
+ BLI_assert(uhandle_lookup(undo_handles, image, iuser->tile) == nullptr);
+ UndoImageHandle *uh = static_cast<UndoImageHandle *>(MEM_callocN(sizeof(*uh), __func__));
uh->image_ref.ptr = image;
uh->iuser = *iuser;
- uh->iuser.scene = NULL;
+ uh->iuser.scene = nullptr;
BLI_addtail(undo_handles, uh);
return uh;
}
@@ -663,7 +704,7 @@ static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageU
static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image, ImageUser *iuser)
{
UndoImageHandle *uh = uhandle_lookup(undo_handles, image, iuser->tile);
- if (uh == NULL) {
+ if (uh == nullptr) {
uh = uhandle_add(undo_handles, image, iuser);
}
return uh;
@@ -675,7 +716,7 @@ static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image, Ima
/** \name Implements ED Undo System
* \{ */
-typedef struct ImageUndoStep {
+struct ImageUndoStep {
UndoStep step;
/** #UndoImageHandle */
@@ -685,12 +726,11 @@ typedef struct ImageUndoStep {
* #PaintTile
* Run-time only data (active during a paint stroke).
*/
- ListBase paint_tiles;
+ PaintTileMap *paint_tile_map;
bool is_encode_init;
ePaintMode paint_mode;
-
-} ImageUndoStep;
+};
/**
* Find the previous undo buffer from this one.
@@ -703,7 +743,7 @@ static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
{
/* Use name lookup because the pointer is cleared for previous steps. */
UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image, tile_number);
- if (uh_prev != NULL) {
+ if (uh_prev != nullptr) {
UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
if (ubuf_reference) {
ubuf_reference = ubuf_reference->post;
@@ -713,7 +753,7 @@ static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
}
}
}
- return NULL;
+ return nullptr;
}
static bool image_undosys_poll(bContext *C)
@@ -737,11 +777,11 @@ static bool image_undosys_poll(bContext *C)
static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
/* dummy, memory is cleared anyway. */
us->is_encode_init = true;
BLI_listbase_clear(&us->handles);
- BLI_listbase_clear(&us->paint_tiles);
+ us->paint_tile_map = MEM_new<PaintTileMap>(__func__);
}
static bool image_undosys_step_encode(struct bContext *C,
@@ -753,7 +793,7 @@ static bool image_undosys_step_encode(struct bContext *C,
*
* This function ensures there are previous and current states of the image in the undo buffer.
*/
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
BLI_assert(us->step.data_size == 0);
@@ -761,39 +801,40 @@ static bool image_undosys_step_encode(struct bContext *C,
ImBuf *tmpibuf = imbuf_alloc_temp_tile();
- ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ ImageUndoStep *us_reference = reinterpret_cast<ImageUndoStep *>(
+ ED_undo_stack_get()->step_active);
while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
- us_reference = (ImageUndoStep *)us_reference->step.prev;
+ us_reference = reinterpret_cast<ImageUndoStep *>(us_reference->step.prev);
}
/* Initialize undo tiles from ptiles (if they exist). */
- for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
+ for (PaintTile *ptile : us->paint_tile_map->map.values()) {
if (ptile->valid) {
UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image, &ptile->iuser);
UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
- UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
+ UndoImageTile *utile = static_cast<UndoImageTile *>(
+ MEM_callocN(sizeof(*utile), "UndoImageTile"));
utile->users = 1;
utile->rect.pt = ptile->rect.pt;
- ptile->rect.pt = NULL;
+ ptile->rect.pt = nullptr;
const uint tile_index = index_from_xy(ptile->x_tile, ptile->y_tile, ubuf_pre->tiles_dims);
- BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
+ BLI_assert(ubuf_pre->tiles[tile_index] == nullptr);
ubuf_pre->tiles[tile_index] = utile;
}
- ptile_next = ptile->next;
ptile_free(ptile);
}
- BLI_listbase_clear(&us->paint_tiles);
+ us->paint_tile_map->map.clear();
LISTBASE_FOREACH (UndoImageHandle *, uh, &us->handles) {
LISTBASE_FOREACH (UndoImageBuf *, ubuf_pre, &uh->buffers) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, &uh->iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, &uh->iuser, nullptr);
const bool has_float = ibuf->rect_float;
- BLI_assert(ubuf_pre->post == NULL);
+ BLI_assert(ubuf_pre->post == nullptr);
ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
UndoImageBuf *ubuf_post = ubuf_pre->post;
@@ -806,7 +847,7 @@ static bool image_undosys_step_encode(struct bContext *C,
UndoImageBuf *ubuf_reference =
(us_reference ? ubuf_lookup_from_reference(
us_reference, uh->image_ref.ptr, uh->iuser.tile, ubuf_post) :
- NULL);
+ nullptr);
int i = 0;
for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
@@ -814,34 +855,35 @@ static bool image_undosys_step_encode(struct bContext *C,
for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
- if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) ||
- /* In this case the paint stroke as has added a tile
- * which we have a duplicate reference available. */
- (ubuf_pre->tiles[i]->users == 1))) {
- if (ubuf_pre->tiles[i] != NULL) {
+ if ((ubuf_reference != nullptr) &&
+ ((ubuf_pre->tiles[i] == nullptr) ||
+ /* In this case the paint stroke as has added a tile
+ * which we have a duplicate reference available. */
+ (ubuf_pre->tiles[i]->users == 1))) {
+ if (ubuf_pre->tiles[i] != nullptr) {
/* If we have a reference, re-use this single use tile for the post state. */
BLI_assert(ubuf_pre->tiles[i]->users == 1);
ubuf_post->tiles[i] = ubuf_pre->tiles[i];
- ubuf_pre->tiles[i] = NULL;
+ ubuf_pre->tiles[i] = nullptr;
utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
}
else {
- BLI_assert(ubuf_post->tiles[i] == NULL);
+ BLI_assert(ubuf_post->tiles[i] == nullptr);
ubuf_post->tiles[i] = ubuf_reference->tiles[i];
ubuf_post->tiles[i]->users += 1;
}
- BLI_assert(ubuf_pre->tiles[i] == NULL);
+ BLI_assert(ubuf_pre->tiles[i] == nullptr);
ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
ubuf_pre->tiles[i]->users += 1;
- BLI_assert(ubuf_pre->tiles[i] != NULL);
- BLI_assert(ubuf_post->tiles[i] != NULL);
+ BLI_assert(ubuf_pre->tiles[i] != nullptr);
+ BLI_assert(ubuf_post->tiles[i] != nullptr);
}
else {
UndoImageTile *utile = utile_alloc(has_float);
utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
- if (ubuf_pre->tiles[i] != NULL) {
+ if (ubuf_pre->tiles[i] != nullptr) {
ubuf_post->tiles[i] = utile;
utile->users = 1;
}
@@ -851,15 +893,15 @@ static bool image_undosys_step_encode(struct bContext *C,
utile->users = 2;
}
}
- BLI_assert(ubuf_pre->tiles[i] != NULL);
- BLI_assert(ubuf_post->tiles[i] != NULL);
+ BLI_assert(ubuf_pre->tiles[i] != nullptr);
+ BLI_assert(ubuf_post->tiles[i] != nullptr);
i += 1;
}
}
BLI_assert(i == ubuf_pre->tiles_len);
BLI_assert(i == ubuf_post->tiles_len);
}
- BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
+ BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, nullptr);
}
}
@@ -871,7 +913,7 @@ static bool image_undosys_step_encode(struct bContext *C,
}
}
else {
- BLI_assert(C != NULL);
+ BLI_assert(C != nullptr);
/* Happens when switching modes. */
ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
@@ -942,7 +984,7 @@ static void image_undosys_step_decode(
/* NOTE: behavior for undo/redo closely matches sculpt undo. */
BLI_assert(dir != STEP_INVALID);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
if (dir == STEP_UNDO) {
image_undosys_step_decode_undo(us, is_final);
}
@@ -951,7 +993,7 @@ static void image_undosys_step_decode(
}
if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set_ex(C, OB_MODE_TEXTURE_PAINT, false, NULL);
+ ED_object_mode_set_ex(C, OB_MODE_TEXTURE_PAINT, false, nullptr);
}
/* Refresh texture slots. */
@@ -963,15 +1005,16 @@ static void image_undosys_step_free(UndoStep *us_p)
ImageUndoStep *us = (ImageUndoStep *)us_p;
uhandle_free_list(&us->handles);
- /* Typically this list will have been cleared. */
- ptile_free_list(&us->paint_tiles);
+ /* Typically this map will have been cleared. */
+ MEM_delete(us->paint_tile_map);
+ us->paint_tile_map = nullptr;
}
static void image_undosys_foreach_ID_ref(UndoStep *us_p,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
void *user_data)
{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
LISTBASE_FOREACH (UndoImageHandle *, uh, &us->handles) {
foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
}
@@ -1011,12 +1054,12 @@ void ED_image_undosys_type(UndoType *ut)
* - So operators can access the pixel-data before the stroke was applied, at run-time.
* \{ */
-ListBase *ED_image_paint_tile_list_get(void)
+PaintTileMap *ED_image_paint_tile_map_get(void)
{
UndoStack *ustack = ED_undo_stack_get();
UndoStep *us_prev = ustack->step_init;
UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
/* We should always have an undo push started when accessing tiles,
* not doing this means we won't have paint_mode correctly set. */
BLI_assert(us_p == us_prev);
@@ -1024,24 +1067,24 @@ ListBase *ED_image_paint_tile_list_get(void)
/* Fallback value until we can be sure this never happens. */
us->paint_mode = PAINT_MODE_TEXTURE_2D;
}
- return &us->paint_tiles;
+ return us->paint_tile_map;
}
void ED_image_undo_restore(UndoStep *us)
{
- ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
- ptile_restore_runtime_list(paint_tiles);
- ptile_invalidate_list(paint_tiles);
+ PaintTileMap *paint_tile_map = reinterpret_cast<ImageUndoStep *>(us)->paint_tile_map;
+ ptile_restore_runtime_map(paint_tile_map);
+ ptile_invalidate_map(paint_tile_map);
}
static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
{
UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
+ bContext *C = nullptr; /* special case, we never read from this. */
UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
+ ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D, PAINT_MODE_SCULPT));
- us->paint_mode = paint_mode;
+ us->paint_mode = (ePaintMode)paint_mode;
return us;
}
@@ -1060,19 +1103,20 @@ void ED_image_undo_push_begin_with_image(const char *name,
BLI_assert(BKE_image_get_tile(image, iuser->tile));
UndoImageHandle *uh = uhandle_ensure(&us->handles, image, iuser);
UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
- BLI_assert(ubuf_pre->post == NULL);
+ BLI_assert(ubuf_pre->post == nullptr);
- ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ ImageUndoStep *us_reference = reinterpret_cast<ImageUndoStep *>(
+ ED_undo_stack_get()->step_active);
while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
- us_reference = (ImageUndoStep *)us_reference->step.prev;
+ us_reference = reinterpret_cast<ImageUndoStep *>(us_reference->step.prev);
}
UndoImageBuf *ubuf_reference = (us_reference ? ubuf_lookup_from_reference(
us_reference, image, iuser->tile, ubuf_pre) :
- NULL);
+ nullptr);
if (ubuf_reference) {
memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
- for (uint i = 0; i < ubuf_pre->tiles_len; i++) {
+ for (uint32_t i = 0; i < ubuf_pre->tiles_len; i++) {
UndoImageTile *utile = ubuf_pre->tiles[i];
utile->users += 1;
}
@@ -1085,7 +1129,7 @@ void ED_image_undo_push_begin_with_image(const char *name,
void ED_image_undo_push_end(void)
{
UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
+ BKE_undosys_step_push(ustack, nullptr, nullptr);
BKE_undosys_stack_limit_steps_and_memory_defaults(ustack);
WM_file_tag_modified();
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index ab8143c5bf5..67bff9677dc 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -20,6 +20,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_remap.h"
#include "BKE_screen.h"
@@ -298,7 +299,7 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
{
wmWindow *win = params->window;
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
SpaceImage *sima = (SpaceImage *)area->spacedata.first;
/* context changes */
@@ -351,7 +352,7 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
break;
case NC_MASK: {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (ED_space_image_check_show_maskedit(sima, obedit)) {
switch (wmn->data) {
case ND_SELECT:
@@ -393,7 +394,7 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
case ND_TRANSFORM:
case ND_MODIFIER: {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob && (ob == wmn->reference) && (ob->mode & OB_MODE_EDIT)) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
ED_area_tag_refresh(area);
@@ -694,6 +695,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
sima->mask_info.draw_flag & ~MASK_DRAWFLAG_OVERLAY,
sima->mask_info.draw_type,
sima->mask_info.overlay_mode,
+ sima->mask_info.blend_factor,
width,
height,
aspx,
@@ -712,7 +714,7 @@ static void image_main_region_listener(const wmRegionListenerParams *params)
{
ScrArea *area = params->area;
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -826,7 +828,7 @@ static void image_buttons_region_draw(const bContext *C, ARegion *region)
static void image_buttons_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -888,7 +890,7 @@ static void image_tools_region_draw(const bContext *C, ARegion *region)
static void image_tools_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -944,7 +946,7 @@ static void image_header_region_draw(const bContext *C, ARegion *region)
static void image_header_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index febb025f5bd..4e9df2b93b0 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -14,7 +14,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index 29a7eb150a1..a796ed5a817 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -161,42 +161,6 @@ static void stats_object(Object *ob,
stats->totlampsel++;
}
break;
- case OB_SURF:
- case OB_CURVES_LEGACY:
- case OB_FONT: {
- const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
- if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) {
- break;
- }
-
- if (stats_mesheval(me_eval, is_selected, stats)) {
- break;
- }
- ATTR_FALLTHROUGH; /* Fall-through to displist. */
- }
- case OB_MBALL: {
- int totv = 0, totf = 0, tottri = 0;
-
- if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
- /* NOTE: We only get the same curve_cache for instances of the same curve/font/...
- * For simple linked duplicated objects, each has its own dispList. */
- if (!BLI_gset_add(objects_gset, ob->runtime.curve_cache)) {
- break;
- }
-
- BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri);
- }
-
- stats->totvert += totv;
- stats->totface += totf;
- stats->tottri += tottri;
-
- if (is_selected) {
- stats->totvertsel += totv;
- stats->totfacesel += totf;
- }
- break;
- }
case OB_GPENCIL: {
if (is_selected) {
bGPdata *gpd = (bGPdata *)ob->data;
@@ -381,7 +345,7 @@ static void stats_object_sculpt(const Object *ob, SceneStats *stats)
stats->tottri = ob->sculpt->bm->totface;
break;
case PBVH_GRIDS:
- stats->totvertsculpt = BKE_pbvh_get_grid_num_vertices(ss->pbvh);
+ stats->totvertsculpt = BKE_pbvh_get_grid_num_verts(ss->pbvh);
stats->totfacesculpt = BKE_pbvh_get_grid_num_faces(ss->pbvh);
break;
}
@@ -393,8 +357,8 @@ static void stats_update(Depsgraph *depsgraph,
View3D *v3d_local,
SceneStats *stats)
{
- const Object *ob = OBACT(view_layer);
- const Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ const Object *ob = BKE_view_layer_active_object_get(view_layer);
+ const Object *obedit = BKE_view_layer_edit_object_get(view_layer);
memset(stats, 0x0, sizeof(*stats));
@@ -439,14 +403,7 @@ static void stats_update(Depsgraph *depsgraph,
}
else if (ob && (ob->mode & OB_MODE_SCULPT)) {
/* Sculpt Mode. */
- if (stats_is_object_dynamic_topology_sculpt(ob)) {
- /* Dynamic topology. Do not count all vertices,
- * dynamic topology stats are initialized later as part of sculpt stats. */
- }
- else {
- /* When dynamic topology is not enabled both sculpt stats and scene stats are collected. */
- stats_object_sculpt(ob, stats);
- }
+ stats_object_sculpt(ob, stats);
}
else {
/* Objects. */
@@ -535,7 +492,7 @@ static bool format_stats(
static void get_stats_string(
char *info, int len, size_t *ofs, ViewLayer *view_layer, SceneStatsFmt *stats_fmt)
{
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
LayerCollection *layer_collection = view_layer->active_collection;
@@ -727,7 +684,7 @@ void ED_info_draw_stats(
return;
}
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
const int font_id = BLF_set_default();
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 73d81c93981..1513ba5e892 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -186,7 +186,7 @@ static void info_header_region_draw(const bContext *C, ARegion *region)
static void info_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -202,7 +202,7 @@ static void info_main_region_listener(const wmRegionListenerParams *params)
static void info_header_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 8fc61f78a6c..9aa2b84169e 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -74,7 +74,7 @@ static void textview_draw_sel(const char *str,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ubv(bg_sel);
immRecti(pos, xy[0] + (cwidth * sta), xy[1] + lheight, xy[0] + (cwidth * end), xy[1]);
@@ -197,7 +197,7 @@ static bool textview_draw_string(TextViewDrawState *tds,
if (bg) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ubv(bg);
immRecti(pos, tds->draw_rect_outer->xmin, line_bottom, tds->draw_rect_outer->xmax, line_top);
immUnbindProgram();
@@ -245,9 +245,6 @@ static bool textview_draw_string(TextViewDrawState *tds,
const int final_offset = offsets[tot_lines - 1];
len = str_len - final_offset;
s = str + final_offset;
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + line_bottom + tds->row_vpadding, 0);
- BLF_color4ubv(tds->font_id, fg);
- BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
if (tds->sel[0] != tds->sel[1]) {
textview_step_sel(tds, -final_offset);
@@ -255,6 +252,10 @@ static bool textview_draw_string(TextViewDrawState *tds,
textview_draw_sel(s, pos, len, tds, bg_sel);
}
+ BLF_position(tds->font_id, tds->xy[0], tds->lofs + line_bottom + tds->row_vpadding, 0);
+ BLF_color4ubv(tds->font_id, fg);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
+
tds->xy[1] += tds->lheight;
BLF_color4ubv(tds->font_id, fg);
@@ -263,14 +264,14 @@ static bool textview_draw_string(TextViewDrawState *tds,
len = offsets[i] - offsets[i - 1];
s = str + offsets[i - 1];
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
- BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
-
if (tds->sel[0] != tds->sel[1]) {
textview_step_sel(tds, len);
textview_draw_sel(s, tds->xy, len, tds, bg_sel);
}
+ BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
+
tds->xy[1] += tds->lheight;
/* Check if we're out of view bounds. */
diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt
index 85a2c3fd0a1..e6995085dbe 100644
--- a/source/blender/editors/space_nla/CMakeLists.txt
+++ b/source/blender/editors/space_nla/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index f89bfd2a36a..9652819404e 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -79,7 +79,7 @@ bool nla_panel_context(const bContext *C,
*/
/* XXX: double-check active! */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ACTIVE |
- ANIMFILTER_LIST_CHANNELS);
+ ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -393,8 +393,8 @@ static void nla_panel_properties(const bContext *C, Panel *panel)
/* strip extents */
column = uiLayoutColumn(layout, true);
- uiItemR(column, &strip_ptr, "frame_start", 0, IFACE_("Frame Start"), ICON_NONE);
- uiItemR(column, &strip_ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "frame_start_ui", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "frame_end_ui", 0, IFACE_("End"), ICON_NONE);
/* Evaluation-Related Strip Properties ------------------ */
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 40082b08806..a0c6a29c422 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -68,7 +68,8 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
/* get the channel that was clicked on */
/* filter channels */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get channel from index */
@@ -394,7 +395,8 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
int filter;
/* filter channels */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* get channel from index */
@@ -561,7 +563,7 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
/* get a list of the (selected) NLA Tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* add tracks... */
@@ -608,7 +610,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac)
/* get a list of the selected AnimData blocks in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* check if selected AnimData blocks are empty, and add tracks if so... */
@@ -710,7 +712,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
/* get a list of the AnimData blocks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete tracks */
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 6c631f46069..e614055441d 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -101,7 +101,7 @@ static void nla_action_draw_keyframes(
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
@@ -178,7 +178,7 @@ static void nla_actionclip_draw_markers(
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (dashed) {
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -189,7 +189,7 @@ static void nla_actionclip_draw_markers(
immUniform1f("dash_factor", 0.5f);
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
immUniformThemeColorShade(TH_STRIP_SELECT, shade);
@@ -377,7 +377,7 @@ static uint nla_draw_use_dashed_outlines(const float color[4], bool muted)
/* Note that we use dashed shader here, and make it draw solid lines if not muted... */
uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -441,7 +441,7 @@ static void nla_draw_strip(SpaceNla *snla,
nla_strip_get_color_inside(adt, strip, color);
shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* draw extrapolation info first (as backdrop)
* - but this should only be drawn if track has some contribution
@@ -502,7 +502,7 @@ static void nla_draw_strip(SpaceNla *snla,
/* restore current vertex format & program (roundbox trashes it) */
shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
else {
/* strip is in disabled track - make less visible */
@@ -617,11 +617,10 @@ static void nla_draw_strip(SpaceNla *snla,
immUnbindProgram();
}
-/* add the relevant text to the cache of text-strings to draw in pixelspace */
+/** Add the relevant text to the cache of text-strings to draw in pixel-space. */
static void nla_draw_strip_text(AnimData *adt,
NlaTrack *nlt,
NlaStrip *strip,
- int index,
View2D *v2d,
float xminc,
float xmaxc,
@@ -636,7 +635,7 @@ static void nla_draw_strip_text(AnimData *adt,
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
+ str_len = BLI_snprintf_rlen(str, sizeof(str), "Temp-Meta");
}
else {
str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
@@ -702,6 +701,89 @@ static void nla_draw_strip_frames_text(
/* ---------------------- */
+/**
+ * Gets the first and last visible NLA strips on a track.
+ * Note that this also includes tracks that might only be
+ * visible because of their extendmode.
+ */
+static ListBase get_visible_nla_strips(NlaTrack *nlt, View2D *v2d)
+{
+ if (BLI_listbase_is_empty(&nlt->strips)) {
+ ListBase empty = {NULL, NULL};
+ return empty;
+ }
+
+ NlaStrip *first = NULL;
+ NlaStrip *last = NULL;
+
+ /* Find the first strip that is within the bounds of the view. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
+ if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ first = last = strip;
+ break;
+ }
+ }
+
+ const bool has_strips_within_bounds = first != NULL;
+
+ if (has_strips_within_bounds) {
+ /* Find the last visible strip. */
+ for (NlaStrip *strip = first->next; strip; strip = strip->next) {
+ if (!BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ break;
+ }
+ last = strip;
+ }
+ /* Check if the first strip is adjacent to a strip outside the view to the left
+ * that has an extendmode region that should be drawn.
+ * If so, adjust the first strip to include drawing that strip as well.
+ */
+ NlaStrip *prev = first->prev;
+ if (prev && prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ first = prev;
+ }
+ }
+ else {
+ /* No immediately visible strips.
+ * Figure out where our view is relative to the strips, then determine
+ * if the view is adjacent to a strip that should have its extendmode
+ * rendered.
+ */
+ NlaStrip *first_strip = nlt->strips.first;
+ NlaStrip *last_strip = nlt->strips.last;
+ if (first_strip && v2d->cur.xmax < first_strip->start &&
+ first_strip->extendmode == NLASTRIP_EXTEND_HOLD) {
+ /* The view is to the left of all strips and the first strip has an
+ * extendmode that should be drawn.
+ */
+ first = last = first_strip;
+ }
+ else if (last_strip && v2d->cur.xmin > last_strip->end &&
+ last_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ /* The view is to the right of all strips and the last strip has an
+ * extendmode that should be drawn.
+ */
+ first = last = last_strip;
+ }
+ else {
+ /* The view is in the middle of two strips. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
+ /* Find the strip to the left by finding the strip to the right and getting its prev. */
+ if (v2d->cur.xmax < strip->start) {
+ /* If the strip to the left has an extendmode, set that as the only visible strip. */
+ if (strip->prev && strip->prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ first = last = strip->prev;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ ListBase visible_strips = {first, last};
+ return visible_strips;
+}
+
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
{
View2D *v2d = &region->v2d;
@@ -710,7 +792,8 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
/* build list of channels to draw */
ListBase anim_data = {NULL, NULL};
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
@@ -737,29 +820,26 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
case ANIMTYPE_NLATRACK: {
AnimData *adt = ale->adt;
NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
- int index;
-
- /* draw each strip in the track (if visible) */
- for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
- if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
- const float xminc = strip->start + text_margin_x;
- const float xmaxc = strip->end - text_margin_x;
-
- /* draw the visualization of the strip */
- nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
-
- /* add the text for this strip to the cache */
- if (xminc < xmaxc) {
- nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax);
- }
-
- /* if transforming strips (only real reason for temp-metas currently),
- * add to the cache the frame numbers of the strip's extents
- */
- if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
- }
+ ListBase visible_nla_strips = get_visible_nla_strips(nlt, v2d);
+
+ /* Draw each visible strip in the track. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &visible_nla_strips) {
+ const float xminc = strip->start + text_margin_x;
+ const float xmaxc = strip->end - text_margin_x;
+
+ /* draw the visualization of the strip */
+ nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
+
+ /* add the text for this strip to the cache */
+ if (xminc < xmaxc) {
+ nla_draw_strip_text(adt, nlt, strip, v2d, xminc, xmaxc, ymin, ymax);
+ }
+
+ /* if transforming strips (only real reason for temp-metas currently),
+ * add to the cache the frame numbers of the strip's extents
+ */
+ if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
+ nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
}
}
break;
@@ -774,7 +854,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
* and a second darker rect within which we draw keyframe indicator dots if there's data
@@ -823,7 +903,8 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
size_t items;
/* build list of channels to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 81520445000..801d032a861 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -60,7 +60,8 @@ void ED_nla_postop_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
/* get blocks to work on */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -107,7 +108,7 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
}
/* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* if no blocks, popup error? */
@@ -211,7 +212,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
int filter;
/* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* if no blocks, popup error? */
@@ -318,7 +319,8 @@ static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const
bool found_bounds = false;
/* get data to filter */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* set large values to try to override */
@@ -436,7 +438,8 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *r_min, fl
short found = 0;
/* get all items - we need to do it this way */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through all channels, finding the first one that's selected */
@@ -625,7 +628,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
}
scene = ac.scene;
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
/* get action to use */
act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
@@ -654,7 +657,8 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
/* get a list of the editable tracks being shown in the NLA
* - this is limited to active ones for now, but could be expanded to
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
@@ -771,7 +775,8 @@ static int nlaedit_add_transition_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, find pairs of strips to add transitions to */
@@ -901,11 +906,11 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
}
scene = ac.scene;
- cfra = CFRA;
+ cfra = scene->r.cfra;
/* get a list of the editable tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT);
+ ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, add sound clips if it belongs to a speaker */
@@ -994,7 +999,8 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, find pairs of strips to add transitions to */
@@ -1070,7 +1076,8 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, find pairs of strips to add transitions to */
@@ -1140,7 +1147,8 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
}
/* get a list of editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* duplicate strips in tracks starting from the last one so that we're
@@ -1208,13 +1216,10 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
nlaedit_duplicate_exec(C, op);
- RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
- WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr, event);
-
return OPERATOR_FINISHED;
}
@@ -1240,9 +1245,6 @@ void NLA_OT_duplicate(wmOperatorType *ot)
false,
"Linked",
"When duplicating strips, assign new copies of the actions they use");
-
- /* to give to transform */
- RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/** \} */
@@ -1267,7 +1269,8 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, delete all selected strips */
@@ -1430,7 +1433,8 @@ static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, split all selected strips into two strips */
@@ -1518,7 +1522,8 @@ static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* go over all selected strips */
@@ -1587,7 +1592,8 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* consider each track in turn */
@@ -1769,7 +1775,8 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* since we're potentially moving strips from lower tracks to higher tracks, we should
@@ -1860,7 +1867,8 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* loop through the tracks in normal order, since we're pushing strips down,
@@ -1952,7 +1960,8 @@ static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
if (active_only) {
filter |= ANIMFILTER_ACTIVE;
}
@@ -2047,7 +2056,8 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Ensure that each action used only has a single user
@@ -2155,7 +2165,8 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, apply scale of all selected strips */
@@ -2187,8 +2198,13 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
/* setup iterator, and iterate over all the keyframes in the action,
* applying this scaling */
ked.data = strip;
- ANIM_animchanneldata_keyframes_loop(
- &ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
+ ANIM_animchanneldata_keyframes_loop(&ked,
+ ac.ads,
+ strip->act,
+ ALE_ACT,
+ NULL,
+ bezt_apply_nlamapping,
+ BKE_fcurve_handles_recalc);
/* clear scale of strip now that it has been applied,
* and recalculate the extents of the action now that it has been scaled
@@ -2265,7 +2281,8 @@ static int nlaedit_clear_scale_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, reset scale of all selected strips */
@@ -2350,7 +2367,8 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* get some necessary vars */
@@ -2388,7 +2406,7 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
/* calculate new start position based on snapping mode */
switch (mode) {
case NLAEDIT_SNAP_CFRA: /* to current frame */
- strip->start = (float)CFRA;
+ strip->start = (float)scene->r.cfra;
break;
case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
strip->start = floorf(start + 0.5f);
@@ -2544,7 +2562,8 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
@@ -2655,7 +2674,8 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
ANIM_fmodifiers_copybuf_free();
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
@@ -2734,7 +2754,7 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* get a list of the editable tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 902e7a176a3..3ae73282230 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -16,6 +16,8 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
+#include "RNA_access.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -138,6 +140,28 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_fmodifier_paste);
}
+void ED_operatormacros_nla()
+{
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("NLA_OT_duplicate_move",
+ "Duplicate",
+ "Duplicate selected strips and their Actions and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "NLA_OT_duplicate");
+ RNA_boolean_set(otmacro->ptr, "linked", false);
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+
+ ot = WM_operatortype_append_macro("NLA_OT_duplicate_linked_move",
+ "Duplicate Linked",
+ "Duplicate selected strips and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "NLA_OT_duplicate");
+ RNA_boolean_set(otmacro->ptr, "linked", true);
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+}
+
/* ************************** registration - keymaps **********************************/
void nla_keymap(wmKeyConfig *keyconf)
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 1efb91bc99f..a816f8fa4f6 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -85,7 +85,7 @@ static void deselect_nla_strips(bAnimContext *ac, short test, short sel)
/* determine type-based settings */
/* FIXME: double check whether ANIMFILTER_LIST_VISIBLE is needed! */
- filter = (ANIMFILTER_DATA_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -223,7 +223,8 @@ static void box_select_nla_strips(bAnimContext *ac, rcti rect, short mode, short
UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* convert selection modes to selection modes */
@@ -278,7 +279,8 @@ static void nlaedit_strip_at_region_position(
0, NLACHANNEL_STEP(snla), 0, NLACHANNEL_FIRST_TOP(ac), view_x, view_y, NULL, &channel_index);
ListBase anim_data = {NULL, NULL};
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click
@@ -455,17 +457,17 @@ static void nlaedit_select_leftright(bContext *C,
/* get range, and get the right flag-setting mode */
if (leftright == NLAEDIT_LRSEL_LEFT) {
xmin = MINAFRAMEF;
- xmax = (float)(CFRA + 0.1f);
+ xmax = (float)(scene->r.cfra + 0.1f);
}
else {
- xmin = (float)(CFRA - 0.1f);
+ xmin = (float)(scene->r.cfra - 0.1f);
xmax = MAXFRAMEF;
}
select_mode = selmodes_to_flagmodes(select_mode);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select strips on the side where most data occurs */
@@ -540,7 +542,7 @@ static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, const wm
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
- if (x < CFRA) {
+ if (x < scene->r.cfra) {
RNA_enum_set(op->ptr, "mode", NLAEDIT_LRSEL_LEFT);
}
else {
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 42d3d841f4b..ba7e8987dd5 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -79,7 +79,6 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene)
BLI_addtail(&snla->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
- region->flag = RGN_FLAG_HIDDEN;
/* main region */
region = MEM_callocN(sizeof(ARegion), "main region for nla");
@@ -87,9 +86,9 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene)
BLI_addtail(&snla->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
- region->v2d.tot.xmin = (float)(SFRA - 10);
+ region->v2d.tot.xmin = (float)(scene->r.sfra - 10);
region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
- region->v2d.tot.xmax = (float)(EFRA + 10);
+ region->v2d.tot.xmax = (float)(scene->r.efra + 10);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -235,7 +234,7 @@ static void nla_main_region_draw(const bContext *C, ARegion *region)
/* strips and backdrops */
draw_nla_main_data(&ac, snla, region);
- /* text draw cached, in pixelspace now */
+ /* Text draw cached, in pixel-space now. */
UI_view2d_text_cache_draw(region);
}
@@ -304,7 +303,7 @@ static void nla_buttons_region_draw(const bContext *C, ARegion *region)
static void nla_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -343,7 +342,7 @@ static void nla_region_listener(const wmRegionListenerParams *params)
static void nla_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -437,7 +436,7 @@ static void nla_main_region_message_subscribe(const wmRegionMessageSubscribePara
static void nla_channel_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -513,7 +512,7 @@ static void nla_channel_region_message_subscribe(const wmRegionMessageSubscribeP
static void nla_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index badcccca87b..8a1d47eaa8d 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -17,7 +17,6 @@ set(INC
../../nodes
../../render
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -50,8 +49,8 @@ set(LIB
bf_editor_screen
)
-if(WITH_COMPOSITOR)
- add_definitions(-DWITH_COMPOSITOR)
+if(WITH_COMPOSITOR_CPU)
+ add_definitions(-DWITH_COMPOSITOR_CPU)
endif()
if(WITH_OPENIMAGEDENOISE)
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 6806d715004..fbbdd40e92e 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -6,6 +6,7 @@
* \brief lower level node drawing for nodes (boarders, headers etc), also node layout.
*/
+#include "BLI_color.hh"
#include "BLI_system.h"
#include "BLI_threads.h"
@@ -329,7 +330,7 @@ static void node_buts_image_user(uiLayout *layout,
Scene *scene = CTX_data_scene(C);
char numstr[32];
- const int framenr = BKE_image_user_frame_get(iuser, CFRA, nullptr);
+ const int framenr = BKE_image_user_frame_get(iuser, scene->r.cfra, nullptr);
BLI_snprintf(numstr, sizeof(numstr), IFACE_("Frame: %d"), framenr);
uiItemL(layout, numstr, ICON_NONE);
}
@@ -477,7 +478,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_RGB:
ntype->draw_buttons = node_buts_rgb;
break;
- case SH_NODE_MIX_RGB:
+ case SH_NODE_MIX_RGB_LEGACY:
ntype->draw_buttons = node_buts_mix_rgb;
break;
case SH_NODE_VALTORGB:
@@ -626,7 +627,7 @@ static void node_composit_backdrop_viewer(
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
@@ -672,7 +673,7 @@ static void node_composit_backdrop_boxmask(
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
@@ -717,7 +718,7 @@ static void node_composit_backdrop_ellipsemask(
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
@@ -1455,7 +1456,11 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
}
case SOCK_BOOLEAN:
case SOCK_RGBA:
- case SOCK_STRING: {
+ case SOCK_STRING:
+ case SOCK_OBJECT:
+ case SOCK_COLLECTION:
+ case SOCK_TEXTURE:
+ case SOCK_MATERIAL: {
uiItemR(col, ptr, "default_value", DEFAULT_FLAGS, IFACE_("Default"), 0);
break;
}
@@ -1565,7 +1570,7 @@ void draw_nodespace_back_pix(const bContext &C,
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_ACTIVE);
immDrawBorderCorners(pos, &pixel_border, 1.0f, 1.0f);
@@ -1580,102 +1585,75 @@ void draw_nodespace_back_pix(const bContext &C,
GPU_matrix_pop();
}
-bool node_link_bezier_handles(const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink &link,
- float vec[4][2])
+static float2 socket_link_connection_location(const bNodeSocket &socket, const bNodeLink &link)
{
- float cursor[2] = {0.0f, 0.0f};
-
- /* this function can be called with snode null (via cut_links_intersect) */
- /* XXX map snode->runtime->cursor back to view space */
- if (snode) {
- cursor[0] = snode->runtime->cursor[0] * UI_DPI_FAC;
- cursor[1] = snode->runtime->cursor[1] * UI_DPI_FAC;
- }
-
- /* in v0 and v3 we put begin/end points */
- if (link.fromsock) {
- vec[0][0] = link.fromsock->locx;
- vec[0][1] = link.fromsock->locy;
- if (link.fromsock->flag & SOCK_MULTI_INPUT) {
- const float2 position = node_link_calculate_multi_input_position(
- {link.fromsock->locx, link.fromsock->locy},
- link.fromsock->total_inputs - 1,
- link.fromsock->total_inputs);
- copy_v2_v2(vec[0], position);
- }
- }
- else {
- if (snode == nullptr) {
- return false;
- }
- copy_v2_v2(vec[0], cursor);
+ const float2 socket_location(socket.locx, socket.locy);
+ if (socket.flag & SOCK_MULTI_INPUT && socket.in_out == SOCK_IN) {
+ return node_link_calculate_multi_input_position(
+ socket_location, link.multi_input_socket_index, socket.total_inputs);
}
- if (link.tosock) {
- vec[3][0] = link.tosock->locx;
- vec[3][1] = link.tosock->locy;
- if (!(link.tonode->flag & NODE_HIDDEN) && link.tosock->flag & SOCK_MULTI_INPUT) {
- const float2 position = node_link_calculate_multi_input_position(
- {link.tosock->locx, link.tosock->locy},
- link.multi_input_socket_index,
- link.tosock->total_inputs);
- copy_v2_v2(vec[3], position);
- }
- }
- else {
- if (snode == nullptr) {
- return false;
- }
- copy_v2_v2(vec[3], cursor);
- }
-
- /* may be called outside of drawing (so pass spacetype) */
- int curving = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE);
+ return socket_location;
+}
+static void calculate_inner_link_bezier_points(std::array<float2, 4> &points)
+{
+ const int curving = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE);
if (curving == 0) {
/* Straight line: align all points. */
- mid_v2_v2v2(vec[1], vec[0], vec[3]);
- mid_v2_v2v2(vec[2], vec[1], vec[3]);
- return true;
+ points[1] = math::interpolate(points[0], points[3], 1.0f / 3.0f);
+ points[2] = math::interpolate(points[0], points[3], 2.0f / 3.0f);
}
+ else {
+ const float dist = curving * 0.1f * math::distance(points[0].x, points[3].x);
- const float dist = curving * 0.10f * fabsf(vec[0][0] - vec[3][0]);
+ points[1].x = points[0].x + dist;
+ points[1].y = points[0].y;
- vec[1][0] = vec[0][0] + dist;
- vec[1][1] = vec[0][1];
+ points[2].x = points[3].x - dist;
+ points[2].y = points[3].y;
+ }
+}
- vec[2][0] = vec[3][0] - dist;
- vec[2][1] = vec[3][1];
+static std::array<float2, 4> node_link_bezier_points(const bNodeLink &link)
+{
+ std::array<float2, 4> points;
+ points[0] = socket_link_connection_location(*link.fromsock, link);
+ points[3] = socket_link_connection_location(*link.tosock, link);
+ calculate_inner_link_bezier_points(points);
+ return points;
+}
- if (v2d && min_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax) {
- return false; /* clipped */
+static bool node_link_draw_is_visible(const View2D &v2d, const std::array<float2, 4> &points)
+{
+ if (min_ffff(points[0].x, points[1].x, points[2].x, points[3].x) > v2d.cur.xmax) {
+ return false;
}
- if (v2d && max_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin) {
- return false; /* clipped */
+ if (max_ffff(points[0].x, points[1].x, points[2].x, points[3].x) < v2d.cur.xmin) {
+ return false;
}
-
return true;
}
-bool node_link_bezier_points(const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink &link,
- float coord_array[][2],
- const int resol)
+void node_link_bezier_points_evaluated(const bNodeLink &link,
+ std::array<float2, NODE_LINK_RESOL + 1> &coords)
{
- float vec[4][2];
-
- if (node_link_bezier_handles(v2d, snode, link, vec)) {
- /* always do all three, to prevent data hanging around */
- BKE_curve_forward_diff_bezier(
- vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0] + 0, resol, sizeof(float[2]));
- BKE_curve_forward_diff_bezier(
- vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0] + 1, resol, sizeof(float[2]));
+ const std::array<float2, 4> points = node_link_bezier_points(link);
- return true;
- }
- return false;
+ /* The extra +1 in size is required by these functions and would be removed ideally. */
+ BKE_curve_forward_diff_bezier(points[0].x,
+ points[1].x,
+ points[2].x,
+ points[3].x,
+ &coords[0].x,
+ NODE_LINK_RESOL,
+ sizeof(float2));
+ BKE_curve_forward_diff_bezier(points[0].y,
+ points[1].y,
+ points[2].y,
+ points[3].y,
+ &coords[0].y,
+ NODE_LINK_RESOL,
+ sizeof(float2));
}
#define NODELINK_GROUP_SIZE 256
@@ -1934,187 +1912,250 @@ void nodelink_batch_end(SpaceNode &snode)
g_batch_link.enabled = false;
}
+struct NodeLinkDrawConfig {
+ int th_col1;
+ int th_col2;
+ int th_col3;
+
+ ColorTheme4f start_color;
+ ColorTheme4f end_color;
+ ColorTheme4f outline_color;
+
+ bool drawarrow;
+ bool drawmuted;
+ bool highlighted;
+
+ float dim_factor;
+ float thickness;
+ float dash_factor;
+ float dash_alpha;
+};
+
static void nodelink_batch_add_link(const SpaceNode &snode,
- const float2 &p0,
- const float2 &p1,
- const float2 &p2,
- const float2 &p3,
- int th_col1,
- int th_col2,
- int th_col3,
- const float start_color[4],
- const float end_color[4],
- bool drawarrow,
- bool drawmuted,
- float dim_factor,
- float thickness,
- float dash_factor,
- float dash_alpha)
+ const std::array<float2, 4> &points,
+ const NodeLinkDrawConfig &draw_config)
{
/* Only allow these colors. If more is needed, you need to modify the shader accordingly. */
- BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
- BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
- BLI_assert(ELEM(th_col3, TH_WIRE, TH_REDALERT, -1));
+ BLI_assert(
+ ELEM(draw_config.th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
+ BLI_assert(
+ ELEM(draw_config.th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
+ BLI_assert(ELEM(draw_config.th_col3, TH_WIRE, TH_REDALERT, -1));
g_batch_link.count++;
- copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p0_step), p0);
- copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p1_step), p1);
- copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p2_step), p2);
- copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p3_step), p3);
+ copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p0_step), points[0]);
+ copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p1_step), points[1]);
+ copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p2_step), points[2]);
+ copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p3_step), points[3]);
char *colid = (char *)GPU_vertbuf_raw_step(&g_batch_link.colid_step);
- colid[0] = nodelink_get_color_id(th_col1);
- colid[1] = nodelink_get_color_id(th_col2);
- colid[2] = nodelink_get_color_id(th_col3);
- colid[3] = drawarrow;
- copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.start_color_step), start_color);
- copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.end_color_step), end_color);
+ colid[0] = nodelink_get_color_id(draw_config.th_col1);
+ colid[1] = nodelink_get_color_id(draw_config.th_col2);
+ colid[2] = nodelink_get_color_id(draw_config.th_col3);
+ colid[3] = draw_config.drawarrow;
+ copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.start_color_step),
+ draw_config.start_color);
+ copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.end_color_step), draw_config.end_color);
char *muted = (char *)GPU_vertbuf_raw_step(&g_batch_link.muted_step);
- muted[0] = drawmuted;
- *(float *)GPU_vertbuf_raw_step(&g_batch_link.dim_factor_step) = dim_factor;
- *(float *)GPU_vertbuf_raw_step(&g_batch_link.thickness_step) = thickness;
- *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_factor_step) = dash_factor;
- *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_alpha_step) = dash_alpha;
+ muted[0] = draw_config.drawmuted;
+ *(float *)GPU_vertbuf_raw_step(&g_batch_link.dim_factor_step) = draw_config.dim_factor;
+ *(float *)GPU_vertbuf_raw_step(&g_batch_link.thickness_step) = draw_config.thickness;
+ *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_factor_step) = draw_config.dash_factor;
+ *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_alpha_step) = draw_config.dash_alpha;
if (g_batch_link.count == NODELINK_GROUP_SIZE) {
nodelink_batch_draw(snode);
}
}
-void node_draw_link_bezier(const bContext &C,
- const View2D &v2d,
- const SpaceNode &snode,
- const bNodeLink &link,
- const int th_col1,
- const int th_col2,
- const int th_col3,
- const bool selected)
+static void node_draw_link_end_marker(const float2 center,
+ const float radius,
+ const ColorTheme4f &color)
{
- const float dim_factor = selected ? 1.0f : node_link_dim_factor(v2d, link);
- float thickness = 1.5f;
- float dash_factor = 1.0f;
+ rctf rect;
+ BLI_rctf_init(&rect, center.x - radius, center.x + radius, center.y - radius, center.y + radius);
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rect, true, radius, color);
+ /* Roundbox disables alpha. Reenable it for node links that are drawn after this one. */
+ GPU_blend(GPU_BLEND_ALPHA);
+}
+
+static void node_draw_link_end_markers(const bNodeLink &link,
+ const NodeLinkDrawConfig &draw_config,
+ const std::array<float2, 4> &points,
+ const bool outline)
+{
+ const float radius = (outline ? 0.65f : 0.45f) * NODE_SOCKSIZE;
+ if (link.fromsock) {
+ node_draw_link_end_marker(
+ points[0], radius, outline ? draw_config.outline_color : draw_config.start_color);
+ }
+ if (link.tosock) {
+ node_draw_link_end_marker(
+ points[3], radius, outline ? draw_config.outline_color : draw_config.end_color);
+ }
+}
+
+static bool node_link_is_field_link(const SpaceNode &snode, const bNodeLink &link)
+{
+ if (snode.edittree->type != NTREE_GEOMETRY) {
+ return false;
+ }
+ if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
+ return true;
+ }
+ return false;
+}
+
+static NodeLinkDrawConfig nodelink_get_draw_config(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
+ const int th_col1,
+ const int th_col2,
+ const int th_col3,
+ const bool selected)
+{
+ NodeLinkDrawConfig draw_config;
+
+ draw_config.th_col1 = th_col1;
+ draw_config.th_col2 = th_col2;
+ draw_config.th_col3 = th_col3;
+
+ draw_config.dim_factor = selected ? 1.0f : node_link_dim_factor(v2d, link);
bTheme *btheme = UI_GetTheme();
- const float dash_alpha = btheme->space_node.dash_alpha;
-
- if (snode.edittree->type == NTREE_GEOMETRY) {
- if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
- /* Make field links a bit thinner. */
- thickness = 1.0f;
- /* Draw field as dashes. */
- dash_factor = 0.75f;
+ draw_config.dash_alpha = btheme->space_node.dash_alpha;
+
+ const bool field_link = node_link_is_field_link(snode, link);
+
+ draw_config.dash_factor = field_link ? 0.75f : 1.0f;
+
+ const float scale = UI_view2d_scale_get_x(&v2d);
+ /* Clamp the thickness to make the links more readable when zooming out. */
+ draw_config.thickness = max_ff(scale, 1.0f) * (field_link ? 0.7f : 1.0f);
+ draw_config.highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT;
+ draw_config.drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) &&
+ (link.fromnode && (link.fromnode->type == NODE_REROUTE)));
+ draw_config.drawmuted = (link.flag & NODE_LINK_MUTED);
+
+ UI_GetThemeColor4fv(th_col3, draw_config.outline_color);
+
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
+ snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
+ PointerRNA from_node_ptr, to_node_ptr;
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
+
+ if (link.fromsock) {
+ node_socket_color_get(
+ C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.start_color);
+ }
+ else {
+ node_socket_color_get(
+ C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.start_color);
}
- }
- float vec[4][2];
- const bool highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT;
- if (node_link_bezier_handles(&v2d, &snode, link, vec)) {
- int drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) &&
- (link.fromnode && (link.fromnode->type == NODE_REROUTE)));
- int drawmuted = (link.flag & NODE_LINK_MUTED);
- if (g_batch_link.batch == nullptr) {
- nodelink_batch_init();
+ if (link.tosock) {
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.end_color);
}
- /* Draw single link. */
- float colors[3][4] = {{0.0f}};
- if (th_col3 != -1) {
- UI_GetThemeColor4fv(th_col3, colors[0]);
+ else {
+ node_socket_color_get(
+ C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.end_color);
}
+ }
+ else {
+ UI_GetThemeColor4fv(th_col1, draw_config.start_color);
+ UI_GetThemeColor4fv(th_col2, draw_config.end_color);
+ }
+
+ /* Highlight links connected to selected nodes. */
+ if (selected) {
+ ColorTheme4f color_selected;
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected);
+ const float alpha = color_selected.a;
- if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
- snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
- PointerRNA from_node_ptr, to_node_ptr;
- RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
- RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
+ /* Interpolate color if highlight color is not fully transparent. */
+ if (alpha != 0.0) {
if (link.fromsock) {
- node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[1]);
- }
- else {
- node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[1]);
+ interp_v3_v3v3(draw_config.start_color, draw_config.start_color, color_selected, alpha);
}
-
if (link.tosock) {
- node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[2]);
- }
- else {
- node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[2]);
+ interp_v3_v3v3(draw_config.end_color, draw_config.end_color, color_selected, alpha);
}
}
- else {
- UI_GetThemeColor4fv(th_col1, colors[1]);
- UI_GetThemeColor4fv(th_col2, colors[2]);
- }
+ }
- /* Highlight links connected to selected nodes. */
- if (selected) {
- float color_selected[4];
- UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected);
- const float alpha = color_selected[3];
+ if (draw_config.highlighted) {
+ ColorTheme4f link_preselection_highlight_color;
+ UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color);
+ /* Multi sockets can only be inputs. So we only have to highlight the end of the link. */
+ copy_v4_v4(draw_config.end_color, link_preselection_highlight_color);
+ }
- /* Interpolate color if highlight color is not fully transparent. */
- if (alpha != 0.0) {
- if (link.fromsock) {
- interp_v3_v3v3(colors[1], colors[1], color_selected, alpha);
- }
- if (link.tosock) {
- interp_v3_v3v3(colors[2], colors[2], color_selected, alpha);
- }
- }
- }
+ return draw_config;
+}
- if (g_batch_link.enabled && !highlighted) {
- /* Add link to batch. */
- nodelink_batch_add_link(snode,
- vec[0],
- vec[1],
- vec[2],
- vec[3],
- th_col1,
- th_col2,
- th_col3,
- colors[1],
- colors[2],
- drawarrow,
- drawmuted,
- dim_factor,
- thickness,
- dash_factor,
- dash_alpha);
- }
- else {
- if (highlighted) {
- float link_preselection_highlight_color[4];
- UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color);
- copy_v4_v4(colors[2], link_preselection_highlight_color);
- }
+static void node_draw_link_bezier_ex(const SpaceNode &snode,
+ const NodeLinkDrawConfig &draw_config,
+ const std::array<float2, 4> &points)
+{
+ if (g_batch_link.batch == nullptr) {
+ nodelink_batch_init();
+ }
- NodeLinkData node_link_data;
- for (int i = 0; i < 4; i++) {
- copy_v2_v2(node_link_data.bezierPts[i], vec[i]);
- }
- for (int i = 0; i < 3; i++) {
- copy_v4_v4(node_link_data.colors[i], colors[i]);
- }
- node_link_data.doArrow = drawarrow;
- node_link_data.doMuted = drawmuted;
- node_link_data.dim_factor = dim_factor;
- node_link_data.thickness = thickness;
- node_link_data.dash_factor = dash_factor;
- node_link_data.dash_alpha = dash_alpha;
- node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
- node_link_data.arrowSize = ARROW_SIZE;
-
- GPUBatch *batch = g_batch_link.batch_single;
- GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
- sizeof(NodeLinkData), &node_link_data, __func__);
-
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
- GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo);
- GPU_batch_draw(batch);
-
- GPU_uniformbuf_unbind(ubo);
- GPU_uniformbuf_free(ubo);
+ if (g_batch_link.enabled && !draw_config.highlighted) {
+ /* Add link to batch. */
+ nodelink_batch_add_link(snode, points, draw_config);
+ }
+ else {
+ NodeLinkData node_link_data;
+ for (const int i : IndexRange(points.size())) {
+ copy_v2_v2(node_link_data.bezierPts[i], points[i]);
}
+
+ copy_v4_v4(node_link_data.colors[0], draw_config.outline_color);
+ copy_v4_v4(node_link_data.colors[1], draw_config.start_color);
+ copy_v4_v4(node_link_data.colors[2], draw_config.end_color);
+
+ node_link_data.doArrow = draw_config.drawarrow;
+ node_link_data.doMuted = draw_config.drawmuted;
+ node_link_data.dim_factor = draw_config.dim_factor;
+ node_link_data.thickness = draw_config.thickness;
+ node_link_data.dash_factor = draw_config.dash_factor;
+ node_link_data.dash_alpha = draw_config.dash_alpha;
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
+
+ GPUBatch *batch = g_batch_link.batch_single;
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(NodeLinkData), &node_link_data, __func__);
+
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
+ GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo);
+ GPU_batch_draw(batch);
+
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
+ }
+}
+
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
+ const int th_col1,
+ const int th_col2,
+ const int th_col3,
+ const bool selected)
+{
+ const std::array<float2, 4> points = node_link_bezier_points(link);
+ if (!node_link_draw_is_visible(v2d, points)) {
+ return;
}
+ const NodeLinkDrawConfig draw_config = nodelink_get_draw_config(
+ C, v2d, snode, link, th_col1, th_col2, th_col3, selected);
+
+ node_draw_link_bezier_ex(snode, draw_config, points);
}
void node_draw_link(const bContext &C,
@@ -2129,34 +2170,29 @@ void node_draw_link(const bContext &C,
return;
}
- /* new connection */
- if (!link.fromsock || !link.tosock) {
- th_col1 = th_col2 = TH_ACTIVE;
+ /* going to give issues once... */
+ if (link.tosock->flag & SOCK_UNAVAIL) {
+ return;
+ }
+ if (link.fromsock->flag & SOCK_UNAVAIL) {
+ return;
}
- else {
- /* going to give issues once... */
- if (link.tosock->flag & SOCK_UNAVAIL) {
- return;
- }
- if (link.fromsock->flag & SOCK_UNAVAIL) {
- return;
- }
- if (link.flag & NODE_LINK_VALID) {
- /* special indicated link, on drop-node */
- if (link.flag & NODE_LINKFLAG_HILITE) {
- th_col1 = th_col2 = TH_ACTIVE;
- }
- else if (link.flag & NODE_LINK_MUTED) {
- th_col1 = th_col2 = TH_REDALERT;
- }
+ if (link.flag & NODE_LINK_VALID) {
+ /* special indicated link, on drop-node */
+ if (link.flag & NODE_LINKFLAG_HILITE) {
+ th_col1 = th_col2 = TH_ACTIVE;
}
- else {
- /* Invalid link. */
- th_col1 = th_col2 = th_col3 = TH_REDALERT;
- // th_col3 = -1; /* no shadow */
+ else if (link.flag & NODE_LINK_MUTED) {
+ th_col1 = th_col2 = TH_REDALERT;
}
}
+ else {
+ /* Invalid link. */
+ th_col1 = th_col2 = th_col3 = TH_REDALERT;
+ // th_col3 = -1; /* no shadow */
+ }
+
/* Links from field to non-field sockets are not allowed. */
if (snode.edittree->type == NTREE_GEOMETRY && !(link.flag & NODE_LINK_DRAGGED)) {
if ((link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
@@ -2168,6 +2204,38 @@ void node_draw_link(const bContext &C,
node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3, selected);
}
+static std::array<float2, 4> node_link_bezier_points_dragged(const SpaceNode &snode,
+ const bNodeLink &link)
+{
+ const float2 cursor = snode.runtime->cursor * UI_DPI_FAC;
+ std::array<float2, 4> points;
+ points[0] = link.fromsock ? socket_link_connection_location(*link.fromsock, link) : cursor;
+ points[3] = link.tosock ? socket_link_connection_location(*link.tosock, link) : cursor;
+ calculate_inner_link_bezier_points(points);
+ return points;
+}
+
+void node_draw_link_dragged(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link)
+{
+ if (link.fromsock == nullptr && link.tosock == nullptr) {
+ return;
+ }
+
+ const std::array<float2, 4> points = node_link_bezier_points_dragged(snode, link);
+
+ const NodeLinkDrawConfig draw_config = nodelink_get_draw_config(
+ C, v2d, snode, link, TH_ACTIVE, TH_ACTIVE, TH_WIRE, true);
+ /* End marker outline. */
+ node_draw_link_end_markers(link, draw_config, points, true);
+ /* Link. */
+ node_draw_link_bezier_ex(snode, draw_config, points);
+ /* End marker fill. */
+ node_draw_link_end_markers(link, draw_config, points, false);
+}
+
} // namespace blender::ed::space_node
void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos)
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index c524de2c55d..553d4013324 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -232,6 +232,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
RNA_boolean_set(&ptr, "view2d_edge_pan", true);
+ RNA_boolean_set(&ptr, "remove_on_cancel", true);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr);
WM_operator_properties_free(&ptr);
}
@@ -292,7 +293,7 @@ static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *ar
0,
nullptr);
- const int offset[2] = {0, -UI_UNIT_Y};
+ const int2 offset = {0, -UI_UNIT_Y};
UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset);
return block;
}
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 975d4eda7e3..9949037479e 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -5,6 +5,8 @@
* \ingroup spnode
*/
+#include <numeric>
+
#include "MEM_guardedalloc.h"
#include "DNA_collection_types.h"
@@ -20,6 +22,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -49,29 +52,48 @@ namespace blender::ed::space_node {
/** \name Utilities
* \{ */
-bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
+static void position_node_based_on_mouse(bNode &node, const float2 &location)
+{
+ node.locx = location.x - NODE_DY * 1.5f / UI_DPI_FAC;
+ node.locy = location.y + NODE_DY * 0.5f / UI_DPI_FAC;
+}
+
+bNode *add_node(const bContext &C, const StringRef idname, const float2 &location)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
Main &bmain = *CTX_data_main(&C);
- bNode *node = nullptr;
node_deselect_all(snode);
- if (idname) {
- node = nodeAddNode(&C, snode.edittree, idname);
- }
- else {
- node = nodeAddStaticNode(&C, snode.edittree, type);
- }
+ const std::string idname_str = idname;
+
+ bNode *node = nodeAddNode(&C, snode.edittree, idname_str.c_str());
BLI_assert(node && node->typeinfo);
- /* Position mouse in node header. */
- node->locx = locx - NODE_DY * 1.5f / UI_DPI_FAC;
- node->locy = locy + NODE_DY * 0.5f / UI_DPI_FAC;
+ position_node_based_on_mouse(*node, location);
nodeSetSelected(node, true);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
+ ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
+ return node;
+}
+
+bNode *add_static_node(const bContext &C, int type, const float2 &location)
+{
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ Main &bmain = *CTX_data_main(&C);
+
+ node_deselect_all(snode);
+
+ bNode *node = nodeAddStaticNode(&C, snode.edittree, type);
+ BLI_assert(node && node->typeinfo);
+
+ position_node_based_on_mouse(*node, location);
+
+ nodeSetSelected(node, true);
ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
+
ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
return node;
}
@@ -82,191 +104,113 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx
/** \name Add Reroute Operator
* \{ */
-static bool add_reroute_intersect_check(const bNodeLink &link,
- float mcoords[][2],
- int tot,
- float result[2])
+std::optional<float2> link_path_intersection(const bNodeLink &link, const Span<float2> path)
{
- float coord_array[NODE_LINK_RESOL + 1][2];
-
- if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) {
- for (int i = 0; i < tot - 1; i++) {
- for (int b = 0; b < NODE_LINK_RESOL; b++) {
- if (isect_seg_seg_v2_point(
- mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1], result) > 0) {
- return true;
- }
+ std::array<float2, NODE_LINK_RESOL + 1> coords;
+ node_link_bezier_points_evaluated(link, coords);
+
+ for (const int i : path.index_range().drop_back(1)) {
+ for (const int j : IndexRange(NODE_LINK_RESOL)) {
+ float2 result;
+ if (isect_seg_seg_v2_point(path[i], path[i + 1], coords[j], coords[j + 1], result) > 0) {
+ return result;
}
}
}
- return false;
-}
-struct bNodeSocketLink {
- struct bNodeSocketLink *next, *prev;
+ return std::nullopt;
+}
- struct bNodeSocket *sock;
- struct bNodeLink *link;
- float point[2];
+struct RerouteCutsForSocket {
+ /* The output socket's owner node. */
+ bNode *from_node;
+ /* Intersected links connected to the socket and their path intersection locations. */
+ Map<bNodeLink *, float2> links;
};
-static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
- bNodeSocket *sock,
- bNodeLink *link,
- const float point[2])
+static int add_reroute_exec(bContext *C, wmOperator *op)
{
- bNodeSocketLink *socklink, *prev;
-
- socklink = MEM_cnew<bNodeSocketLink>("socket link");
- socklink->sock = sock;
- socklink->link = link;
- copy_v2_v2(socklink->point, point);
+ const ARegion &region = *CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
- for (prev = (bNodeSocketLink *)lb->last; prev; prev = prev->prev) {
- if (prev->sock == sock) {
+ Vector<float2> path;
+ RNA_BEGIN (op->ptr, itemptr, "path") {
+ float2 loc_region;
+ RNA_float_get_array(&itemptr, "loc", loc_region);
+ float2 loc_view;
+ UI_view2d_region_to_view(&region.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y);
+ path.append(loc_view);
+ if (path.size() >= 256) {
break;
}
}
- BLI_insertlinkafter(lb, prev, socklink);
- return socklink;
-}
-
-static bNodeSocketLink *add_reroute_do_socket_section(bContext *C,
- bNodeSocketLink *socklink,
- int in_out)
-{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNode *reroute_node = nullptr;
- bNodeSocket *cursock = socklink->sock;
- float insert_point[2];
- int num_links;
-
- zero_v2(insert_point);
- num_links = 0;
-
- while (socklink && socklink->sock == cursock) {
- if (!(socklink->link->flag & NODE_LINK_TEST)) {
- socklink->link->flag |= NODE_LINK_TEST;
-
- /* create the reroute node for this cursock */
- if (!reroute_node) {
- reroute_node = nodeAddStaticNode(C, ntree, NODE_REROUTE);
-
- /* add a single link to/from the reroute node to replace multiple links */
- if (in_out == SOCK_OUT) {
- nodeAddLink(ntree,
- socklink->link->fromnode,
- socklink->link->fromsock,
- reroute_node,
- (bNodeSocket *)reroute_node->inputs.first);
- }
- else {
- nodeAddLink(ntree,
- reroute_node,
- (bNodeSocket *)reroute_node->outputs.first,
- socklink->link->tonode,
- socklink->link->tosock);
- }
- }
-
- /* insert the reroute node into the link */
- if (in_out == SOCK_OUT) {
- socklink->link->fromnode = reroute_node;
- socklink->link->fromsock = (bNodeSocket *)reroute_node->outputs.first;
- }
- else {
- socklink->link->tonode = reroute_node;
- socklink->link->tosock = (bNodeSocket *)reroute_node->inputs.first;
- }
-
- add_v2_v2(insert_point, socklink->point);
- num_links++;
- }
- socklink = socklink->next;
- }
-
- if (num_links > 0) {
- /* average cut point from shared links */
- mul_v2_fl(insert_point, 1.0f / num_links);
+ RNA_END;
- reroute_node->locx = insert_point[0] / UI_DPI_FAC;
- reroute_node->locy = insert_point[1] / UI_DPI_FAC;
+ if (path.is_empty()) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- return socklink;
-}
+ ntree.ensure_topology_cache();
+ const Vector<bNode *> frame_nodes = ntree.nodes_by_type("NodeFrame");
-static int add_reroute_exec(bContext *C, wmOperator *op)
-{
- SpaceNode &snode = *CTX_wm_space_node(C);
- ARegion &region = *CTX_wm_region(C);
- bNodeTree &ntree = *snode.edittree;
- float mcoords[256][2];
- int i = 0;
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+ node_deselect_all(snode);
- /* Get the cut path */
- RNA_BEGIN (op->ptr, itemptr, "path") {
- float loc[2];
+ /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per
+ * output socket is useful because it allows reusing reroutes for connected intersections.
+ * Further deduplication using the second map means we only have one cut per link. */
+ Map<bNodeSocket *, RerouteCutsForSocket> cuts_per_socket;
- RNA_float_get_array(&itemptr, "loc", loc);
- UI_view2d_region_to_view(
- &region.v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
- i++;
- if (i >= 256) {
- break;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
+ continue;
+ }
+ const std::optional<float2> intersection = link_path_intersection(*link, path);
+ if (!intersection) {
+ continue;
}
+ RerouteCutsForSocket &from_cuts = cuts_per_socket.lookup_or_add_default(link->fromsock);
+ from_cuts.from_node = link->fromnode;
+ from_cuts.links.add(link, *intersection);
}
- RNA_END;
-
- if (i > 1) {
- ListBase output_links, input_links;
- bNodeSocketLink *socklink;
- float insert_point[2];
- /* always first */
- ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+ for (const auto item : cuts_per_socket.items()) {
+ const Map<bNodeLink *, float2> &cuts = item.value.links;
- node_deselect_all(snode);
+ bNode *reroute = nodeAddStaticNode(C, &ntree, NODE_REROUTE);
- /* Find cut links and sort them by sockets */
- BLI_listbase_clear(&output_links);
- BLI_listbase_clear(&input_links);
+ nodeAddLink(&ntree,
+ item.value.from_node,
+ item.key,
+ reroute,
+ static_cast<bNodeSocket *>(reroute->inputs.first));
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
- continue;
- }
- if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) {
- add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point);
- add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point);
-
- /* Clear flag */
- link->flag &= ~NODE_LINK_TEST;
- }
+ /* Reconnect links from the original output socket to the new reroute. */
+ for (bNodeLink *link : cuts.keys()) {
+ link->fromnode = reroute;
+ link->fromsock = static_cast<bNodeSocket *>(reroute->outputs.first);
+ BKE_ntree_update_tag_link_changed(&ntree);
}
- /* Create reroute nodes for intersected links.
- * Only one reroute if links share the same input/output socket.
- */
- socklink = (bNodeSocketLink *)output_links.first;
- while (socklink) {
- socklink = add_reroute_do_socket_section(C, socklink, SOCK_OUT);
- }
- socklink = (bNodeSocketLink *)input_links.first;
- while (socklink) {
- socklink = add_reroute_do_socket_section(C, socklink, SOCK_IN);
+ /* Place the new reroute at the average location of all connected cuts. */
+ const float2 loc = std::accumulate(cuts.values().begin(), cuts.values().end(), float2(0)) /
+ cuts.size() / UI_DPI_FAC;
+ reroute->locx = loc.x;
+ reroute->locy = loc.y;
+
+ /* Attach the reroute node to frame nodes behind it. */
+ for (const int i : frame_nodes.index_range()) {
+ bNode *frame_node = frame_nodes.last(i);
+ if (BLI_rctf_isect_pt_v(&frame_node->totr, loc)) {
+ nodeAttachNode(reroute, frame_node);
+ break;
+ }
}
-
- BLI_freelistN(&output_links);
- BLI_freelistN(&input_links);
-
- /* always last */
- ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
- return OPERATOR_FINISHED;
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
+ return OPERATOR_FINISHED;
}
void NODE_OT_add_reroute(wmOperatorType *ot)
@@ -338,9 +282,9 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
- bNodeTree *node_group;
- if (!(node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree))) {
+ bNodeTree *node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree);
+ if (!node_group) {
return OPERATOR_CANCELLED;
}
@@ -352,12 +296,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- bNode *group_node = node_add_node(*C,
- node_idname,
- (node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
- NODE_GROUP,
- snode->runtime->cursor[0],
- snode->runtime->cursor[1]);
+ bNode *group_node = add_node(*C, node_idname, snode->runtime->cursor);
if (!group_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node group");
return OPERATOR_CANCELLED;
@@ -382,7 +321,7 @@ static bool node_add_group_poll(bContext *C)
if (snode->edittree->type == NTREE_CUSTOM) {
CTX_wm_operator_poll_msg_set(C,
"This node editor displays a custom (Python defined) node tree. "
- "Dropping node groups isn't supported for this.");
+ "Dropping node groups isn't supported for this");
return false;
}
return true;
@@ -445,8 +384,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *object_node = node_add_node(
- *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor);
if (!object_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node object");
return OPERATOR_CANCELLED;
@@ -522,7 +460,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- bNodeTree *ntree = snode.edittree;
+ bNodeTree &ntree = *snode.edittree;
Collection *collection = reinterpret_cast<Collection *>(
WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR));
@@ -533,8 +471,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *collection_node = node_add_node(
- *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]);
+ bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor);
if (!collection_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
return OPERATOR_CANCELLED;
@@ -550,8 +487,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
socket_data->value = collection;
id_us_plus(&collection->id);
- nodeSetActive(ntree, collection_node);
- ED_node_tree_propagate_change(C, bmain, ntree);
+ nodeSetActive(&ntree, collection_node);
+ ED_node_tree_propagate_change(C, bmain, &ntree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -617,11 +554,9 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- bNode *node;
- Image *ima;
int type = 0;
- ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
+ Image *ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!ima) {
return OPERATOR_CANCELLED;
}
@@ -645,7 +580,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]);
+ bNode *node = add_static_node(*C, type, snode.runtime->cursor);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
@@ -690,8 +625,8 @@ static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *even
snode->runtime->cursor[0] /= UI_DPI_FAC;
snode->runtime->cursor[1] /= UI_DPI_FAC;
- if (RNA_struct_property_is_set(op->ptr, "filepath") ||
- RNA_struct_property_is_set(op->ptr, "name")) {
+ if (WM_operator_properties_id_lookup_is_set(op->ptr) ||
+ RNA_struct_property_is_set(op->ptr, "filepath")) {
return node_add_file_exec(C, op);
}
return WM_operator_filesel(C, op, event);
@@ -739,7 +674,6 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- bNode *node;
ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_MSK);
if (!mask) {
@@ -748,8 +682,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(
- *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]);
+ bNode *node = add_static_node(*C, CMP_NODE_MASK, snode.runtime->cursor);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
index b9bee3ed15e..4f7497b5f49 100644
--- a/source/blender/editors/space_node/node_context_path.cc
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -28,27 +28,26 @@
#include "node_intern.hh"
-struct Curve;
-struct Light;
struct Material;
-struct Mesh;
-struct World;
namespace blender::ed::space_node {
static void context_path_add_object_data(Vector<ui::ContextPathItem> &path, Object &object)
{
- if (object.type == OB_MESH && object.data) {
- Mesh *mesh = (Mesh *)object.data;
- ui::context_path_add_generic(path, RNA_Mesh, mesh);
+ if (!object.data) {
+ return;
}
- if (object.type == OB_LAMP && object.data) {
- Light *light = (Light *)object.data;
- ui::context_path_add_generic(path, RNA_Light, light);
+ if (object.type == OB_MESH) {
+ ui::context_path_add_generic(path, RNA_Mesh, object.data);
}
- if (ELEM(object.type, OB_CURVES_LEGACY, OB_FONT, OB_SURF) && object.data) {
- Curve *curve = (Curve *)object.data;
- ui::context_path_add_generic(path, RNA_Curve, curve);
+ else if (object.type == OB_CURVES) {
+ ui::context_path_add_generic(path, RNA_Curves, object.data);
+ }
+ else if (object.type == OB_LAMP) {
+ ui::context_path_add_generic(path, RNA_Light, object.data);
+ }
+ else if (ELEM(object.type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
+ ui::context_path_add_generic(path, RNA_Curve, object.data);
}
}
@@ -71,8 +70,7 @@ static void get_context_path_node_shader(const bContext &C,
Scene *scene = CTX_data_scene(&C);
ui::context_path_add_generic(path, RNA_Scene, scene);
if (scene != nullptr) {
- World *world = scene->world;
- ui::context_path_add_generic(path, RNA_World, world);
+ ui::context_path_add_generic(path, RNA_World, scene->world);
}
/* Skip the base node tree here, because the world contains a node tree already. */
context_path_add_node_tree_and_node_groups(snode, path, true);
@@ -95,8 +93,7 @@ static void get_context_path_node_shader(const bContext &C,
Scene *scene = CTX_data_scene(&C);
ui::context_path_add_generic(path, RNA_Scene, scene);
if (scene != nullptr) {
- World *world = scene->world;
- ui::context_path_add_generic(path, RNA_World, world);
+ ui::context_path_add_generic(path, RNA_World, scene->world);
}
}
#ifdef WITH_FREESTYLE
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 7003d51b2b6..3da799d0fd5 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -34,6 +34,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -248,6 +249,7 @@ void node_sort(bNodeTree &ntree)
b++;
BLI_remlink(&ntree.nodes, tmp);
BLI_insertlinkbefore(&ntree.nodes, node_a, tmp);
+ BKE_ntree_update_tag_node_reordered(&ntree);
}
}
@@ -340,13 +342,13 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
bool add_output_space = false;
int buty;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
- if (nodeSocketIsHidden(nsock)) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
+ if (nodeSocketIsHidden(socket)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, socket, &sockptr);
uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
@@ -369,10 +371,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
/* Align output buttons to the right. */
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
- const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ const char *socket_label = nodeSocketLabel(socket);
+ socket->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- node_socket_add_tooltip(&ntree, &node, nsock, row);
+ node_socket_add_tooltip(ntree, node, *socket, *row);
UI_block_align_end(&block);
UI_block_layout_resolve(&block, nullptr, &buty);
@@ -381,11 +383,11 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
buty = min_ii(buty, dy - NODE_DY);
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(loc.x + NODE_WIDTH(node));
- nsock->locy = round(dy - NODE_DYS);
+ socket->locx = round(loc.x + NODE_WIDTH(node));
+ socket->locy = round(dy - NODE_DYS);
dy = buty;
- if (nsock->next) {
+ if (socket->next) {
dy -= NODE_SOCKDY;
}
@@ -463,20 +465,20 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
}
/* Input sockets. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
- if (nodeSocketIsHidden(nsock)) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
+ if (nodeSocketIsHidden(socket)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, socket, &sockptr);
/* Add the half the height of a multi-input socket to cursor Y
* to account for the increased height of the taller sockets. */
float multi_input_socket_offset = 0.0f;
- if (nsock->flag & SOCK_MULTI_INPUT) {
- if (nsock->total_inputs > 2) {
- multi_input_socket_offset = (nsock->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP;
+ if (socket->flag & SOCK_MULTI_INPUT) {
+ if (socket->total_inputs > 2) {
+ multi_input_socket_offset = (socket->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP;
}
}
dy -= multi_input_socket_offset * 0.5f;
@@ -501,10 +503,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
uiLayout *row = uiLayoutRow(layout, true);
- const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ const char *socket_label = nodeSocketLabel(socket);
+ socket->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- node_socket_add_tooltip(&ntree, &node, nsock, row);
+ node_socket_add_tooltip(ntree, node, *socket, *row);
UI_block_align_end(&block);
UI_block_layout_resolve(&block, nullptr, &buty);
@@ -512,12 +514,12 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
- nsock->locx = loc.x;
+ socket->locx = loc.x;
/* Round the socket vertical position to stop it from jiggling. */
- nsock->locy = round(dy - NODE_DYS);
+ socket->locy = round(dy - NODE_DYS);
dy = buty - multi_input_socket_offset * 0.5;
- if (nsock->next) {
+ if (socket->next) {
dy -= NODE_SOCKDY;
}
}
@@ -555,13 +557,13 @@ static void node_update_hidden(bNode &node, uiBlock &block)
loc.y = round(loc.y);
/* Calculate minimal radius. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
- if (!nodeSocketIsHidden(nsock)) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
+ if (!nodeSocketIsHidden(socket)) {
totin++;
}
}
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
- if (!nodeSocketIsHidden(nsock)) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
+ if (!nodeSocketIsHidden(socket)) {
totout++;
}
}
@@ -581,11 +583,11 @@ static void node_update_hidden(bNode &node, uiBlock &block)
float rad = (float)M_PI / (1.0f + (float)totout);
float drad = rad;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
- if (!nodeSocketIsHidden(nsock)) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
+ if (!nodeSocketIsHidden(socket)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ socket->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
+ socket->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
@@ -593,11 +595,11 @@ static void node_update_hidden(bNode &node, uiBlock &block)
/* Input sockets. */
rad = drad = -(float)M_PI / (1.0f + (float)totin);
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
- if (!nodeSocketIsHidden(nsock)) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
+ if (!nodeSocketIsHidden(socket)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ socket->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
+ socket->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
@@ -663,7 +665,9 @@ static void node_draw_mute_line(const bContext &C,
GPU_blend(GPU_BLEND_ALPHA);
LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) {
- node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE, false);
+ if (!nodeLinkIsHidden(link)) {
+ node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE, false);
+ }
}
GPU_blend(GPU_BLEND_NONE);
@@ -718,8 +722,7 @@ static void node_socket_draw_multi_input(const float color[4],
const float color_outline[4],
const float width,
const float height,
- const int locx,
- const int locy)
+ const float2 location)
{
/* The other sockets are drawn with the keyframe shader. There, the outline has a base thickness
* that can be varied but always scales with the size the socket is drawn at. Using `U.dpi_fac`
@@ -729,10 +732,10 @@ static void node_socket_draw_multi_input(const float color[4],
/* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */
const rctf rect = {
- locx - width + outline_width * 0.5f,
- locx + width - outline_width * 0.5f,
- locy - height + outline_width * 0.5f,
- locy + height - outline_width * 0.5f,
+ location.x - width + outline_width * 0.5f,
+ location.x + width - outline_width * 0.5f,
+ location.y - height + outline_width * 0.5f,
+ location.y + height - outline_width * 0.5f,
};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
@@ -749,14 +752,14 @@ static void node_socket_outline_color_get(const bool selected,
if (selected) {
UI_GetThemeColor4fv(TH_ACTIVE, r_outline_color);
}
+ else if (socket_type == SOCK_CUSTOM) {
+ /* Until there is a better place for per socket color,
+ * the outline color for virtual sockets is set here. */
+ copy_v4_v4(r_outline_color, virtual_node_socket_outline_color);
+ }
else {
UI_GetThemeColor4fv(TH_WIRE, r_outline_color);
- }
-
- /* Until there is a better place for per socket color,
- * the outline color for virtual sockets is set here. */
- if (socket_type == SOCK_CUSTOM) {
- copy_v4_v4(r_outline_color, virtual_node_socket_outline_color);
+ r_outline_color[3] = 1.0f;
}
}
@@ -774,9 +777,9 @@ void node_socket_color_get(const bContext &C,
}
struct SocketTooltipData {
- bNodeTree *ntree;
- bNode *node;
- bNodeSocket *socket;
+ const bNodeTree *ntree;
+ const bNode *node;
+ const bNodeSocket *socket;
};
static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss)
@@ -938,6 +941,19 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
ss << TIP_("\u2022 Volume") << line_end;
break;
}
+ case GEO_COMPONENT_TYPE_EDIT: {
+ if (value_log.edit_data_info.has_value()) {
+ const geo_log::GeometryValueLog::EditDataInfo &edit_info = *value_log.edit_data_info;
+ char line[256];
+ BLI_snprintf(line,
+ sizeof(line),
+ TIP_("\u2022 Edit Curves: %s, %s"),
+ edit_info.has_deformed_positions ? TIP_("positions") : TIP_("no positions"),
+ edit_info.has_deform_matrices ? TIP_("matrices") : TIP_("no matrices"));
+ ss << line << line_end;
+ }
+ break;
+ }
}
}
@@ -976,16 +992,19 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
ss << TIP_("Volume");
break;
}
+ case GEO_COMPONENT_TYPE_EDIT: {
+ break;
+ }
}
ss << ((type == supported_types.last()) ? "" : ", ");
}
}
-static std::optional<std::string> create_socket_inspection_string(bContext *C,
- bNode &node,
- bNodeSocket &socket)
+static std::optional<std::string> create_socket_inspection_string(const bContext &C,
+ const bNode &node,
+ const bNodeSocket &socket)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ const SpaceNode *snode = CTX_wm_space_node(&C);
if (snode == nullptr) {
return {};
};
@@ -1020,41 +1039,41 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
return ss.str();
}
-static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket)
+static bool node_socket_has_tooltip(const bNodeTree &ntree, const bNodeSocket &socket)
{
- if (ntree->type == NTREE_GEOMETRY) {
+ if (ntree.type == NTREE_GEOMETRY) {
return true;
}
- if (socket->runtime->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
+ if (socket.runtime->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
return !socket_decl.description().is_empty();
}
return false;
}
-static char *node_socket_get_tooltip(bContext *C,
- bNodeTree *ntree,
- bNode *node,
- bNodeSocket *socket)
+static char *node_socket_get_tooltip(const bContext &C,
+ const bNodeTree &ntree,
+ const bNode &node,
+ const bNodeSocket &socket)
{
std::stringstream output;
- if (socket->runtime->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
+ if (socket.runtime->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
blender::StringRef description = socket_decl.description();
if (!description.is_empty()) {
output << TIP_(description.data());
}
}
- if (ntree->type == NTREE_GEOMETRY) {
+ if (ntree.type == NTREE_GEOMETRY) {
if (!output.str().empty()) {
output << ".\n\n";
}
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
- C, *node, *socket);
+ C, node, socket);
if (socket_inspection_str.has_value()) {
output << *socket_inspection_str;
}
@@ -1064,28 +1083,31 @@ static char *node_socket_get_tooltip(bContext *C,
}
if (output.str().empty()) {
- output << nodeSocketLabel(socket);
+ output << nodeSocketLabel(&socket);
}
return BLI_strdup(output.str().c_str());
}
-void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout)
+void node_socket_add_tooltip(const bNodeTree &ntree,
+ const bNode &node,
+ const bNodeSocket &sock,
+ uiLayout &layout)
{
if (!node_socket_has_tooltip(ntree, sock)) {
return;
}
- SocketTooltipData *data = MEM_cnew<SocketTooltipData>(__func__);
- data->ntree = ntree;
- data->node = node;
- data->socket = sock;
+ SocketTooltipData *data = MEM_new<SocketTooltipData>(__func__);
+ data->ntree = &ntree;
+ data->node = &node;
+ data->socket = &sock;
uiLayoutSetTooltipFunc(
- layout,
+ &layout,
[](bContext *C, void *argN, const char *UNUSED(tip)) {
- SocketTooltipData *data = static_cast<SocketTooltipData *>(argN);
- return node_socket_get_tooltip(C, data->ntree, data->node, data->socket);
+ const SocketTooltipData *data = static_cast<SocketTooltipData *>(argN);
+ return node_socket_get_tooltip(*C, *data->ntree, *data->node, *data->socket);
},
data,
MEM_dupallocN,
@@ -1105,9 +1127,10 @@ static void node_socket_draw_nested(const bContext &C,
const float size,
const bool selected)
{
+ const float2 location(sock.locx, sock.locy);
+
float color[4];
float outline_color[4];
-
node_socket_color_get(C, ntree, node_ptr, sock, color);
node_socket_outline_color_get(selected, sock.type, outline_color);
@@ -1115,15 +1138,15 @@ static void node_socket_draw_nested(const bContext &C,
color,
outline_color,
size,
- sock.locx,
- sock.locy,
+ location.x,
+ location.y,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id);
- if (!node_socket_has_tooltip(&ntree, &sock)) {
+ if (!node_socket_has_tooltip(ntree, sock)) {
return;
}
@@ -1135,8 +1158,8 @@ static void node_socket_draw_nested(const bContext &C,
UI_BTYPE_BUT,
0,
ICON_NONE,
- sock.locx - size / 2,
- sock.locy - size / 2,
+ location.x - size / 2.0f,
+ location.y - size / 2.0f,
size,
size,
nullptr,
@@ -1146,16 +1169,16 @@ static void node_socket_draw_nested(const bContext &C,
0,
nullptr);
- SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
+ SocketTooltipData *data = MEM_new<SocketTooltipData>(__func__);
data->ntree = &ntree;
- data->node = (bNode *)node_ptr.data;
+ data->node = static_cast<const 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;
- return node_socket_get_tooltip(C, data->ntree, data->node, data->socket);
+ return node_socket_get_tooltip(*C, *data->ntree, *data->node, *data->socket);
},
data,
MEM_freeN);
@@ -1267,7 +1290,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
/* Premul graphics. */
GPU_blend(GPU_BLEND_ALPHA);
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexTiled(&state,
draw_rect.xmin,
draw_rect.ymin,
@@ -1283,14 +1306,14 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
GPU_blend(GPU_BLEND_NONE);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
immUnbindProgram();
}
/* Common handle function for operator buttons that need to select the node first. */
-static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
+static void node_toggle_button_cb(bContext *C, void *node_argv, void *op_argv)
{
bNode *node = (bNode *)node_argv;
const char *opname = (const char *)op_argv;
@@ -1509,7 +1532,8 @@ static void node_draw_sockets(const View2D &v2d,
node_socket_color_get(C, ntree, node_ptr, *socket, color);
node_socket_outline_color_get(socket->flag & SELECT, socket->type, outline_color);
- node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
+ const float2 location(socket->locx, socket->locy);
+ node_socket_draw_multi_input(color, outline_color, width, height, location);
}
}
@@ -1698,7 +1722,7 @@ static std::string node_get_execution_time_label(const SpaceNode &snode, const b
{
int node_count = 0;
std::chrono::microseconds exec_time = node_get_execution_time(
- *snode.nodetree, node, snode, node_count);
+ *snode.edittree, node, snode, node_count);
if (node_count == 0) {
return std::string("");
@@ -2246,6 +2270,7 @@ static void node_draw_basis(const bContext &C,
if (node.flag & NODE_MUTED) {
UI_GetThemeColor4fv(TH_WIRE, color_underline);
+ color_underline[3] = 1.0f;
}
else {
UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.2f, color_underline);
@@ -2453,7 +2478,7 @@ static void node_draw_hidden(const bContext &C,
/* Scale widget thing. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_blend(GPU_BLEND_ALPHA);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_TEXT, -40, -180);
float dx = 0.5f * U.widget_unit;
@@ -2626,13 +2651,13 @@ static void reroute_node_prepare_for_draw(bNode &node)
const float2 loc = node_to_view(node, float2(0));
/* reroute node has exactly one input and one output, both in the same place */
- bNodeSocket *nsock = (bNodeSocket *)node.outputs.first;
- nsock->locx = loc.x;
- nsock->locy = loc.y;
+ bNodeSocket *socket = (bNodeSocket *)node.outputs.first;
+ socket->locx = loc.x;
+ socket->locy = loc.y;
- nsock = (bNodeSocket *)node.inputs.first;
- nsock->locx = loc.x;
- nsock->locy = loc.y;
+ socket = (bNodeSocket *)node.inputs.first;
+ socket->locx = loc.x;
+ socket->locy = loc.y;
const float size = 8.0f;
node.width = size * 2;
@@ -2749,7 +2774,7 @@ static void frame_node_draw_label(const bNodeTree &ntree,
BLF_wordwrap(fontid, line_width);
LISTBASE_FOREACH (const TextLine *, line, &text->lines) {
- struct ResultBLF info;
+ ResultBLF info;
if (line->line[0]) {
BLF_position(fontid, x, y, 0);
BLF_draw_ex(fontid, line->line, line->len, &info);
@@ -3004,8 +3029,9 @@ static void draw_nodetree(const bContext &C,
bNodeInstanceKey parent_key)
{
SpaceNode *snode = CTX_wm_space_node(&C);
+ ntree.ensure_topology_cache();
- Vector<bNode *> nodes = ntree.nodes;
+ Span<bNode *> nodes = ntree.all_nodes();
Array<uiBlock *> blocks = node_uiblocks_init(C, nodes);
@@ -3085,8 +3111,8 @@ void node_draw_space(const bContext &C, ARegion &region)
}
/* Current View2D center, will be set temporarily for parent node trees. */
- float center[2];
- UI_view2d_center_get(&v2d, &center[0], &center[1]);
+ float2 center;
+ UI_view2d_center_get(&v2d, &center.x, &center.y);
/* Store new view center in path and current edit tree. */
copy_v2_v2(path->view_center, center);
@@ -3125,7 +3151,7 @@ void node_draw_space(const bContext &C, ARegion &region)
GPU_line_smooth(true);
if (snode.runtime->linkdrag) {
for (const bNodeLink *link : snode.runtime->linkdrag->links) {
- node_draw_link(C, v2d, snode, *link, true);
+ node_draw_link_dragged(C, v2d, snode, *link);
}
}
GPU_line_smooth(false);
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index ffc9befc81c..f07a1205c6b 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -29,6 +29,8 @@
#include "BKE_scene.h"
#include "BKE_workspace.h"
+#include "BLT_translation.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
@@ -107,8 +109,7 @@ float2 node_link_calculate_multi_input_position(const float2 &socket_position,
{
const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) *
0.5f;
- return {socket_position.x - NODE_SOCKSIZE * 0.5f,
- socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
+ return {socket_position.x, socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
}
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
@@ -319,7 +320,7 @@ static void compo_completejob(void *cjv)
/** \name Composite Job C API
* \{ */
-void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
+void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner)
{
using namespace blender::ed::space_node;
@@ -463,22 +464,22 @@ void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
}
}
-bool ED_node_is_compositor(struct SpaceNode *snode)
+bool ED_node_is_compositor(SpaceNode *snode)
{
return STREQ(snode->tree_idname, ntreeType_Composite->idname);
}
-bool ED_node_is_shader(struct SpaceNode *snode)
+bool ED_node_is_shader(SpaceNode *snode)
{
return STREQ(snode->tree_idname, ntreeType_Shader->idname);
}
-bool ED_node_is_texture(struct SpaceNode *snode)
+bool ED_node_is_texture(SpaceNode *snode)
{
return STREQ(snode->tree_idname, ntreeType_Texture->idname);
}
-bool ED_node_is_geometry(struct SpaceNode *snode)
+bool ED_node_is_geometry(SpaceNode *snode)
{
return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
@@ -505,12 +506,12 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
/* Emission */
- bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
+ bNodeTree *ntree = ntreeAddTreeEmbedded(
+ nullptr, id, "Shader Nodetree", ntreeType_Shader->idname);
bNode *shader, *output;
if (GS(id->name) == ID_WO) {
World *world = (World *)id;
- world->nodetree = ntree;
shader = nodeAddStaticNode(nullptr, ntree, SH_NODE_BACKGROUND);
output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_WORLD);
@@ -524,9 +525,6 @@ void ED_node_shader_default(const bContext *C, ID *id)
copy_v3_v3(((bNodeSocketValueRGBA *)color_sock->default_value)->value, &world->horr);
}
else {
- Light *light = (Light *)id;
- light->nodetree = ntree;
-
shader = nodeAddStaticNode(nullptr, ntree, SH_NODE_EMISSION);
output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_LIGHT);
nodeAddLink(ntree,
@@ -549,7 +547,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
}
-void ED_node_composit_default(const bContext *C, struct Scene *sce)
+void ED_node_composit_default(const bContext *C, Scene *sce)
{
/* but lets check it anyway */
if (sce->nodetree) {
@@ -559,7 +557,8 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
return;
}
- sce->nodetree = ntreeAddTree(nullptr, "Compositing Nodetree", ntreeType_Composite->idname);
+ sce->nodetree = ntreeAddTreeEmbedded(
+ nullptr, &sce->id, "Compositing Nodetree", ntreeType_Composite->idname);
sce->nodetree->chunksize = 256;
sce->nodetree->edit_quality = NTREE_QUALITY_HIGH;
@@ -592,7 +591,8 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
return;
}
- tex->nodetree = ntreeAddTree(nullptr, "Texture Nodetree", ntreeType_Texture->idname);
+ tex->nodetree = ntreeAddTreeEmbedded(
+ nullptr, &tex->id, "Texture Nodetree", ntreeType_Texture->idname);
bNode *out = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_OUTPUT);
out->locx = 300.0f;
@@ -729,19 +729,26 @@ void ED_node_set_active(
}
}
- /* Sync to Image Editor. */
+ /* Sync to Image Editor under the following conditions:
+ * - current image is not pinned
+ * - current image is not a Render Result or ViewerNode (want to keep looking at these) */
Image *image = (Image *)node->id;
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
- if (!sima->pin) {
- ED_space_image_set(bmain, sima, image, true);
- }
+ if (sl->spacetype != SPACE_IMAGE) {
+ continue;
+ }
+ SpaceImage *sima = (SpaceImage *)sl;
+ if (sima->pin) {
+ continue;
+ }
+ if (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ continue;
}
+ ED_space_image_set(bmain, sima, image, true);
}
}
}
@@ -913,15 +920,24 @@ static void edit_node_properties_get(
/** \name Node Generic
* \{ */
-/* is rct in visible part of node? */
-static bNode *visible_node(SpaceNode &snode, const rctf &rct)
+static bool socket_is_occluded(const float2 &location,
+ const bNode &node_the_socket_belongs_to,
+ const SpaceNode &snode)
{
LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) {
- if (BLI_rctf_isect(&node->totr, &rct, nullptr)) {
- return node;
+ if (node == &node_the_socket_belongs_to) {
+ /* Nodes after this one are underneath and can't occlude the socket. */
+ return false;
+ }
+
+ rctf socket_hitbox;
+ const float socket_hitbox_radius = NODE_SOCKSIZE - 0.1f * U.widget_unit;
+ BLI_rctf_init_pt_radius(&socket_hitbox, location, socket_hitbox_radius);
+ if (BLI_rctf_inside_rctf(&node->totr, &socket_hitbox)) {
+ return true;
}
}
- return nullptr;
+ return false;
}
/** \} */
@@ -939,14 +955,14 @@ struct NodeSizeWidget {
};
static void node_resize_init(
- bContext *C, wmOperator *op, const float cursor[2], const bNode *node, NodeResizeDirection dir)
+ bContext *C, wmOperator *op, const float2 &cursor, const bNode *node, NodeResizeDirection dir)
{
NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
op->customdata = nsw;
- nsw->mxstart = cursor[0];
- nsw->mystart = cursor[1];
+ nsw->mxstart = cursor.x;
+ nsw->mystart = cursor.y;
/* store old */
nsw->oldlocx = node->locx;
@@ -993,12 +1009,12 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- int mval[2];
+ int2 mval;
WM_event_drag_start_mval(event, region, mval);
float mx, my;
- UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &mx, &my);
- float dx = (mx - nsw->mxstart) / UI_DPI_FAC;
- float dy = (my - nsw->mystart) / UI_DPI_FAC;
+ UI_view2d_region_to_view(&region->v2d, mval.x, mval.y, &mx, &my);
+ const float dx = (mx - nsw->mxstart) / UI_DPI_FAC;
+ const float dy = (my - nsw->mystart) / UI_DPI_FAC;
if (node) {
float *pwidth = &node->width;
@@ -1080,6 +1096,10 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
break;
}
+ case EVT_ESCKEY:
+ node_resize_exit(C, op, true);
+ ED_region_tag_redraw(region);
+ return OPERATOR_CANCELLED;
}
return OPERATOR_RUNNING_MODAL;
@@ -1096,11 +1116,11 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* convert mouse coordinates to v2d space */
- float cursor[2];
- int mval[2];
+ float2 cursor;
+ int2 mval;
WM_event_drag_start_mval(event, region, mval);
- UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
- const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ UI_view2d_region_to_view(&region->v2d, mval.x, mval.y, &cursor.x, &cursor.y);
+ const NodeResizeDirection dir = node_get_resize_direction(node, cursor.x, cursor.y);
if (dir == NODE_RESIZE_NONE) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
@@ -1178,21 +1198,22 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
}
/* checks snode->mouse position, and returns found node/socket */
-static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket &socket)
+static bool cursor_isect_multi_input_socket(const float2 &cursor, const bNodeSocket &socket)
{
const float node_socket_height = node_socket_calculate_height(socket);
- rctf multi_socket_rect;
+ const float2 location(socket.locx, socket.locy);
/* `.xmax = socket->locx + NODE_SOCKSIZE * 5.5f`
* would be the same behavior as for regular sockets.
* But keep it smaller because for multi-input socket you
* sometimes want to drag the link to the other side, if you may
* accidentally pick the wrong link otherwise. */
+ rctf multi_socket_rect;
BLI_rctf_init(&multi_socket_rect,
- socket.locx - NODE_SOCKSIZE * 4.0f,
- socket.locx + NODE_SOCKSIZE * 2.0f,
- socket.locy - node_socket_height,
- socket.locy + node_socket_height);
- if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) {
+ location.x - NODE_SOCKSIZE * 4.0f,
+ location.x + NODE_SOCKSIZE * 2.0f,
+ location.y - node_socket_height,
+ location.y + node_socket_height);
+ if (BLI_rctf_isect_pt(&multi_socket_rect, cursor.x, cursor.y)) {
return true;
}
return false;
@@ -1212,10 +1233,8 @@ bool node_find_indicated_socket(SpaceNode &snode,
*sockp = nullptr;
/* check if we click in a socket */
- LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) {
BLI_rctf_init_pt_radius(&rect, cursor, size_sock_padded);
- rctf node_visible;
- BLI_rctf_init_pt_radius(&node_visible, cursor, size_sock_padded);
if (!(node->flag & NODE_HIDDEN)) {
/* extra padding inside and out - allow dragging on the text areas too */
@@ -1232,17 +1251,18 @@ bool node_find_indicated_socket(SpaceNode &snode,
if (in_out & SOCK_IN) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!nodeSocketIsHidden(sock)) {
+ const float2 location(sock->locx, sock->locy);
if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) {
if (cursor_isect_multi_input_socket(cursor, *sock)) {
- if (node == visible_node(snode, node_visible)) {
+ if (!socket_is_occluded(location, *node, snode)) {
*nodep = node;
*sockp = sock;
return true;
}
}
}
- else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, node_visible)) {
+ else if (BLI_rctf_isect_pt(&rect, location.x, location.y)) {
+ if (!socket_is_occluded(location, *node, snode)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1254,8 +1274,9 @@ bool node_find_indicated_socket(SpaceNode &snode,
if (in_out & SOCK_OUT) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (!nodeSocketIsHidden(sock)) {
- if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, node_visible)) {
+ const float2 location(sock->locx, sock->locy);
+ if (BLI_rctf_isect_pt(&rect, location.x, location.y)) {
+ if (!socket_is_occluded(location, *node, snode)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1281,11 +1302,12 @@ float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
return 1.0f;
}
+ const float2 from(link.fromsock->locx, link.fromsock->locy);
+ const float2 to(link.tosock->locx, link.tosock->locy);
+
const float min_endpoint_distance = std::min(
- std::max(BLI_rctf_length_x(&v2d.cur, link.fromsock->locx),
- BLI_rctf_length_y(&v2d.cur, link.fromsock->locy)),
- std::max(BLI_rctf_length_x(&v2d.cur, link.tosock->locx),
- BLI_rctf_length_y(&v2d.cur, link.tosock->locy)));
+ std::max(BLI_rctf_length_x(&v2d.cur, from.x), BLI_rctf_length_y(&v2d.cur, from.y)),
+ std::max(BLI_rctf_length_x(&v2d.cur, to.x), BLI_rctf_length_y(&v2d.cur, to.y)));
if (min_endpoint_distance == 0.0f) {
return 1.0f;
@@ -1344,7 +1366,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
bNode *lastnode = (bNode *)ntree->nodes.last;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
- bNode *new_node = blender::bke::node_copy_with_mapping(
+ bNode *new_node = bke::node_copy_with_mapping(
ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, new_node);
changed = true;
@@ -1451,43 +1473,6 @@ void NODE_OT_duplicate(wmOperatorType *ot)
ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
}
-static bool node_select_check(const ListBase *lb)
-{
- LISTBASE_FOREACH (const bNode *, node, lb) {
- if (node->flag & NODE_SELECT) {
- return true;
- }
- }
-
- return false;
-}
-
-void node_select_all(ListBase *lb, int action)
-{
- if (action == SEL_TOGGLE) {
- if (node_select_check(lb)) {
- action = SEL_DESELECT;
- }
- else {
- action = SEL_SELECT;
- }
- }
-
- LISTBASE_FOREACH (bNode *, node, lb) {
- switch (action) {
- case SEL_SELECT:
- nodeSetSelected(node, true);
- break;
- case SEL_DESELECT:
- nodeSetSelected(node, false);
- break;
- case SEL_INVERT:
- nodeSetSelected(node, !(node->flag & SELECT));
- break;
- }
- }
-}
-
/* XXX: some code needing updating to operators. */
/* goes over all scenes, reads render layers */
@@ -2149,24 +2134,23 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
- bNode *node = nodeGetActive(&ntree);
- if (!node) {
+ bNode *active_node = nodeGetActive(&ntree);
+ if (!active_node) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node_iter, &ntree.nodes) {
- if (node_iter->flag & NODE_SELECT && node_iter != node) {
- if (node->flag & NODE_CUSTOM_COLOR) {
- node_iter->flag |= NODE_CUSTOM_COLOR;
- copy_v3_v3(node_iter->color, node->color);
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node->flag & NODE_SELECT && node != active_node) {
+ if (active_node->flag & NODE_CUSTOM_COLOR) {
+ node->flag |= NODE_CUSTOM_COLOR;
+ copy_v3_v3(node->color, active_node->color);
}
else {
- node_iter->flag &= ~NODE_CUSTOM_COLOR;
+ node->flag &= ~NODE_CUSTOM_COLOR;
}
}
}
- node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2211,12 +2195,12 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
if (node->flag & SELECT) {
/* No ID refcounting, this node is virtual,
* detached from any actual Blender data currently. */
- bNode *new_node = blender::bke::node_copy_with_mapping(nullptr,
- *node,
- LIB_ID_CREATE_NO_USER_REFCOUNT |
- LIB_ID_CREATE_NO_MAIN,
- false,
- socket_map);
+ bNode *new_node = bke::node_copy_with_mapping(nullptr,
+ *node,
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_MAIN,
+ false,
+ socket_map);
node_map.add_new(node, new_node);
}
}
@@ -2336,11 +2320,11 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
node_deselect_all(*snode);
/* calculate "barycenter" for placing on mouse cursor */
- float center[2] = {0.0f, 0.0f};
+ float2 center = {0.0f, 0.0f};
int num_nodes = 0;
LISTBASE_FOREACH_INDEX (bNode *, node, clipboard_nodes_lb, num_nodes) {
- center[0] += BLI_rctf_cent_x(&node->totr);
- center[1] += BLI_rctf_cent_y(&node->totr);
+ center.x += BLI_rctf_cent_x(&node->totr);
+ center.y += BLI_rctf_cent_y(&node->totr);
}
mul_v2_fl(center, 1.0 / num_nodes);
@@ -2349,7 +2333,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
/* copy nodes from clipboard */
LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = blender::bke::node_copy_with_mapping(
+ bNode *new_node = bke::node_copy_with_mapping(
ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, new_node);
}
@@ -2424,7 +2408,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
const eNodeSocketInOut in_out = (eNodeSocketInOut)RNA_enum_get(op->ptr, "in_out");
ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs;
- const char *default_name = (in_out == SOCK_IN) ? "Input" : "Output";
+ const char *default_name = (in_out == SOCK_IN) ? DATA_("Input") : DATA_("Output");
bNodeSocket *active_sock = ntree_get_active_interface_socket(sockets);
bNodeSocket *sock;
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 f08e23c8371..e328a86b0fd 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -113,14 +113,6 @@ static void attribute_search_update_fn(
Vector<const GeometryAttributeInfo *> infos = get_attribute_info_from_context(*C, *data);
- /* Remove the deprecated normal attribute from the search. */
- for (const int i : infos.index_range()) {
- if (infos[i]->domain == ATTR_DOMAIN_FACE && infos[i]->name == "normal") {
- infos.remove(i);
- break;
- }
- }
-
ui::attribute_search_add_items(str, true, infos, items, is_first);
}
diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc
index 4f27f9baabc..f9126556b71 100644
--- a/source/blender/editors/space_node/node_gizmo.cc
+++ b/source/blender/editors/space_node/node_gizmo.cc
@@ -49,14 +49,14 @@ static void node_gizmo_calc_matrix_space(const SpaceNode *snode,
static void node_gizmo_calc_matrix_space_with_image_dims(const SpaceNode *snode,
const ARegion *region,
- const float image_dims[2],
+ const float2 &image_dims,
float matrix_space[4][4])
{
unit_m4(matrix_space);
- mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]);
- mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]);
- matrix_space[3][0] = ((region->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom);
- matrix_space[3][1] = ((region->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom);
+ mul_v3_fl(matrix_space[0], snode->zoom * image_dims.x);
+ mul_v3_fl(matrix_space[1], snode->zoom * image_dims.y);
+ matrix_space[3][0] = ((region->winx / 2) + snode->xof) - ((image_dims.x / 2.0f) * snode->zoom);
+ matrix_space[3][1] = ((region->winy / 2) + snode->yof) - ((image_dims.y / 2.0f) * snode->zoom);
}
/** \} */
@@ -135,7 +135,7 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup *
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
- const float dims[2] = {
+ const float2 dims = {
(ibuf->x > 0) ? ibuf->x : 64.0f,
(ibuf->y > 0) ? ibuf->y : 64.0f,
};
@@ -190,7 +190,7 @@ struct NodeCropWidgetGroup {
wmGizmo *border;
struct {
- float dims[2];
+ float2 dims;
} state;
struct {
@@ -206,10 +206,7 @@ static void gizmo_node_crop_update(struct NodeCropWidgetGroup *crop_group)
crop_group->update_data.context, &crop_group->update_data.ptr, crop_group->update_data.prop);
}
-static void two_xy_to_rect(const NodeTwoXYs *nxy,
- rctf *rect,
- const float dims[2],
- bool is_relative)
+static void two_xy_to_rect(const NodeTwoXYs *nxy, rctf *rect, const float2 &dims, bool is_relative)
{
if (is_relative) {
rect->xmin = nxy->fac_x1;
@@ -218,16 +215,16 @@ static void two_xy_to_rect(const NodeTwoXYs *nxy,
rect->ymax = nxy->fac_y2;
}
else {
- rect->xmin = nxy->x1 / dims[0];
- rect->xmax = nxy->x2 / dims[0];
- rect->ymin = nxy->y1 / dims[1];
- rect->ymax = nxy->y2 / dims[1];
+ rect->xmin = nxy->x1 / dims.x;
+ rect->xmax = nxy->x2 / dims.x;
+ rect->ymin = nxy->y1 / dims.y;
+ rect->ymax = nxy->y2 / dims.y;
}
}
static void two_xy_from_rect(NodeTwoXYs *nxy,
const rctf *rect,
- const float dims[2],
+ const float2 &dims,
bool is_relative)
{
if (is_relative) {
@@ -237,10 +234,10 @@ static void two_xy_from_rect(NodeTwoXYs *nxy,
nxy->fac_y2 = rect->ymax;
}
else {
- nxy->x1 = rect->xmin * dims[0];
- nxy->x2 = rect->xmax * dims[0];
- nxy->y1 = rect->ymin * dims[1];
- nxy->y2 = rect->ymax * dims[1];
+ nxy->x1 = rect->xmin * dims.x;
+ nxy->x2 = rect->xmax * dims.x;
+ nxy->y1 = rect->ymin * dims.y;
+ nxy->y2 = rect->ymax * dims.y;
}
}
@@ -321,9 +318,7 @@ static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUS
static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
- struct NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)MEM_mallocN(
- sizeof(struct NodeCropWidgetGroup), __func__);
-
+ NodeCropWidgetGroup *crop_group = MEM_new<NodeCropWidgetGroup>(__func__);
crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
RNA_enum_set(crop_group->border->ptr,
@@ -407,7 +402,7 @@ struct NodeSunBeamsWidgetGroup {
wmGizmo *gizmo;
struct {
- float dims[2];
+ float2 dims;
} state;
};
@@ -512,7 +507,7 @@ struct NodeCornerPinWidgetGroup {
wmGizmo *gizmos[4];
struct {
- float dims[2];
+ float2 dims;
} state;
};
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index 160a379d3c6..21def1bd9d7 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -25,6 +25,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_report.h"
@@ -36,6 +37,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_path.h"
#include "RNA_prototypes.h"
#include "WM_api.h"
@@ -44,7 +46,12 @@
#include "UI_resources.h"
#include "NOD_common.h"
+#include "NOD_composite.h"
+#include "NOD_geometry.h"
+#include "NOD_shader.h"
#include "NOD_socket.h"
+#include "NOD_texture.h"
+
#include "node_intern.hh" /* own include */
namespace blender::ed::space_node {
@@ -99,16 +106,16 @@ const char *node_group_idname(bContext *C)
SpaceNode *snode = CTX_wm_space_node(C);
if (ED_node_is_shader(snode)) {
- return "ShaderNodeGroup";
+ return ntreeType_Shader->group_idname;
}
if (ED_node_is_compositor(snode)) {
- return "CompositorNodeGroup";
+ return ntreeType_Composite->group_idname;
}
if (ED_node_is_texture(snode)) {
- return "TextureNodeGroup";
+ return ntreeType_Texture->group_idname;
}
if (ED_node_is_geometry(snode)) {
- return "GeometryNodeGroup";
+ return ntreeType_Geometry->group_idname;
}
return "";
@@ -456,8 +463,7 @@ static bool node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = blender::bke::node_copy_with_mapping(
- &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ newnode = bke::node_copy_with_mapping(&ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, newnode);
}
else {
@@ -647,7 +653,7 @@ static bool node_group_make_use_node(bNode &node, bNode *gnode)
static bool node_group_make_test_selected(bNodeTree &ntree,
bNode *gnode,
const char *ntree_idname,
- struct ReportList &reports)
+ ReportList &reports)
{
int ok = true;
@@ -711,13 +717,13 @@ static int node_get_selected_minmax(
INIT_MINMAX2(min, max);
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node_group_make_use_node(*node, gnode)) {
- float loc[2];
- nodeToView(node, node->offsetx, node->offsety, &loc[0], &loc[1]);
- minmax_v2v2_v2(min, max, loc);
+ float2 loc;
+ nodeToView(node, node->offsetx, node->offsety, &loc.x, &loc.y);
+ math::min_max(loc, min, max);
if (use_size) {
- loc[0] += node->width;
- loc[1] -= node->height;
- minmax_v2v2_v2(min, max, loc);
+ loc.x += node->width;
+ loc.y -= node->height;
+ math::min_max(loc, min, max);
}
totselect++;
}
@@ -831,8 +837,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* relink external sockets */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
- int fromselect = node_group_make_use_node(*link->fromnode, gnode);
- int toselect = node_group_make_use_node(*link->tonode, gnode);
+ const bool fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ const bool toselect = node_group_make_use_node(*link->tonode, gnode);
if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
/* remove all links to/from the gnode.
@@ -912,8 +918,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* move internal links */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
- int fromselect = node_group_make_use_node(*link->fromnode, gnode);
- int toselect = node_group_make_use_node(*link->tonode, gnode);
+ const bool fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ const bool toselect = node_group_make_use_node(*link->tonode, gnode);
if (fromselect && toselect) {
BLI_remlink(&ntree.links, link);
@@ -1036,9 +1042,6 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
nodeSetActive(&ntree, gnode);
if (ngroup) {
ED_node_tree_push(&snode, ngroup, gnode);
- LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
- }
}
}
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 924537d0e8a..456cbf5064d 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -9,6 +9,7 @@
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
+#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "BKE_node.h"
@@ -144,7 +145,10 @@ void node_socket_color_get(const bContext &C,
void node_draw_space(const bContext &C, ARegion &region);
-void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout);
+void node_socket_add_tooltip(const bNodeTree &ntree,
+ const bNode &node,
+ const bNodeSocket &sock,
+ uiLayout &layout);
/**
* Sort nodes by selection: unselected nodes first, then selected,
@@ -166,8 +170,9 @@ void node_keymap(wmKeyConfig *keyconf);
/* node_select.cc */
rctf node_frame_rect_inside(const bNode &node);
-bool node_or_socket_isect_event(bContext *C, const wmEvent *event);
+bool node_or_socket_isect_event(const bContext &C, const wmEvent &event);
+Set<bNode *> get_selected_nodes(bNodeTree &node_tree);
void node_deselect_all(SpaceNode &snode);
void node_socket_select(bNode *node, bNodeSocket &sock);
void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);
@@ -214,6 +219,10 @@ void node_draw_link(const bContext &C,
const SpaceNode &snode,
const bNodeLink &link,
bool selected);
+void node_draw_link_dragged(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link);
/**
* Don't do shadows if th_col3 is -1.
*/
@@ -225,19 +234,12 @@ void node_draw_link_bezier(const bContext &C,
int th_col2,
int th_col3,
bool selected);
-/** If v2d not nullptr, it clips and returns 0 if not visible. */
-bool node_link_bezier_points(const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink &link,
- float coord_array[][2],
- int resol);
-/**
- * Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr.
- */
-bool node_link_bezier_handles(const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink &ink,
- float vec[4][2]);
+
+void node_link_bezier_points_evaluated(const bNodeLink &link,
+ std::array<float2, NODE_LINK_RESOL + 1> &coords);
+
+std::optional<float2> link_path_intersection(const bNodeLink &link, Span<float2> path);
+
void draw_nodespace_back_pix(const bContext &C,
ARegion &region,
SpaceNode &snode,
@@ -245,12 +247,9 @@ void draw_nodespace_back_pix(const bContext &C,
/* node_add.cc */
-/**
- * XXX Does some additional initialization on top of #nodeAddNode
- * Can be used with both custom and static nodes,
- * if `idname == nullptr` the static int type will be used instead.
- */
-bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy);
+bNode *add_node(const bContext &C, StringRef idname, const float2 &location);
+bNode *add_static_node(const bContext &C, int type, const float2 &location);
+
void NODE_OT_add_reroute(wmOperatorType *ot);
void NODE_OT_add_group(wmOperatorType *ot);
void NODE_OT_add_object(wmOperatorType *ot);
@@ -270,11 +269,6 @@ void NODE_OT_group_edit(wmOperatorType *ot);
/* node_relationships.cc */
-void sort_multi_input_socket_links(SpaceNode &snode,
- bNode &node,
- bNodeLink *drag_link,
- const float2 *cursor);
-
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
void NODE_OT_links_cut(wmOperatorType *ot);
@@ -296,8 +290,6 @@ float2 node_link_calculate_multi_input_position(const float2 &socket_position,
int index,
int total_inputs);
-void node_select_all(ListBase *lb, int action);
-
float node_socket_calculate_height(const bNodeSocket &socket);
void snode_set_context(const bContext &C);
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index ce000aba1da..3b3189983e2 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -111,7 +111,7 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
-void node_keymap(struct wmKeyConfig *keyconf)
+void node_keymap(wmKeyConfig *keyconf)
{
/* Entire Editor only ----------------- */
WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index e10bedb18f4..40f5d20d06d 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -11,6 +11,7 @@
#include "DNA_node_types.h"
#include "BLI_easing.h"
+#include "BLI_stack.hh"
#include "BKE_anim_data.h"
#include "BKE_context.h"
@@ -18,6 +19,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_screen.h"
@@ -46,19 +48,11 @@
#include "BLT_translation.h"
#include "NOD_node_declaration.hh"
-#include "NOD_node_tree_ref.hh"
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "node_intern.hh" /* own include */
-using namespace blender::nodes::node_tree_ref_types;
-
-struct bNodeListItem {
- struct bNodeListItem *next, *prev;
- struct bNode *node;
-};
-
struct NodeInsertOfsData {
bNodeTree *ntree;
bNode *insert; /* inserted node */
@@ -79,6 +73,8 @@ static void clear_picking_highlight(ListBase *links)
namespace blender::ed::space_node {
+void update_multi_input_indices_for_removed_links(bNode &node);
+
/* -------------------------------------------------------------------- */
/** \name Add Node
* \{ */
@@ -109,11 +105,9 @@ static void pick_link(
nldrag.links.append(link);
nodeRemLink(snode.edittree, &link_to_pick);
-
+ snode.edittree->ensure_topology_cache();
BLI_assert(nldrag.last_node_hovered_while_dragging_a_link != nullptr);
-
- sort_multi_input_socket_links(
- snode, *nldrag.last_node_hovered_while_dragging_a_link, nullptr, nullptr);
+ update_multi_input_indices_for_removed_links(*nldrag.last_node_hovered_while_dragging_a_link);
/* Send changed event to original link->tonode. */
if (node) {
@@ -127,10 +121,8 @@ static void pick_input_link_by_link_intersect(const bContext &C,
const float2 &cursor)
{
SpaceNode *snode = CTX_wm_space_node(&C);
- const ARegion *region = CTX_wm_region(&C);
- const View2D *v2d = &region->v2d;
- float drag_start[2];
+ float2 drag_start;
RNA_float_get_array(op.ptr, "drag_start", drag_start);
bNode *node;
bNodeSocket *socket;
@@ -139,26 +131,16 @@ static void pick_input_link_by_link_intersect(const bContext &C,
/* Distance to test overlapping of cursor on link. */
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
- const int resolution = NODE_LINK_RESOL;
-
bNodeLink *link_to_pick = nullptr;
clear_picking_highlight(&snode->edittree->links);
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
if (link->tosock == socket) {
/* Test if the cursor is near a link. */
- float vec[4][2];
- node_link_bezier_handles(v2d, snode, *link, vec);
-
- float data[NODE_LINK_RESOL * 2 + 2];
- BKE_curve_forward_diff_bezier(
- vec[0][0], vec[1][0], vec[2][0], vec[3][0], data, resolution, sizeof(float[2]));
- BKE_curve_forward_diff_bezier(
- vec[0][1], vec[1][1], vec[2][1], vec[3][1], data + 1, resolution, sizeof(float[2]));
-
- for (int i = 0; i < resolution * 2; i += 2) {
- float *l1 = &data[i];
- float *l2 = &data[i + 2];
- float distance = dist_squared_to_line_segment_v2(cursor, l1, l2);
+ std::array<float2, NODE_LINK_RESOL + 1> coords;
+ node_link_bezier_points_evaluated(*link, coords);
+
+ for (const int i : IndexRange(coords.size() - 1)) {
+ const float distance = dist_squared_to_line_segment_v2(cursor, coords[i], coords[i + 1]);
if (distance < cursor_link_touch_distance) {
link_to_pick = link;
nldrag.last_picked_multi_input_socket_link = link_to_pick;
@@ -310,35 +292,24 @@ struct LinkAndPosition {
float2 multi_socket_position;
};
-void sort_multi_input_socket_links(SpaceNode &snode,
- bNode &node,
- bNodeLink *drag_link,
- const float2 *cursor)
+static void sort_multi_input_socket_links_with_drag(bNode &node,
+ bNodeLink &drag_link,
+ const float2 &cursor)
{
- LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
- if (!(socket->flag & SOCK_MULTI_INPUT)) {
+ for (bNodeSocket *socket : node.input_sockets()) {
+ if (!socket->is_multi_input()) {
continue;
}
- Vector<LinkAndPosition, 8> links;
+ const float2 &socket_location = {socket->locx, socket->locy};
- LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
- if (link->tosock == socket) {
- links.append(
- {link,
- node_link_calculate_multi_input_position({link->tosock->locx, link->tosock->locy},
- link->multi_input_socket_index,
- link->tosock->total_inputs)});
- }
- }
+ Vector<LinkAndPosition, 8> links;
+ for (bNodeLink *link : socket->directly_linked_links()) {
+ const float2 location = node_link_calculate_multi_input_position(
+ socket_location, link->multi_input_socket_index, link->tosock->total_inputs);
+ links.append({link, location});
+ };
- if (drag_link) {
- LinkAndPosition link_and_position{};
- link_and_position.link = drag_link;
- if (cursor) {
- link_and_position.multi_socket_position = *cursor;
- }
- links.append(link_and_position);
- }
+ links.append({&drag_link, cursor});
std::sort(links.begin(), links.end(), [](const LinkAndPosition a, const LinkAndPosition b) {
return a.multi_socket_position.y < b.multi_socket_position.y;
@@ -350,6 +321,23 @@ void sort_multi_input_socket_links(SpaceNode &snode,
}
}
+void update_multi_input_indices_for_removed_links(bNode &node)
+{
+ for (bNodeSocket *socket : node.input_sockets()) {
+ if (!socket->is_multi_input()) {
+ continue;
+ }
+ Vector<bNodeLink *, 8> links = socket->directly_linked_links();
+ std::sort(links.begin(), links.end(), [](const bNodeLink *a, const bNodeLink *b) {
+ return a->multi_input_socket_index < b->multi_input_socket_index;
+ });
+
+ for (const int i : links.index_range()) {
+ links[i]->multi_input_socket_index = i;
+ }
+ }
+}
+
static void snode_autoconnect(SpaceNode &snode, const bool allow_multiple, const bool replace)
{
bNodeTree *ntree = snode.edittree;
@@ -434,18 +422,18 @@ namespace viewer_linking {
* \{ */
/* Depending on the node tree type, different socket types are supported by viewer nodes. */
-static bool socket_can_be_viewed(const OutputSocketRef &socket)
+static bool socket_can_be_viewed(const bNodeSocket &socket)
{
- if (nodeSocketIsHidden(socket.bsocket())) {
+ if (nodeSocketIsHidden(&socket)) {
return false;
}
- if (socket.idname() == "NodeSocketVirtual") {
+ if (STREQ(socket.idname, "NodeSocketVirtual")) {
return false;
}
- if (socket.tree().btree()->type != NTREE_GEOMETRY) {
+ if (socket.owner_tree().type != NTREE_GEOMETRY) {
return true;
}
- return ELEM(socket.typeinfo()->type,
+ return ELEM(socket.typeinfo->type,
SOCK_GEOMETRY,
SOCK_FLOAT,
SOCK_VECTOR,
@@ -502,15 +490,15 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
return nullptr;
}
-static bool is_viewer_node(const NodeRef &node)
+static bool is_viewer_node(const bNode &node)
{
- return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
+ return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
}
-static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
+static Vector<const bNode *> find_viewer_nodes(const bNodeTree &tree)
{
- Vector<const NodeRef *> viewer_nodes;
- for (const NodeRef *node : tree.nodes()) {
+ Vector<const bNode *> viewer_nodes;
+ for (const bNode *node : tree.all_nodes()) {
if (is_viewer_node(*node)) {
viewer_nodes.append(node);
}
@@ -518,20 +506,20 @@ static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
return viewer_nodes;
}
-static bool is_viewer_socket_in_viewer(const InputSocketRef &socket)
+static bool is_viewer_socket_in_viewer(const bNodeSocket &socket)
{
- const NodeRef &node = socket.node();
+ const bNode &node = socket.owner_node();
BLI_assert(is_viewer_node(node));
- if (node.typeinfo()->type == GEO_NODE_VIEWER) {
+ if (node.typeinfo->type == GEO_NODE_VIEWER) {
return true;
}
return socket.index() == 0;
}
-static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node)
+static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node)
{
- for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) {
- if (&target_socket->node() != &viewer_node) {
+ for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) {
+ if (&target_socket->owner_node() != &viewer_node) {
continue;
}
if (!target_socket->is_available()) {
@@ -561,39 +549,39 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &
}
}
-static const NodeRef *get_existing_viewer(const NodeTreeRef &tree)
+static const bNode *get_existing_viewer(const bNodeTree &tree)
{
- Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree);
+ Vector<const bNode *> viewer_nodes = find_viewer_nodes(tree);
/* Check if there is already an active viewer node that should be used. */
- for (const NodeRef *viewer_node : viewer_nodes) {
- if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) {
+ for (const bNode *viewer_node : viewer_nodes) {
+ if (viewer_node->flag & NODE_DO_OUTPUT) {
return viewer_node;
}
}
/* If no active but non-active viewers exist, make one active. */
if (!viewer_nodes.is_empty()) {
- viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT;
+ const_cast<bNode *>(viewer_nodes[0])->flag |= NODE_DO_OUTPUT;
return viewer_nodes[0];
}
return nullptr;
}
-static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node,
- const NodeRef &node_to_view)
+static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node,
+ const bNode &node_to_view)
{
/* Check if any of the output sockets is selected, which is the case when the user just clicked
* on the socket. */
- for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
- if (output_socket->bsocket()->flag & SELECT) {
+ for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
+ if (output_socket->flag & SELECT) {
return output_socket;
}
}
- const OutputSocketRef *last_socket_linked_to_viewer = nullptr;
+ const bNodeSocket *last_socket_linked_to_viewer = nullptr;
if (active_viewer_node != nullptr) {
- for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
if (!socket_can_be_viewed(*output_socket)) {
continue;
}
@@ -604,7 +592,7 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act
}
if (last_socket_linked_to_viewer == nullptr) {
/* If no output is connected to a viewer, use the first output that can be viewed. */
- for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
if (socket_can_be_viewed(*output_socket)) {
return output_socket;
}
@@ -612,10 +600,10 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act
}
else {
/* Pick the next socket to be linked to the viewer. */
- const int tot_outputs = node_to_view.outputs().size();
+ const int tot_outputs = node_to_view.output_sockets().size();
for (const int offset : IndexRange(1, tot_outputs - 1)) {
const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
- const OutputSocketRef &output_socket = node_to_view.output(index);
+ const bNodeSocket &output_socket = node_to_view.output_socket(index);
if (!socket_can_be_viewed(output_socket)) {
continue;
}
@@ -639,8 +627,9 @@ static int link_socket_to_viewer(const bContext &C,
if (viewer_bnode == nullptr) {
/* Create a new viewer node if none exists. */
const int viewer_type = get_default_viewer_type(&C);
- viewer_bnode = node_add_node(
- C, nullptr, viewer_type, bsocket_to_view.locx + 100, bsocket_to_view.locy);
+ const float2 location{bsocket_to_view.locx / UI_DPI_FAC + 100,
+ bsocket_to_view.locy / UI_DPI_FAC};
+ viewer_bnode = add_static_node(C, viewer_type, location);
if (viewer_bnode == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -682,20 +671,15 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree *btree = snode.edittree;
+ btree->ensure_topology_cache();
- const NodeTreeRef tree{btree};
- const NodeRef &node_to_view = *tree.find_node(bnode_to_view);
- const NodeRef *active_viewer_node = get_existing_viewer(tree);
-
- const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
- node_to_view);
- if (socket_to_view == nullptr) {
+ bNode *active_viewer_bnode = const_cast<bNode *>(get_existing_viewer(*btree));
+ bNodeSocket *bsocket_to_view = const_cast<bNodeSocket *>(
+ find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view));
+ if (bsocket_to_view == nullptr) {
return OPERATOR_FINISHED;
}
-
- bNodeSocket &bsocket_to_view = *socket_to_view->bsocket();
- bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
- return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
+ return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view);
}
/** \} */
@@ -949,6 +933,7 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
if (nldrag->in_out == SOCK_OUT) {
bNode *tnode;
bNodeSocket *tsock = nullptr;
+ snode.edittree->ensure_topology_cache();
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
for (bNodeLink *link : nldrag->links) {
/* skip if socket is on the same node as the fromsock */
@@ -975,19 +960,19 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
continue;
}
if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) {
- sort_multi_input_socket_links(snode, *tnode, link, &cursor);
+ sort_multi_input_socket_links_with_drag(*tnode, *link, cursor);
}
}
}
else {
for (bNodeLink *link : nldrag->links) {
- if (nldrag->last_node_hovered_while_dragging_a_link) {
- sort_multi_input_socket_links(
- snode, *nldrag->last_node_hovered_while_dragging_a_link, nullptr, &cursor);
- }
link->tonode = nullptr;
link->tosock = nullptr;
}
+ if (nldrag->last_node_hovered_while_dragging_a_link) {
+ update_multi_input_indices_for_removed_links(
+ *nldrag->last_node_hovered_while_dragging_a_link);
+ }
}
}
else {
@@ -1184,7 +1169,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool detach = RNA_boolean_get(op->ptr, "detach");
- int mval[2];
+ int2 mval;
WM_event_drag_start_mval(event, &region, mval);
float2 cursor;
@@ -1324,28 +1309,6 @@ void NODE_OT_link_make(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Node Link Intersect
- * \{ */
-
-static bool node_links_intersect(bNodeLink &link, const float mcoords[][2], int tot)
-{
- float coord_array[NODE_LINK_RESOL + 1][2];
-
- if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) {
- for (int i = 0; i < tot - 1; i++) {
- for (int b = 0; b < NODE_LINK_RESOL; b++) {
- if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Cut Link Operator
* \{ */
@@ -1353,56 +1316,63 @@ static int cut_links_exec(bContext *C, wmOperator *op)
{
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- ARegion &region = *CTX_wm_region(C);
+ const ARegion &region = *CTX_wm_region(C);
- int i = 0;
- float mcoords[256][2];
+ Vector<float2> path;
RNA_BEGIN (op->ptr, itemptr, "path") {
- float loc[2];
-
- RNA_float_get_array(&itemptr, "loc", loc);
- UI_view2d_region_to_view(
- &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
- i++;
- if (i >= 256) {
+ float2 loc_region;
+ RNA_float_get_array(&itemptr, "loc", loc_region);
+ float2 loc_view;
+ UI_view2d_region_to_view(&region.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y);
+ path.append(loc_view);
+ if (path.size() >= 256) {
break;
}
}
RNA_END;
- if (i > 1) {
- bool found = false;
+ if (path.is_empty()) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
- ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
+ bool found = false;
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
- if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
- continue;
- }
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- if (node_links_intersect(*link, mcoords, i)) {
+ bNodeTree &node_tree = *snode.edittree;
- if (found == false) {
- /* TODO(sergey): Why did we kill jobs twice? */
- ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- found = true;
- }
+ Set<bNode *> affected_nodes;
- bNode *to_node = link->tonode;
- nodeRemLink(snode.edittree, link);
- sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
- }
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_tree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
+ continue;
}
- ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
- if (found) {
- return OPERATOR_FINISHED;
+ if (link_path_intersection(*link, path)) {
+
+ if (!found) {
+ /* TODO(sergey): Why did we kill jobs twice? */
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
+ found = true;
+ }
+
+ bNode *to_node = link->tonode;
+ nodeRemLink(snode.edittree, link);
+ affected_nodes.add(to_node);
}
+ }
- return OPERATOR_CANCELLED;
+ node_tree.ensure_topology_cache();
+ for (bNode *node : affected_nodes) {
+ update_multi_input_indices_for_removed_links(*node);
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
+ if (found) {
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
}
void NODE_OT_links_cut(wmOperatorType *ot)
@@ -1436,69 +1406,99 @@ void NODE_OT_links_cut(wmOperatorType *ot)
/** \name Mute Links Operator
* \{ */
+static bool all_links_muted(const bNodeSocket &socket)
+{
+ for (const bNodeLink *link : socket.directly_linked_links()) {
+ if (!(link->flag & NODE_LINK_MUTED)) {
+ return false;
+ }
+ }
+ return true;
+}
+
static int mute_links_exec(bContext *C, wmOperator *op)
{
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- ARegion &region = *CTX_wm_region(C);
+ const ARegion &region = *CTX_wm_region(C);
+ bNodeTree &ntree = *snode.edittree;
- int i = 0;
- float mcoords[256][2];
+ Vector<float2> path;
RNA_BEGIN (op->ptr, itemptr, "path") {
- float loc[2];
-
- RNA_float_get_array(&itemptr, "loc", loc);
- UI_view2d_region_to_view(
- &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
- i++;
- if (i >= 256) {
+ float2 loc_region;
+ RNA_float_get_array(&itemptr, "loc", loc_region);
+ float2 loc_view;
+ UI_view2d_region_to_view(&region.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y);
+ path.append(loc_view);
+ if (path.size() >= 256) {
break;
}
}
RNA_END;
- if (i > 1) {
- ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
+ if (path.is_empty()) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
- /* Count intersected links and clear test flag. */
- int tot = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
- if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
- continue;
- }
- link->flag &= ~NODE_LINK_TEST;
- if (node_links_intersect(*link, mcoords, i)) {
- tot++;
- }
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
+
+ ntree.ensure_topology_cache();
+
+ Set<bNodeLink *> affected_links;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
+ continue;
}
- if (tot == 0) {
- return OPERATOR_CANCELLED;
+ if (!link_path_intersection(*link, path)) {
+ continue;
}
+ affected_links.add(link);
+ }
- /* Mute links. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
- if (node_link_is_hidden_or_dimmed(region.v2d, *link) || (link->flag & NODE_LINK_TEST)) {
- continue;
- }
+ if (affected_links.is_empty()) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree};
- if (node_links_intersect(*link, mcoords, i)) {
- nodeMuteLinkToggle(snode.edittree, link);
+ for (bNodeLink *link : affected_links) {
+ nodeLinkSetMute(&ntree, link, !(link->flag & NODE_LINK_MUTED));
+ const bool muted = link->flag & NODE_LINK_MUTED;
+
+ /* Propagate mute status downstream past reroute nodes. */
+ if (link->tonode->is_reroute()) {
+ Stack<bNodeLink *> links;
+ links.push_multiple(link->tonode->output_sockets().first()->directly_linked_links());
+ while (!links.is_empty()) {
+ bNodeLink *link = links.pop();
+ nodeLinkSetMute(&ntree, link, muted);
+ if (!link->tonode->is_reroute()) {
+ continue;
+ }
+ links.push_multiple(link->tonode->output_sockets().first()->directly_linked_links());
}
}
-
- /* Clear remaining test flags. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
- if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
- continue;
+ /* Propagate mute status upstream past reroutes, but only if all outputs are muted. */
+ if (link->fromnode->is_reroute()) {
+ if (!muted || all_links_muted(*link->fromsock)) {
+ Stack<bNodeLink *> links;
+ links.push_multiple(link->fromnode->input_sockets().first()->directly_linked_links());
+ while (!links.is_empty()) {
+ bNodeLink *link = links.pop();
+ nodeLinkSetMute(&ntree, link, muted);
+ if (!link->fromnode->is_reroute()) {
+ continue;
+ }
+ if (!muted || all_links_muted(*link->fromsock)) {
+ links.push_multiple(link->fromnode->input_sockets().first()->directly_linked_links());
+ }
+ }
}
- link->flag &= ~NODE_LINK_TEST;
}
-
- ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
- return OPERATOR_FINISHED;
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
+ return OPERATOR_FINISHED;
}
void NODE_OT_links_mute(wmOperatorType *ot)
@@ -1619,7 +1619,9 @@ void NODE_OT_parent_set(wmOperatorType *ot)
#define NODE_JOIN_DONE 1
#define NODE_JOIN_IS_DESCENDANT 2
-static void node_join_attach_recursive(bNode *node, bNode *frame)
+static void node_join_attach_recursive(bNode *node,
+ bNode *frame,
+ const Set<bNode *> &selected_nodes)
{
node->done |= NODE_JOIN_DONE;
@@ -1629,21 +1631,21 @@ static void node_join_attach_recursive(bNode *node, bNode *frame)
else if (node->parent) {
/* call recursively */
if (!(node->parent->done & NODE_JOIN_DONE)) {
- node_join_attach_recursive(node->parent, frame);
+ node_join_attach_recursive(node->parent, frame, selected_nodes);
}
/* in any case: if the parent is a descendant, so is the child */
if (node->parent->done & NODE_JOIN_IS_DESCENDANT) {
node->done |= NODE_JOIN_IS_DESCENDANT;
}
- else if (node->flag & NODE_TEST) {
+ else if (selected_nodes.contains(node)) {
/* if parent is not an descendant of the frame, reattach the node */
nodeDetachNode(node);
nodeAttachNode(node, frame);
node->done |= NODE_JOIN_IS_DESCENDANT;
}
}
- else if (node->flag & NODE_TEST) {
+ else if (selected_nodes.contains(node)) {
nodeAttachNode(node, frame);
node->done |= NODE_JOIN_IS_DESCENDANT;
}
@@ -1651,21 +1653,13 @@ static void node_join_attach_recursive(bNode *node, bNode *frame)
static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
- /* XXX save selection: node_add_node call below sets the new frame as single
- * active+selected node */
- LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
- if (node->flag & NODE_SELECT) {
- node->flag |= NODE_TEST;
- }
- else {
- node->flag &= ~NODE_TEST;
- }
- }
+ const Set<bNode *> selected_nodes = get_selected_nodes(ntree);
- bNode *frame = node_add_node(*C, nullptr, NODE_FRAME, 0.0f, 0.0f);
+ bNode *frame_node = nodeAddStaticNode(C, &ntree, NODE_FRAME);
/* reset tags */
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
@@ -1674,18 +1668,12 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_JOIN_DONE)) {
- node_join_attach_recursive(node, frame);
- }
- }
-
- /* restore selection */
- LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
- if (node->flag & NODE_TEST) {
- node->flag |= NODE_SELECT;
+ node_join_attach_recursive(node, frame_node, selected_nodes);
}
}
node_sort(ntree);
+ ED_node_tree_propagate_change(C, &bmain, snode.edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1714,11 +1702,11 @@ void NODE_OT_join(wmOperatorType *ot)
static bNode *node_find_frame_to_attach(ARegion &region,
const bNodeTree &ntree,
- const int mouse_xy[2])
+ const int2 mouse_xy)
{
/* convert mouse coordinates to v2d space */
- float cursor[2];
- UI_view2d_region_to_view(&region.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region.v2d, mouse_xy.x, mouse_xy.y, &cursor.x, &cursor.y);
LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) {
/* skip selected, those are the nodes we want to attach */
@@ -1739,32 +1727,33 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
bNode *frame = node_find_frame_to_attach(region, ntree, event->mval);
+ if (frame == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
- if (frame) {
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
- if (node->flag & NODE_SELECT) {
- if (node->parent == nullptr) {
- /* disallow moving a parent into its child */
- if (nodeAttachNodeCheck(frame, node) == false) {
- /* attach all unparented nodes */
- nodeAttachNode(node, frame);
- }
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (node->flag & NODE_SELECT) {
+ if (node->parent == nullptr) {
+ /* disallow moving a parent into its child */
+ if (nodeAttachNodeCheck(frame, node) == false) {
+ /* attach all unparented nodes */
+ nodeAttachNode(node, frame);
}
- else {
- /* attach nodes which share parent with the frame */
- bNode *parent;
- for (parent = frame->parent; parent; parent = parent->parent) {
- if (parent == node->parent) {
- break;
- }
+ }
+ else {
+ /* attach nodes which share parent with the frame */
+ bNode *parent;
+ for (parent = frame->parent; parent; parent = parent->parent) {
+ if (parent == node->parent) {
+ break;
}
+ }
- if (parent) {
- /* disallow moving a parent into its child */
- if (nodeAttachNodeCheck(frame, node) == false) {
- nodeDetachNode(node);
- nodeAttachNode(node, frame);
- }
+ if (parent) {
+ /* disallow moving a parent into its child */
+ if (nodeAttachNodeCheck(frame, node) == false) {
+ nodeDetachNode(node);
+ nodeAttachNode(node, frame);
}
}
}
@@ -1942,6 +1931,7 @@ static bool ed_node_link_conditions(ScrArea *area,
void ED_node_link_intersect_test(ScrArea *area, int test)
{
+ using namespace blender;
using namespace blender::ed::space_node;
bNode *select;
@@ -1965,36 +1955,34 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
bNodeLink *selink = nullptr;
float dist_best = FLT_MAX;
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- float coord_array[NODE_LINK_RESOL + 1][2];
if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
- if (node_link_bezier_points(nullptr, nullptr, *link, coord_array, NODE_LINK_RESOL)) {
- float dist = FLT_MAX;
+ std::array<float2, NODE_LINK_RESOL + 1> coords;
+ node_link_bezier_points_evaluated(*link, coords);
+ float dist = FLT_MAX;
- /* loop over link coords to find shortest dist to
- * upper left node edge of a intersected line segment */
- for (int i = 0; i < NODE_LINK_RESOL; i++) {
- /* Check if the node rectangle intersects the line from this point to next one. */
- if (BLI_rctf_isect_segment(&select->totr, coord_array[i], coord_array[i + 1])) {
- /* store the shortest distance to the upper left edge
- * of all intersections found so far */
- const float node_xy[] = {select->totr.xmin, select->totr.ymax};
+ /* loop over link coords to find shortest dist to
+ * upper left node edge of a intersected line segment */
+ for (int i = 0; i < NODE_LINK_RESOL; i++) {
+ /* Check if the node rectangle intersects the line from this point to next one. */
+ if (BLI_rctf_isect_segment(&select->totr, coords[i], coords[i + 1])) {
+ /* store the shortest distance to the upper left edge
+ * of all intersections found so far */
+ const float node_xy[] = {select->totr.xmin, select->totr.ymax};
- /* to be precise coord_array should be clipped by select->totr,
- * but not done since there's no real noticeable difference */
- dist = min_ff(
- dist_squared_to_line_segment_v2(node_xy, coord_array[i], coord_array[i + 1]), dist);
- }
+ /* to be precise coords should be clipped by select->totr,
+ * but not done since there's no real noticeable difference */
+ dist = min_ff(dist_squared_to_line_segment_v2(node_xy, coords[i], coords[i + 1]), dist);
}
+ }
- /* we want the link with the shortest distance to node center */
- if (dist < dist_best) {
- dist_best = dist;
- selink = link;
- }
+ /* we want the link with the shortest distance to node center */
+ if (dist < dist_best) {
+ dist_best = dist;
+ selink = link;
}
}
@@ -2048,7 +2036,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn
/* Try to get the main socket based on the socket declaration. */
nodeDeclarationEnsure(&ntree, &node);
- const nodes::NodeDeclaration *node_decl = node.runtime->declaration;
+ const nodes::NodeDeclaration *node_decl = node.declaration();
if (node_decl != nullptr) {
Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
node_decl->outputs();
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 9d73156edab..82aaa2c3cc6 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -14,6 +14,7 @@
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
+#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_string_search.h"
#include "BLI_string_utf8.h"
@@ -22,6 +23,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_workspace.h"
#include "ED_node.h" /* own include */
@@ -48,7 +50,7 @@
namespace blender::ed::space_node {
-static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event);
+static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event);
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
@@ -100,17 +102,17 @@ rctf node_frame_rect_inside(const bNode &node)
return frame_inside;
}
-bool node_or_socket_isect_event(bContext *C, const wmEvent *event)
+bool node_or_socket_isect_event(const bContext &C, const wmEvent &event)
{
return is_event_over_node_or_socket(C, event);
}
-static bool node_frame_select_isect_mouse(bNode *node, const float2 &mouse)
+static bool node_frame_select_isect_mouse(const bNode &node, const float2 &mouse)
{
/* Frame nodes are selectable by their borders (including their whole rect - as for other nodes -
* would prevent e.g. box selection of nodes inside that frame). */
- const rctf frame_inside = node_frame_rect_inside(*node);
- if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y) &&
+ const rctf frame_inside = node_frame_rect_inside(node);
+ if (BLI_rctf_isect_pt(&node.totr, mouse.x, mouse.y) &&
!BLI_rctf_isect_pt(&frame_inside, mouse.x, mouse.y)) {
return true;
}
@@ -118,19 +120,18 @@ static bool node_frame_select_isect_mouse(bNode *node, const float2 &mouse)
return false;
}
-static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
+static bNode *node_under_mouse_select(bNodeTree &ntree, const float2 mouse)
{
LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
switch (node->type) {
case NODE_FRAME: {
- const float2 mouse{(float)mx, (float)my};
- if (node_frame_select_isect_mouse(node, mouse)) {
+ if (node_frame_select_isect_mouse(*node, mouse)) {
return node;
}
break;
}
default: {
- if (BLI_rctf_isect_pt(&node->totr, mx, my)) {
+ if (BLI_rctf_isect_pt(&node->totr, int(mouse.x), int(mouse.y))) {
return node;
}
break;
@@ -140,35 +141,32 @@ static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
return nullptr;
}
-static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse)
+static bool node_under_mouse_tweak(const bNodeTree &ntree, const float2 &mouse)
{
- using namespace blender::math;
-
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ LISTBASE_FOREACH_BACKWARD (const bNode *, node, &ntree.nodes) {
switch (node->type) {
case NODE_REROUTE: {
- bNodeSocket *socket = (bNodeSocket *)node->inputs.first;
- const float2 location{socket->locx, socket->locy};
- if (distance(mouse, location) < 24.0f) {
- return node;
+ const float2 location = node_to_view(*node, {node->locx, node->locy});
+ if (math::distance(mouse, location) < 24.0f) {
+ return true;
}
break;
}
case NODE_FRAME: {
- if (node_frame_select_isect_mouse(node, mouse)) {
- return node;
+ if (node_frame_select_isect_mouse(*node, mouse)) {
+ return true;
}
break;
}
default: {
if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y)) {
- return node;
+ return true;
}
break;
}
}
}
- return nullptr;
+ return false;
}
static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mouse)
@@ -187,17 +185,17 @@ static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mous
return false;
}
-static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
+static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
- float2 mouse;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ ARegion &region = *CTX_wm_region(&C);
- int mval[2];
- WM_event_drag_start_mval(event, region, mval);
+ int2 mval;
+ WM_event_drag_start_mval(&event, &region, mval);
- UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &mouse.x, &mouse.y);
- return is_position_over_node_or_socket(*snode, mouse);
+ float2 mouse;
+ UI_view2d_region_to_view(&region.v2d, mval.x, mval.y, &mouse.x, &mouse.y);
+ return is_position_over_node_or_socket(snode, mouse);
}
void node_socket_select(bNode *node, bNodeSocket &sock)
@@ -314,6 +312,17 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node
}
}
+Set<bNode *> get_selected_nodes(bNodeTree &node_tree)
+{
+ Set<bNode *> selected_nodes;
+ for (bNode *node : node_tree.all_nodes()) {
+ if (node->flag & NODE_SELECT) {
+ selected_nodes.add(node);
+ }
+ }
+ return selected_nodes;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -412,9 +421,7 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op)
const int type = RNA_enum_get(op->ptr, "type");
if (!extend) {
- LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
- nodeSetSelected(node, false);
- }
+ node_deselect_all(snode);
}
nodeSetSelected(node_act, true);
@@ -514,8 +521,8 @@ void node_select_single(bContext &C, bNode &node)
static bool node_mouse_select(bContext *C,
wmOperator *op,
- const int mval[2],
- struct SelectPick_Params *params)
+ const int2 mval,
+ SelectPick_Params *params)
{
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
@@ -526,7 +533,6 @@ static bool node_mouse_select(bContext *C,
bNode *node, *tnode;
bNodeSocket *sock = nullptr;
bNodeSocket *tsock;
- float cursor[2];
/* always do socket_select when extending selection. */
const bool socket_select = (params->sel_op == SEL_OP_XOR) ||
@@ -536,7 +542,8 @@ static bool node_mouse_select(bContext *C,
bool node_was_selected = false;
/* get mouse coordinates in view2d space */
- UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region.v2d, mval.x, mval.y, &cursor.x, &cursor.y);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
@@ -593,7 +600,7 @@ static bool node_mouse_select(bContext *C,
if (!sock) {
/* find the closest visible node */
- node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
+ node = node_under_mouse_select(*snode.edittree, cursor);
found = (node != nullptr);
node_was_selected = node && (node->flag & SELECT);
@@ -603,9 +610,7 @@ static bool node_mouse_select(bContext *C,
}
else if (found || params->deselect_all) {
/* Deselect everything. */
- for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
- nodeSetSelected(tnode, false);
- }
+ node_deselect_all(snode);
changed = true;
}
}
@@ -640,37 +645,38 @@ static bool node_mouse_select(bContext *C,
}
}
- /* update node order */
- if (changed || found) {
- bool active_texture_changed = false;
- bool viewer_node_changed = false;
- if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
- viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
- ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
- }
- else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
- ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
- }
- ED_node_set_active_viewer_key(&snode);
- node_sort(*snode.edittree);
- if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
- viewer_node_changed) {
- DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
- }
+ if (!(changed || found)) {
+ return false;
+ }
- WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
+ bool active_texture_changed = false;
+ bool viewer_node_changed = false;
+ if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
+ viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
+ }
+ else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
+ ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
}
+ ED_node_set_active_viewer_key(&snode);
+ node_sort(*snode.edittree);
+ if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
+ viewer_node_changed) {
+ DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
+
+ WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
- return changed || found;
+ return true;
}
static int node_select_exec(bContext *C, wmOperator *op)
{
/* get settings from RNA properties for operator */
- int mval[2];
+ int2 mval;
RNA_int_get_array(op->ptr, "location", mval);
- struct SelectPick_Params params = {};
+ SelectPick_Params params = {};
ED_select_pick_params_from_operator(op->ptr, &params);
/* perform the select */
@@ -747,7 +753,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- node_select_all(&node_tree.nodes, SEL_DESELECT);
+ node_deselect_all(snode);
}
LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
@@ -787,7 +793,7 @@ static int node_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *ev
{
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
- if (tweak && is_event_over_node_or_socket(C, event)) {
+ if (tweak && is_event_over_node_or_socket(*C, *event)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
@@ -836,7 +842,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op)
bNode *node;
int x, y, radius;
- float offset[2];
+ float2 offset;
float zoom = (float)(BLI_rcti_size_x(&region->winrct)) /
(float)(BLI_rctf_size_x(&region->v2d.cur));
@@ -846,7 +852,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op)
WM_gesture_is_modal_first((const wmGesture *)op->customdata));
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_deselect_all(*snode);
}
/* get operator properties */
@@ -854,7 +860,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op)
y = RNA_int_get(op->ptr, "y");
radius = RNA_int_get(op->ptr, "radius");
- UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
+ UI_view2d_region_to_view(&region->v2d, x, y, &offset.x, &offset.y);
for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
switch (node->type) {
@@ -916,7 +922,7 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent *
{
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
- if (tweak && is_event_over_node_or_socket(C, event)) {
+ if (tweak && is_event_over_node_or_socket(*C, *event)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
@@ -938,7 +944,7 @@ static bool do_lasso_select_node(bContext *C,
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_deselect_all(*snode);
changed = true;
}
@@ -968,14 +974,14 @@ static bool do_lasso_select_node(bContext *C,
break;
}
default: {
- int screen_co[2];
- const float cent[2] = {BLI_rctf_cent_x(&node->totr), BLI_rctf_cent_y(&node->totr)};
+ int2 screen_co;
+ const float2 center = {BLI_rctf_cent_x(&node->totr), BLI_rctf_cent_y(&node->totr)};
/* marker in screen coords */
if (UI_view2d_view_to_region_clip(
- &region->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) &&
- BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
+ &region->v2d, center.x, center.y, &screen_co.x, &screen_co.y) &&
+ BLI_rcti_isect_pt(&rect, screen_co.x, screen_co.y) &&
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co.x, screen_co.y, INT_MAX)) {
nodeSetSelected(node, select);
changed = true;
}
@@ -1042,13 +1048,48 @@ void NODE_OT_select_lasso(wmOperatorType *ot)
/** \name (De)select All Operator
* \{ */
+static bool any_node_selected(const bNodeTree &node_tree)
+{
+ for (const bNode *node : node_tree.all_nodes()) {
+ if (node->flag & NODE_SELECT) {
+ return true;
+ }
+ }
+ return false;
+}
+
static int node_select_all_exec(bContext *C, wmOperator *op)
{
SpaceNode &snode = *CTX_wm_space_node(C);
- ListBase *node_lb = &snode.edittree->nodes;
+ bNodeTree &node_tree = *snode.edittree;
+
+ node_tree.ensure_topology_cache();
+
int action = RNA_enum_get(op->ptr, "action");
+ if (action == SEL_TOGGLE) {
+ if (any_node_selected(node_tree)) {
+ action = SEL_DESELECT;
+ }
+ else {
+ action = SEL_SELECT;
+ }
+ }
- node_select_all(node_lb, action);
+ switch (action) {
+ case SEL_SELECT:
+ for (bNode *node : node_tree.all_nodes()) {
+ nodeSetSelected(node, true);
+ }
+ break;
+ case SEL_DESELECT:
+ node_deselect_all(snode);
+ break;
+ case SEL_INVERT:
+ for (bNode *node : node_tree.all_nodes()) {
+ nodeSetSelected(node, !(node->flag & SELECT));
+ }
+ break;
+ }
node_sort(*snode.edittree);
@@ -1084,22 +1125,21 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &node_tree = *snode.edittree;
- LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
- node->flag &= ~NODE_TEST;
- }
+ node_tree.ensure_topology_cache();
- LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
- if (nodeLinkIsHidden(link)) {
- continue;
- }
- if (link->fromnode && link->tonode && (link->fromnode->flag & NODE_SELECT)) {
- link->tonode->flag |= NODE_TEST;
- }
- }
+ Set<bNode *> initial_selection = get_selected_nodes(node_tree);
- LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
- if (node->flag & NODE_TEST) {
- nodeSetSelected(node, true);
+ for (bNode *node : initial_selection) {
+ for (bNodeSocket *output_socket : node->output_sockets()) {
+ if (!output_socket->is_available()) {
+ continue;
+ }
+ for (bNodeSocket *input_socket : output_socket->directly_linked_sockets()) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ nodeSetSelected(&input_socket->owner_node(), true);
+ }
}
}
@@ -1135,22 +1175,21 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &node_tree = *snode.edittree;
- LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
- node->flag &= ~NODE_TEST;
- }
+ node_tree.ensure_topology_cache();
- LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
- if (nodeLinkIsHidden(link)) {
- continue;
- }
- if (link->fromnode && link->tonode && (link->tonode->flag & NODE_SELECT)) {
- link->fromnode->flag |= NODE_TEST;
- }
- }
+ Set<bNode *> initial_selection = get_selected_nodes(node_tree);
- LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
- if (node->flag & NODE_TEST) {
- nodeSetSelected(node, true);
+ for (bNode *node : initial_selection) {
+ for (bNodeSocket *input_socket : node->input_sockets()) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ for (bNodeSocket *output_socket : input_socket->directly_linked_sockets()) {
+ if (!output_socket->is_available()) {
+ continue;
+ }
+ nodeSetSelected(&output_socket->owner_node(), true);
+ }
}
}
@@ -1298,7 +1337,7 @@ static void node_find_create_label(const bNode *node, char *str, int maxlen)
}
/* Generic search invoke. */
-static void node_find_update_fn(const struct bContext *C,
+static void node_find_update_fn(const bContext *C,
void *UNUSED(arg),
const char *str,
uiSearchItems *items,
@@ -1330,7 +1369,7 @@ static void node_find_update_fn(const struct bContext *C,
BLI_string_search_free(search);
}
-static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2)
+static void node_find_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *active = (bNode *)arg2;
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 58a313c328e..5fc194e02a4 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -758,43 +758,42 @@ namespace blender::ed::space_node {
/**************************** Node Tree Layout *******************************/
static void ui_node_draw_input(
- uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
+ uiLayout &layout, bContext &C, bNodeTree &ntree, bNode &node, bNodeSocket &input, int depth);
static void ui_node_draw_node(
- uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
+ uiLayout &layout, bContext &C, bNodeTree &ntree, bNode &node, int depth)
{
- bNodeSocket *input;
PointerRNA nodeptr;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
- if (node->typeinfo->draw_buttons) {
- if (node->type != NODE_GROUP) {
- uiLayoutSetPropSep(layout, true);
- node->typeinfo->draw_buttons(layout, C, &nodeptr);
+ if (node.typeinfo->draw_buttons) {
+ if (node.type != NODE_GROUP) {
+ uiLayoutSetPropSep(&layout, true);
+ node.typeinfo->draw_buttons(&layout, &C, &nodeptr);
}
}
- for (input = (bNodeSocket *)node->inputs.first; input; input = input->next) {
- ui_node_draw_input(layout, C, ntree, node, input, depth + 1);
+ LISTBASE_FOREACH (bNodeSocket *, input, &node.inputs) {
+ ui_node_draw_input(layout, C, ntree, node, *input, depth + 1);
}
}
static void ui_node_draw_input(
- uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
+ uiLayout &layout, bContext &C, bNodeTree &ntree, bNode &node, bNodeSocket &input, int depth)
{
PointerRNA inputptr, nodeptr;
- uiBlock *block = uiLayoutGetBlock(layout);
+ uiBlock *block = uiLayoutGetBlock(&layout);
uiLayout *row = nullptr;
bool dependency_loop;
- if (input->flag & SOCK_UNAVAIL) {
+ if (input.flag & SOCK_UNAVAIL) {
return;
}
/* to avoid eternal loops on cyclic dependencies */
- node->flag |= NODE_TEST;
- bNode *lnode = (input->link) ? input->link->fromnode : nullptr;
+ node.flag |= NODE_TEST;
+ bNode *lnode = (input.link) ? input.link->fromnode : nullptr;
dependency_loop = (lnode && (lnode->flag & NODE_TEST));
if (dependency_loop) {
@@ -802,10 +801,10 @@ static void ui_node_draw_input(
}
/* socket RNA pointer */
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, &input, &inputptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
- row = uiLayoutRow(layout, true);
+ row = uiLayoutRow(&layout, true);
/* Decorations are added manually here. */
uiLayoutSetPropDecorate(row, false);
@@ -821,8 +820,8 @@ static void ui_node_draw_input(
if (lnode &&
(lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
- int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
- ICON_DISCLOSURE_TRI_DOWN;
+ int icon = (input.flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
+ ICON_DISCLOSURE_TRI_DOWN;
uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
}
@@ -831,7 +830,7 @@ static void ui_node_draw_input(
sub = uiLayoutRow(sub, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- uiItemL(sub, IFACE_(input->name), ICON_NONE);
+ uiItemL(sub, IFACE_(input.name), ICON_NONE);
}
if (dependency_loop) {
@@ -840,28 +839,28 @@ static void ui_node_draw_input(
}
else if (lnode) {
/* input linked to a node */
- uiTemplateNodeLink(row, C, ntree, node, input);
+ uiTemplateNodeLink(row, &C, &ntree, &node, &input);
add_dummy_decorator = true;
- if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
+ if (depth == 0 || !(input.flag & SOCK_COLLAPSED)) {
if (depth == 0) {
- uiItemS(layout);
+ uiItemS(&layout);
}
- ui_node_draw_node(layout, C, ntree, lnode, depth);
+ ui_node_draw_node(layout, C, ntree, *lnode, depth);
}
}
else {
uiLayout *sub = uiLayoutRow(row, true);
- uiTemplateNodeLink(sub, C, ntree, node, input);
+ uiTemplateNodeLink(sub, &C, &ntree, &node, &input);
- if (input->flag & SOCK_HIDE_VALUE) {
+ if (input.flag & SOCK_HIDE_VALUE) {
add_dummy_decorator = true;
}
/* input not linked, show value */
else {
- switch (input->type) {
+ switch (input.type) {
case SOCK_VECTOR:
uiItemS(sub);
sub = uiLayoutColumn(sub, true);
@@ -876,11 +875,11 @@ static void ui_node_draw_input(
break;
case SOCK_STRING: {
const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id;
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) {
/* Only add the attribute search in the node editor, in other places there is not
* enough context. */
- node_geometry_add_attribute_search_button(*C, *node, inputptr, *sub);
+ node_geometry_add_attribute_search_button(C, node, inputptr, *sub);
}
else {
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
@@ -899,10 +898,10 @@ static void ui_node_draw_input(
uiItemDecoratorR(split_wrapper.decorate_column, nullptr, nullptr, 0);
}
- node_socket_add_tooltip(ntree, node, input, row);
+ node_socket_add_tooltip(ntree, node, input, *row);
/* clear */
- node->flag &= ~NODE_TEST;
+ node.flag &= ~NODE_TEST;
}
} // namespace blender::ed::space_node
@@ -924,9 +923,9 @@ void uiTemplateNodeView(
}
if (input) {
- ui_node_draw_input(layout, C, ntree, node, input, 0);
+ ui_node_draw_input(*layout, *C, *ntree, *node, *input, 0);
}
else {
- ui_node_draw_node(layout, C, ntree, node, 0);
+ ui_node_draw_node(*layout, *C, *ntree, *node, 0);
}
}
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index 6f30632244b..00756083580 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -177,7 +177,7 @@ void NODE_OT_view_selected(wmOperatorType *ot)
* \{ */
struct NodeViewMove {
- int mvalo[2];
+ int2 mvalo;
int xmin, ymin, xmax, ymax;
/** Original Offset for cancel. */
float xof_orig, yof_orig;
@@ -192,10 +192,10 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e
switch (event->type) {
case MOUSEMOVE:
- snode->xof -= (nvm->mvalo[0] - event->mval[0]);
- snode->yof -= (nvm->mvalo[1] - event->mval[1]);
- nvm->mvalo[0] = event->mval[0];
- nvm->mvalo[1] = event->mval[1];
+ snode->xof -= (nvm->mvalo.x - event->mval[0]);
+ snode->yof -= (nvm->mvalo.y - event->mval[1]);
+ nvm->mvalo.x = event->mval[0];
+ nvm->mvalo.y = event->mval[1];
/* prevent dragging image outside of the window and losing it! */
CLAMP(snode->xof, nvm->xmin, nvm->xmax);
@@ -252,10 +252,10 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_CANCELLED;
}
- nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct");
+ nvm = MEM_cnew<NodeViewMove>(__func__);
op->customdata = nvm;
- nvm->mvalo[0] = event->mval[0];
- nvm->mvalo[1] = event->mval[1];
+ nvm->mvalo.x = event->mval[0];
+ nvm->mvalo.y = event->mval[1];
nvm->xmin = -(region->winx / 2) - (ibuf->x * (0.5f * snode->zoom)) + pad;
nvm->xmax = (region->winx / 2) + (ibuf->x * (0.5f * snode->zoom)) - pad;
@@ -447,7 +447,7 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
} // namespace blender::ed::space_node
bool ED_space_node_get_position(
- Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2])
+ Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float fpos[2])
{
if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) {
return false;
@@ -645,7 +645,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* Don't handle events intended for nodes (which rely on click/drag distinction).
* which this operator would use since sampling is normally activated on press, see: T98191. */
- if (node_or_socket_isect_event(C, event)) {
+ if (node_or_socket_isect_event(*C, *event)) {
return OPERATOR_PASS_THROUGH;
}
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 15afd024766..17fc02e98a8 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -302,7 +302,7 @@ static void node_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
+static void node_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -362,7 +362,7 @@ static void node_area_tag_tree_recalc(SpaceNode *snode, ScrArea *area)
static void node_area_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* NOTE: #ED_area_tag_refresh will re-execute compositor. */
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -511,7 +511,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void node_area_refresh(const struct bContext *C, ScrArea *area)
+static void node_area_refresh(const bContext *C, ScrArea *area)
{
/* default now: refresh node is starting preview */
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -526,7 +526,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
if (snode->runtime->recalc_auto_compositing) {
snode->runtime->recalc_auto_compositing = false;
snode->runtime->recalc_regular_compositing = false;
- node_render_changed_exec((struct bContext *)C, nullptr);
+ node_render_changed_exec((bContext *)C, nullptr);
}
else if (snode->runtime->recalc_regular_compositing) {
snode->runtime->recalc_regular_compositing = false;
@@ -753,7 +753,7 @@ static void node_header_region_draw(const bContext *C, ARegion *region)
static void node_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
wmGizmoMap *gzmap = region->gizmo_map;
/* context changes */
@@ -973,9 +973,7 @@ static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data)
}
}
-static void node_id_remap(ScrArea *UNUSED(area),
- SpaceLink *slink,
- const struct IDRemapper *mappings)
+static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, const IDRemapper *mappings)
{
/* Although we should be able to perform all the mappings in a single go this lead to issues when
* running the python test cases. Somehow the nodetree/edittree weren't updated to the new
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 97d2957eed2..d29028dad63 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -13,7 +13,6 @@ set(INC
../../sequencer
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -52,6 +51,7 @@ set(SRC
tree/tree_element_id.cc
tree/tree_element_id_library.cc
tree/tree_element_id_scene.cc
+ tree/tree_element_label.cc
tree/tree_element_nla.cc
tree/tree_element_overrides.cc
tree/tree_element_rna.cc
@@ -71,6 +71,7 @@ set(SRC
tree/tree_element_id.hh
tree/tree_element_id_library.hh
tree/tree_element_id_scene.hh
+ tree/tree_element_label.hh
tree/tree_element_nla.hh
tree/tree_element_overrides.hh
tree/tree_element_rna.hh
diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc
index 8ca2ffe6a9c..0ded4654c80 100644
--- a/source/blender/editors/space_outliner/outliner_collections.cc
+++ b/source/blender/editors/space_outliner/outliner_collections.cc
@@ -38,6 +38,8 @@
#include "outliner_intern.hh" /* own include */
+namespace blender::ed::outliner {
+
/* -------------------------------------------------------------------- */
/** \name Utility API
* \{ */
@@ -72,7 +74,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
+ LayerCollection *lc = static_cast<LayerCollection *>(te->directdata);
return lc->collection;
}
if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
@@ -86,9 +88,9 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
return nullptr;
}
-TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
+TreeTraversalAction outliner_collect_selected_collections(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
+ struct IDsSelectedData *data = static_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
@@ -103,9 +105,9 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu
return TRAVERSE_CONTINUE;
}
-TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
+TreeTraversalAction outliner_collect_selected_objects(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
+ struct IDsSelectedData *data = static_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
@@ -122,15 +124,19 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
return TRAVERSE_CONTINUE;
}
+} // namespace blender::ed::outliner
+
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
{
+ using namespace blender::ed::outliner;
+
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
struct IDsSelectedData data = {{nullptr}};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
TSE_SELECTED,
- outliner_find_selected_objects,
+ outliner_collect_selected_objects,
&data);
LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
TreeElement *ten_selected = (TreeElement *)link->data;
@@ -140,12 +146,16 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
BLI_freelistN(&data.selected_array);
}
+namespace blender::ed::outliner {
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Poll Functions
* \{ */
+} // namespace blender::ed::outliner
+
bool ED_outliner_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -153,6 +163,8 @@ bool ED_outliner_collections_editor_poll(bContext *C)
ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
}
+namespace blender::ed::outliner {
+
static bool outliner_view_layer_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -184,7 +196,7 @@ struct CollectionNewData {
static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
{
- struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata);
+ struct CollectionNewData *data = static_cast<CollectionNewData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
@@ -284,9 +296,9 @@ struct CollectionEditData {
bool is_liboverride_hierarchy_root_allowed;
};
-static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
+static TreeTraversalAction collection_collect_data_to_edit(TreeElement *te, void *customdata)
{
- CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
+ CollectionEditData *data = static_cast<CollectionEditData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
@@ -333,13 +345,17 @@ void outliner_collection_delete(
/* We first walk over and find the Collections we actually want to delete
* (ignoring duplicates). */
- outliner_tree_traverse(
- space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
+ outliner_tree_traverse(space_outliner,
+ &space_outliner->tree,
+ 0,
+ TSE_SELECTED,
+ collection_collect_data_to_edit,
+ &data);
/* Effectively delete the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = reinterpret_cast<Collection *>(
+ Collection *collection = static_cast<Collection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
/* Test in case collection got deleted as part of another one. */
@@ -364,7 +380,7 @@ void outliner_collection_delete(
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
BLI_assert(id_type->owner_get != nullptr);
- ID *scene_owner = id_type->owner_get(bmain, &parent->id);
+ ID *scene_owner = id_type->owner_get(&parent->id);
BLI_assert(GS(scene_owner->name) == ID_SCE);
if (ID_IS_LINKED(scene_owner) || ID_IS_OVERRIDE_LIBRARY(scene_owner)) {
skip = true;
@@ -397,7 +413,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- const Base *basact_prev = BASACT(view_layer);
+ const Base *basact_prev = view_layer->basact;
outliner_collection_delete(C, bmain, scene, op->reports, true);
@@ -406,7 +422,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
- if (basact_prev != BASACT(view_layer)) {
+ if (basact_prev != view_layer->basact) {
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
}
@@ -444,12 +460,12 @@ struct CollectionObjectsSelectData {
static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te,
void *customdata)
{
- CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata);
+ CollectionObjectsSelectData *data = static_cast<CollectionObjectsSelectData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
case TSE_LAYER_COLLECTION:
- data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
+ data->layer_collection = static_cast<LayerCollection *>(te->directdata);
return TRAVERSE_BREAK;
case TSE_R_LAYER:
case TSE_SCENE_COLLECTION_BASE:
@@ -538,7 +554,7 @@ struct CollectionDuplicateData {
static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te,
void *customdata)
{
- CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata);
+ CollectionDuplicateData *data = static_cast<CollectionDuplicateData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -597,7 +613,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
BLI_assert(id_type->owner_get != nullptr);
- Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id);
+ Scene *scene_owner = (Scene *)id_type->owner_get(&parent->id);
BLI_assert(scene_owner != nullptr);
BLI_assert(GS(scene_owner->id.name) == ID_SCE);
@@ -695,13 +711,17 @@ static int collection_link_exec(bContext *C, wmOperator *op)
data.collections_to_edit = BLI_gset_ptr_new(__func__);
/* We first walk over and find the Collections we actually want to link (ignoring duplicates). */
- outliner_tree_traverse(
- space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
+ outliner_tree_traverse(space_outliner,
+ &space_outliner->tree,
+ 0,
+ TSE_SELECTED,
+ collection_collect_data_to_edit,
+ &data);
/* Effectively link the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = reinterpret_cast<Collection *>(
+ Collection *collection = static_cast<Collection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_collection_child_add(bmain, active_collection, collection);
id_fake_user_clear(&collection->id);
@@ -754,15 +774,19 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
/* We first walk over and find the Collections we actually want to instance
* (ignoring duplicates). */
- outliner_tree_traverse(
- space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
+ outliner_tree_traverse(space_outliner,
+ &space_outliner->tree,
+ 0,
+ TSE_SELECTED,
+ collection_collect_data_to_edit,
+ &data);
/* Find an active collection to add to, that doesn't give dependency cycles. */
LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = reinterpret_cast<Collection *>(
+ Collection *collection = static_cast<Collection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
while (BKE_collection_cycle_find(active_lc->collection, collection)) {
@@ -772,7 +796,7 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
/* Effectively instance the collections. */
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = reinterpret_cast<Collection *>(
+ Collection *collection = static_cast<Collection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
Object *ob = ED_object_add_type(
C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0);
@@ -812,16 +836,16 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot)
/** \name Exclude Collection
* \{ */
-static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
+static TreeTraversalAction layer_collection_collect_data_to_edit(TreeElement *te, void *customdata)
{
- CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
+ CollectionEditData *data = static_cast<CollectionEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
return TRAVERSE_CONTINUE;
}
- LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
+ LayerCollection *lc = static_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* skip - showing warning/error message might be misleading
@@ -857,12 +881,12 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
&space_outliner->tree,
0,
TSE_SELECTED,
- layer_collection_find_data_to_edit,
+ layer_collection_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ LayerCollection *lc = static_cast<LayerCollection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (clear && (lc->flag & flag)) {
@@ -929,12 +953,12 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- layer_collection_find_data_to_edit,
+ layer_collection_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ LayerCollection *lc = static_cast<LayerCollection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_flag(lc, flag, !clear);
}
@@ -1063,12 +1087,12 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- layer_collection_find_data_to_edit,
+ layer_collection_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (extend) {
@@ -1163,12 +1187,12 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- layer_collection_find_data_to_edit,
+ layer_collection_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside);
}
@@ -1315,11 +1339,11 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- layer_collection_find_data_to_edit,
+ layer_collection_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
Collection *collection = layer_collection->collection;
if (!BKE_id_is_editable(bmain, &collection->id)) {
@@ -1344,11 +1368,11 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- collection_find_data_to_edit,
+ collection_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = reinterpret_cast<Collection *>(
+ Collection *collection = static_cast<Collection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (!BKE_id_is_editable(bmain, &collection->id)) {
continue;
@@ -1449,9 +1473,9 @@ struct OutlinerHideEditData {
/** \name Visibility for Collection & Object Operators
* \{ */
-static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata)
+static TreeTraversalAction outliner_hide_collect_data_to_edit(TreeElement *te, void *customdata)
{
- OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata);
+ OutlinerHideEditData *data = static_cast<OutlinerHideEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (tselem == nullptr) {
@@ -1459,7 +1483,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
+ LayerCollection *lc = static_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* Skip - showing warning/error message might be misleading
@@ -1496,12 +1520,12 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
&space_outliner->tree,
0,
TSE_SELECTED,
- outliner_hide_find_data_to_edit,
+ outliner_hide_collect_data_to_edit,
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(
BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, false, false);
}
@@ -1509,7 +1533,7 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator bases_to_edit_iter;
GSET_ITER (bases_to_edit_iter, data.bases_to_edit) {
- Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter));
+ Base *base = static_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter));
base->flag |= BASE_HIDDEN;
}
BLI_gset_free(data.bases_to_edit, nullptr);
@@ -1542,8 +1566,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Unhide all the collections. */
- LayerCollection *lc_master = reinterpret_cast<LayerCollection *>(
- view_layer->layer_collections.first);
+ LayerCollection *lc_master = static_cast<LayerCollection *>(view_layer->layer_collections.first);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false);
}
@@ -1593,7 +1616,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- outliner_find_selected_collections,
+ outliner_collect_selected_collections,
&selected);
LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) {
@@ -1637,3 +1660,5 @@ void OUTLINER_OT_collection_color_tag_set(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_context.cc b/source/blender/editors/space_outliner/outliner_context.cc
index 1a804cb58b8..001bda57fa2 100644
--- a/source/blender/editors/space_outliner/outliner_context.cc
+++ b/source/blender/editors/space_outliner/outliner_context.cc
@@ -14,7 +14,7 @@
#include "outliner_intern.hh"
#include "tree/tree_iterator.hh"
-using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
static void outliner_context_selected_ids_recursive(const SpaceOutliner &space_outliner,
bContextDataResult *result)
@@ -55,3 +55,5 @@ int /*eContextResult*/ outliner_context(const bContext *C,
return CTX_RESULT_MEMBER_NOT_FOUND;
}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index e20958c1b1e..4a0e00b8bf1 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.cc
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -45,6 +45,8 @@
#include "outliner_intern.hh"
+namespace blender::ed::outliner {
+
static Collection *collection_parent_from_ID(ID *id);
/* -------------------------------------------------------------------- */
@@ -144,7 +146,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return te_hovered;
}
*r_insert_type = TE_INSERT_BEFORE;
- return reinterpret_cast<TreeElement *>(te_hovered->subtree.first);
+ return static_cast<TreeElement *>(te_hovered->subtree.first);
}
*r_insert_type = TE_INSERT_AFTER;
return te_hovered;
@@ -159,8 +161,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Mouse doesn't hover any item (ignoring x-axis),
* so it's either above list bounds or below. */
- TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
- TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last);
+ TreeElement *first = static_cast<TreeElement *>(space_outliner->tree.first);
+ TreeElement *last = static_cast<TreeElement *>(space_outliner->tree.last);
if (view_mval[1] < last->ys) {
*r_insert_type = TE_INSERT_AFTER;
@@ -422,12 +424,12 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
- wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
+ wmDrag *drag = static_cast<wmDrag *>(lb->first);
parent_drop_set_parents(C,
op->reports,
- reinterpret_cast<wmDragID *>(drag->ids.first),
+ static_cast<wmDragID *>(drag->ids.first),
par,
PAR_OBJECT,
event->modifier & KM_ALT);
@@ -505,8 +507,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
return OPERATOR_CANCELLED;
}
- ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
- wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
+ wmDrag *drag = static_cast<wmDrag *>(lb->first);
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
if (GS(drag_id->id->name) == ID_OB) {
@@ -849,7 +851,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
- StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
+ StackDropData *drop_data = static_cast<StackDropData *>(drag->poin);
if (!drop_data) {
return false;
}
@@ -887,7 +889,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C),
const int UNUSED(xy[2]),
struct wmDropBox *UNUSED(drop))
{
- StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
+ StackDropData *drop_data = static_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_REORDER:
return BLI_strdup(TIP_("Reorder"));
@@ -965,14 +967,13 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
case TSE_MODIFIER:
if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
ED_object_gpencil_modifier_copy_to_object(
- ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata));
+ ob_dst, static_cast<GpencilModifierData *>(drop_data->drag_directdata));
}
else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
- ED_object_modifier_copy_to_object(
- C,
- ob_dst,
- drop_data->ob_parent,
- reinterpret_cast<ModifierData *>(drop_data->drag_directdata));
+ ED_object_modifier_copy_to_object(C,
+ ob_dst,
+ drop_data->ob_parent,
+ static_cast<ModifierData *>(drop_data->drag_directdata));
}
break;
case TSE_CONSTRAINT:
@@ -980,12 +981,12 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
ED_object_constraint_copy_for_pose(
bmain,
ob_dst,
- reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata),
- reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
+ static_cast<bPoseChannel *>(drop_data->drop_te->directdata),
+ static_cast<bConstraint *>(drop_data->drag_directdata));
}
else {
ED_object_constraint_copy_for_object(
- bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
+ bmain, ob_dst, static_cast<bConstraint *>(drop_data->drag_directdata));
}
break;
case TSE_GPENCIL_EFFECT: {
@@ -993,8 +994,7 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
return;
}
- ED_object_shaderfx_copy(ob_dst,
- reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata));
+ ED_object_shaderfx_copy(ob_dst, static_cast<ShaderFxData *>(drop_data->drag_directdata));
break;
}
}
@@ -1021,15 +1021,12 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
index = outliner_get_insert_index(
drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
ED_object_gpencil_modifier_move_to_index(
- reports,
- ob,
- reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata),
- index);
+ reports, ob, static_cast<GpencilModifierData *>(drop_data->drag_directdata), index);
}
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
ED_object_modifier_move_to_index(
- reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index);
+ reports, ob, static_cast<ModifierData *>(drop_data->drag_directdata), index);
}
break;
case TSE_CONSTRAINT:
@@ -1041,13 +1038,13 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
}
ED_object_constraint_move_to_index(
- ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index);
+ ob, static_cast<bConstraint *>(drop_data->drag_directdata), index);
break;
case TSE_GPENCIL_EFFECT:
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
ED_object_shaderfx_move_to_index(
- reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index);
+ reports, ob, static_cast<ShaderFxData *>(drop_data->drag_directdata), index);
}
}
@@ -1057,9 +1054,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
- ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
- wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
- StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
+ wmDrag *drag = static_cast<wmDrag *>(lb->first);
+ StackDropData *drop_data = static_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_LINK:
@@ -1124,8 +1121,7 @@ static Collection *collection_parent_from_ID(ID *id)
return nullptr;
}
-static bool collection_drop_init(
- bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data)
+static bool collection_drop_init(bContext *C, wmDrag *drag, const int xy[2], CollectionDrop *data)
{
/* Get collection to drop into. */
TreeElementInsertType insert_type;
@@ -1144,7 +1140,7 @@ static bool collection_drop_init(
return false;
}
- wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first);
+ wmDragID *drag_id = static_cast<wmDragID *>(drag->ids.first);
if (drag_id == nullptr) {
return false;
}
@@ -1157,9 +1153,6 @@ static bool collection_drop_init(
/* Get collection to drag out of. */
ID *parent = drag_id->from_parent;
Collection *from_collection = collection_parent_from_ID(parent);
- if (is_link) {
- from_collection = nullptr;
- }
/* Currently this should not be allowed, cannot edit items in an override of a Collection. */
if (from_collection != nullptr && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
@@ -1197,29 +1190,22 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
- if (((event->modifier & KM_SHIFT) == 0) &&
- collection_drop_init(C, drag, event->xy, event->modifier & KM_CTRL, &data)) {
+ if (((event->modifier & KM_SHIFT) == 0) && collection_drop_init(C, drag, event->xy, &data)) {
TreeElement *te = data.te;
TreeStoreElem *tselem = TREESTORE(te);
- if (!data.from || event->modifier & KM_CTRL) {
- tselem->flag |= TSE_DRAG_INTO;
- changed = true;
- }
- else {
- switch (data.insert_type) {
- case TE_INSERT_BEFORE:
- tselem->flag |= TSE_DRAG_BEFORE;
- changed = true;
- break;
- case TE_INSERT_AFTER:
- tselem->flag |= TSE_DRAG_AFTER;
- changed = true;
- break;
- case TE_INSERT_INTO: {
- tselem->flag |= TSE_DRAG_INTO;
- changed = true;
- break;
- }
+ switch (data.insert_type) {
+ case TE_INSERT_BEFORE:
+ tselem->flag |= TSE_DRAG_BEFORE;
+ changed = true;
+ break;
+ case TE_INSERT_AFTER:
+ tselem->flag |= TSE_DRAG_AFTER;
+ changed = true;
+ break;
+ case TE_INSERT_INTO: {
+ tselem->flag |= TSE_DRAG_INTO;
+ changed = true;
+ break;
}
}
if (changed) {
@@ -1242,30 +1228,49 @@ static char *collection_drop_tooltip(bContext *C,
const wmEvent *event = win ? win->eventstate : nullptr;
CollectionDrop data;
- if (event && ((event->modifier & KM_SHIFT) == 0) &&
- collection_drop_init(C, drag, xy, event->modifier & KM_CTRL, &data)) {
- TreeElement *te = data.te;
- if (!data.from || event->modifier & KM_CTRL) {
- return BLI_strdup(TIP_("Link inside Collection"));
+ if (event && ((event->modifier & KM_SHIFT) == 0) && collection_drop_init(C, drag, xy, &data)) {
+ const bool is_link = !data.from || (event->modifier & KM_CTRL);
+
+ /* Test if we are moving within same parent collection. */
+ bool same_level = false;
+ LISTBASE_FOREACH (CollectionParent *, parent, &data.to->parents) {
+ if (data.from == parent->collection) {
+ same_level = true;
+ }
}
+
+ /* Tooltips when not moving directly into another collection i.e. mouse on border of
+ * collections. Later we will decide which tooltip to return. */
+ const bool tooltip_link = (is_link && !same_level);
+ const char *tooltip_before = tooltip_link ? TIP_("Link before collection") :
+ TIP_("Move before collection");
+ const char *tooltip_between = tooltip_link ? TIP_("Link between collections") :
+ TIP_("Move between collections");
+ const char *tooltip_after = tooltip_link ? TIP_("Link after collection") :
+ TIP_("Move after collection");
+
+ TreeElement *te = data.te;
switch (data.insert_type) {
case TE_INSERT_BEFORE:
if (te->prev && outliner_is_collection_tree_element(te->prev)) {
- return BLI_strdup(TIP_("Move between collections"));
+ return BLI_strdup(tooltip_between);
}
else {
- return BLI_strdup(TIP_("Move before collection"));
+ return BLI_strdup(tooltip_before);
}
break;
case TE_INSERT_AFTER:
if (te->next && outliner_is_collection_tree_element(te->next)) {
- return BLI_strdup(TIP_("Move between collections"));
+ return BLI_strdup(tooltip_between);
}
else {
- return BLI_strdup(TIP_("Move after collection"));
+ return BLI_strdup(tooltip_after);
}
break;
case TE_INSERT_INTO: {
+ if (is_link) {
+ return BLI_strdup(TIP_("Link inside collection"));
+ }
/* Check the type of the drag IDs to avoid the incorrect "Shift to parent"
* for collections. Checking the type of the first ID works fine here since
@@ -1292,11 +1297,11 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
return OPERATOR_CANCELLED;
}
- ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
- wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
+ wmDrag *drag = static_cast<wmDrag *>(lb->first);
CollectionDrop data;
- if (!collection_drop_init(C, drag, event->xy, event->modifier & KM_CTRL, &data)) {
+ if (!collection_drop_init(C, drag, event->xy, &data)) {
return OPERATOR_CANCELLED;
}
@@ -1447,7 +1452,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
TSE_GPENCIL_EFFECT_BASE);
const int wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID;
- wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
+ wmDrag *drag = WM_drag_data_create(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
if (use_datastack_drag) {
TreeElement *te_bone = nullptr;
@@ -1471,7 +1476,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
&space_outliner->tree,
0,
TSE_SELECTED,
- outliner_find_selected_objects,
+ outliner_collect_selected_objects,
&selected);
}
else {
@@ -1479,7 +1484,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
&space_outliner->tree,
0,
TSE_SELECTED,
- outliner_find_selected_collections,
+ outliner_collect_selected_collections,
&selected);
}
@@ -1537,6 +1542,8 @@ static int outliner_item_drag_drop_invoke(bContext *C,
WM_drag_add_local_ID(drag, data.drag_id, data.drag_parent);
}
+ WM_event_start_prepared_drag(C, drag);
+
ED_outliner_select_sync_from_outliner(C, space_outliner);
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
@@ -1587,3 +1594,5 @@ void outliner_dropboxes(void)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index 753de83a10d..3f99b19cd16 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -37,6 +37,7 @@
#include "BKE_lib_override.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_main_namemap.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -73,8 +74,7 @@
#include "tree/tree_element_rna.hh"
#include "tree/tree_iterator.hh"
-using namespace blender;
-using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
/* -------------------------------------------------------------------- */
/** \name Tree Size Functions
@@ -276,8 +276,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
Object *ob_parent = ob ? ob : base->object;
- for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter;
- ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) {
+ for (Object *ob_iter = static_cast<Object *>(bmain->objects.first); ob_iter;
+ ob_iter = static_cast<Object *>(ob_iter->id.next)) {
if (BKE_object_is_child_recursive(ob_parent, ob_iter)) {
if (ob) {
RNA_id_pointer_create(&ob_iter->id, &ptr);
@@ -311,8 +311,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
*/
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Object *ob = reinterpret_cast<Object *>(poin);
- char *propname = reinterpret_cast<char *>(poin2);
+ Object *ob = static_cast<Object *>(poin);
+ char *propname = static_cast<char *>(poin2);
outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
}
@@ -321,8 +321,8 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void
*/
static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Base *base = reinterpret_cast<Base *>(poin);
- char *propname = reinterpret_cast<char *>(poin2);
+ Base *base = static_cast<Base *>(poin);
+ char *propname = static_cast<char *>(poin2);
outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
}
@@ -487,7 +487,7 @@ void outliner_collection_isolate_flag(Scene *scene,
const bool is_hide = strstr(propname, "hide_") != nullptr;
LayerCollection *top_layer_collection = layer_collection ?
- reinterpret_cast<LayerCollection *>(
+ static_cast<LayerCollection *>(
view_layer->layer_collections.first) :
nullptr;
Collection *top_collection = collection ? scene->master_collection : nullptr;
@@ -558,7 +558,7 @@ void outliner_collection_isolate_flag(Scene *scene,
else {
CollectionParent *parent;
Collection *child = collection;
- while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) {
+ while ((parent = static_cast<CollectionParent *>(child->parents.first))) {
if (parent->collection->flag & COLLECTION_IS_MASTER) {
break;
}
@@ -637,8 +637,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
void *poin,
void *poin2)
{
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
- char *propname = reinterpret_cast<char *>(poin2);
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
+ char *propname = static_cast<char *>(poin2);
outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
}
@@ -648,8 +648,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
*/
static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
- char *propname = reinterpret_cast<char *>(poin2);
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
+ char *propname = static_cast<char *>(poin2);
outliner_collection_set_flag_recursive_fn(
C, layer_collection, layer_collection->collection, propname);
}
@@ -660,8 +660,8 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin
*/
static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Collection *collection = reinterpret_cast<Collection *>(poin);
- char *propname = reinterpret_cast<char *>(poin2);
+ Collection *collection = static_cast<Collection *>(poin);
+ char *propname = static_cast<char *>(poin2);
outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
}
@@ -671,12 +671,13 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
BLI_mempool *ts = space_outliner->treestore;
- TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep);
+ TreeStoreElem *tselem = static_cast<TreeStoreElem *>(tsep);
if (ts && tselem) {
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
if (tselem->type == TSE_SOME_ID) {
+ BKE_main_namemap_remove_name(bmain, tselem->id, oldname);
BLI_libblock_ensure_unique_name(bmain, tselem->id->name);
WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
@@ -699,7 +700,6 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
if (ob->type == OB_MBALL) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
break;
}
default:
@@ -730,26 +730,31 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
lib->id.tag &= ~LIB_TAG_MISSING;
}
}
+
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
}
else {
switch (tselem->type) {
case TSE_DEFGROUP: {
Object *ob = (Object *)tselem->id;
- bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata);
+ bDeformGroup *vg = static_cast<bDeformGroup *>(te->directdata);
BKE_object_defgroup_unique_name(vg, ob);
WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_NLA_ACTION: {
bAction *act = (bAction *)tselem->id;
+ BKE_main_namemap_remove_name(bmain, &act->id, oldname);
BLI_libblock_ensure_unique_name(bmain, act->id.name);
WM_msg_publish_rna_prop(mbus, &act->id, &act->id, ID, name);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
if (arm->edbo) {
- EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
+ EditBone *ebone = static_cast<EditBone *>(te->directdata);
char newname[sizeof(ebone->name)];
/* restore bone name */
@@ -758,6 +763,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
}
break;
}
@@ -767,7 +773,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
outliner_viewcontext_init(C, &tvc);
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = reinterpret_cast<Bone *>(te->directdata);
+ Bone *bone = static_cast<Bone *>(te->directdata);
char newname[sizeof(bone->name)];
/* always make current object active */
@@ -779,6 +785,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_POSE_CHANNEL: {
@@ -787,7 +794,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id;
bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
@@ -798,15 +805,16 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
- ED_armature_bone_rename(
- bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname);
+ ED_armature_bone_rename(bmain, static_cast<bArmature *>(ob->data), oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id; /* id = object. */
- bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata);
+ bActionGroup *grp = static_cast<bActionGroup *>(te->directdata);
BLI_uniquename(&ob->pose->agroups,
grp,
@@ -816,11 +824,12 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
sizeof(grp->name));
WM_msg_publish_rna_prop(mbus, &ob->id, grp, ActionGroup, name);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_GP_LAYER: {
bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
- bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
+ bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
/* always make layer active */
BKE_gpencil_layer_active_set(gpd, gpl);
@@ -832,11 +841,12 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
WM_msg_publish_rna_prop(mbus, &gpd->id, gpl, GPencilLayer, info);
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_R_LAYER: {
Scene *scene = (Scene *)tselem->id;
- ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
+ ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
/* Restore old name. */
char newname[sizeof(view_layer->name)];
@@ -847,14 +857,17 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BKE_view_layer_rename(bmain, scene, view_layer, newname);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
case TSE_LAYER_COLLECTION: {
/* The ID is a #Collection, not a #LayerCollection */
Collection *collection = (Collection *)tselem->id;
+ BKE_main_namemap_remove_name(bmain, &collection->id, oldname);
BLI_libblock_ensure_unique_name(bmain, collection->id.name);
WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name);
WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
+ DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE);
break;
}
}
@@ -987,7 +1000,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
{
TreeStoreElem *tselem = TREESTORE(te);
LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
- reinterpret_cast<LayerCollection *>(te->directdata) :
+ static_cast<LayerCollection *>(te->directdata) :
nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
@@ -1101,7 +1114,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
/* View layer render toggle. */
- ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata);
+ ViewLayer *layer = static_cast<ViewLayer *>(te->directdata);
bt = uiDefIconButBitS(block,
UI_BTYPE_ICON_TOGGLE_N,
@@ -1325,7 +1338,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
@@ -1475,8 +1488,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) {
LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
- reinterpret_cast<LayerCollection *>(
- te->directdata) :
+ static_cast<LayerCollection *>(te->directdata) :
nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
@@ -1802,18 +1814,17 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
if (!outliner_is_element_in_view(te, &region->v2d)) {
continue;
}
- if (tselem->type != TSE_LIBRARY_OVERRIDE) {
+ TreeElementOverridesProperty *override_elem = tree_element_cast<TreeElementOverridesProperty>(
+ te);
+ if (!override_elem) {
continue;
}
- TreeElementOverridesProperty &override_elem = *tree_element_cast<TreeElementOverridesProperty>(
- te);
-
- if (!override_elem.is_rna_path_valid) {
+ if (!override_elem->is_rna_path_valid) {
uiBut *but = uiDefBut(block,
UI_BTYPE_LABEL,
0,
- override_elem.rna_path.c_str(),
+ override_elem->rna_path.c_str(),
x + pad_x,
te->ys + pad_y,
item_max_width,
@@ -1828,8 +1839,28 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
continue;
}
- PointerRNA *ptr = &override_elem.override_rna_ptr;
- PropertyRNA *prop = &override_elem.override_rna_prop;
+ if (const TreeElementOverridesPropertyOperation *override_op_elem =
+ tree_element_cast<TreeElementOverridesPropertyOperation>(te)) {
+ StringRefNull op_label = override_op_elem->getOverrideOperationLabel();
+ uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ op_label.c_str(),
+ x + pad_x,
+ te->ys + pad_y,
+ item_max_width,
+ item_height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ continue;
+ }
+
+ PointerRNA *ptr = &override_elem->override_rna_ptr;
+ PropertyRNA *prop = &override_elem->override_rna_prop;
const PropertyType prop_type = RNA_property_type(prop);
uiBut *auto_but = uiDefAutoButR(block,
@@ -1927,7 +1958,7 @@ static void outliner_draw_separator(ARegion *region, const int x)
GPU_line_width(1.0f);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
immBegin(GPU_PRIM_LINES, 2);
@@ -2495,7 +2526,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
break;
case TSE_CONSTRAINT: {
- bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata);
+ bConstraint *con = static_cast<bConstraint *>(te->directdata);
data.drag_id = tselem->id;
switch ((eBConstraint_Types)con->type) {
case CONSTRAINT_TYPE_CAMERASOLVER:
@@ -2612,9 +2643,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
if (ob->type != OB_GPENCIL) {
- ModifierData *md = reinterpret_cast<ModifierData *>(
- BLI_findlink(&ob->modifiers, tselem->nr));
- const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>(
+ ModifierData *md = static_cast<ModifierData *>(BLI_findlink(&ob->modifiers, tselem->nr));
+ const ModifierTypeInfo *modifier_type = static_cast<const ModifierTypeInfo *>(
BKE_modifier_get_info((ModifierType)md->type));
if (modifier_type != nullptr) {
data.icon = modifier_type->icon;
@@ -2625,7 +2655,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else {
/* grease pencil modifiers */
- GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>(
+ GpencilModifierData *md = static_cast<GpencilModifierData *>(
BLI_findlink(&ob->greasepencil_modifiers, tselem->nr));
switch ((GpencilModifierType)md->type) {
case eGpencilModifierType_Noise:
@@ -2784,7 +2814,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
const PointerRNA &ptr = te_rna_struct->getPointerRNA();
if (RNA_struct_is_ID(ptr.type)) {
- data.drag_id = reinterpret_cast<ID *>(ptr.data);
+ data.drag_id = static_cast<ID *>(ptr.data);
data.icon = RNA_struct_ui_icon(ptr.type);
}
else {
@@ -2824,10 +2854,20 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.icon = tree_element_get_icon_from_id(tselem->id);
}
+ if (!te->abstract_element) {
+ /* Pass */
+ }
+ else if (auto icon = te->abstract_element->getIcon()) {
+ data.icon = *icon;
+ }
+
return data;
}
-static void tselem_draw_icon(uiBlock *block,
+/**
+ * \return true if the element has an icon that was drawn, false if it doesn't have an icon.
+ */
+static bool tselem_draw_icon(uiBlock *block,
int xmax,
float x,
float y,
@@ -2838,7 +2878,7 @@ static void tselem_draw_icon(uiBlock *block,
{
TreeElementIcon data = tree_element_get_icon(tselem, te);
if (data.icon == 0) {
- return;
+ return false;
}
const bool is_collection = outliner_is_collection_tree_element(te);
@@ -2862,7 +2902,7 @@ static void tselem_draw_icon(uiBlock *block,
0.0f,
btheme->collection_color[collection->color_tag].color,
true);
- return;
+ return true;
}
}
@@ -2894,6 +2934,8 @@ static void tselem_draw_icon(uiBlock *block,
alpha,
(data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->filepath : "");
}
+
+ return true;
}
/**
@@ -3088,6 +3130,7 @@ static void outliner_draw_iconrow(bContext *C,
TSE_GP_LAYER,
TSE_LIBRARY_OVERRIDE_BASE,
TSE_LIBRARY_OVERRIDE,
+ TSE_LIBRARY_OVERRIDE_OPERATION,
TSE_BONE,
TSE_EBONE,
TSE_POSE_CHANNEL,
@@ -3292,7 +3335,7 @@ static void outliner_draw_tree_element(bContext *C,
/* Scene collection in view layer can't expand/collapse. */
}
else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) ||
- (te->flag & TE_LAZY_CLOSED)) {
+ (te->flag & TE_PRETEND_HAS_CHILDREN)) {
/* Open/close icon, only when sub-levels, except for scene. */
int icon_x = startx;
@@ -3313,15 +3356,15 @@ static void outliner_draw_tree_element(bContext *C,
offsx += UI_UNIT_X;
/* Data-type icon. */
- if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) {
- tselem_draw_icon(block,
- xmax,
- (float)startx + offsx,
- (float)*starty,
- tselem,
- te,
- (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
- true);
+ if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) &&
+ tselem_draw_icon(block,
+ xmax,
+ (float)startx + offsx,
+ (float)*starty,
+ tselem,
+ te,
+ (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
+ true)) {
offsx += UI_UNIT_X + 4 * ufac;
}
else {
@@ -3508,7 +3551,7 @@ static void outliner_draw_hierarchy_lines(SpaceOutliner *space_outliner,
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uchar col[4];
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -3539,7 +3582,7 @@ static void outliner_draw_struct_marks(ARegion *region,
if (tselem->type == TSE_RNA_STRUCT) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immThemeColorShadeAlpha(TH_BACK, -15, -200);
immRecti(pos, 0, *starty + 1, (int)region->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
immUnbindProgram();
@@ -3552,7 +3595,7 @@ static void outliner_draw_struct_marks(ARegion *region,
if (tselem->type == TSE_RNA_STRUCT) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immThemeColorShadeAlpha(TH_BACK, -15, -200);
immBegin(GPU_PRIM_LINES, 2);
@@ -3657,7 +3700,7 @@ static void outliner_draw_highlights(ARegion *region,
GPU_blend(GPU_BLEND_ALPHA);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
outliner_draw_highlights(pos,
region,
space_outliner,
@@ -3758,7 +3801,7 @@ static void outliner_back(ARegion *region)
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float col_alternating[4];
UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating);
@@ -3950,3 +3993,5 @@ void draw_outliner(const bContext *C)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index c4a9398a5f7..8618c2999c2 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -29,6 +29,7 @@
#include "BKE_blender_copybuffer.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_query.h"
@@ -55,6 +56,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "RNA_path.h"
#include "GPU_material.h"
@@ -64,6 +66,8 @@
using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
+
static void outliner_show_active(SpaceOutliner *space_outliner,
ARegion *region,
TreeElement *te,
@@ -143,14 +147,10 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
/** \name Toggle Open/Closed Operator
* \{ */
-void outliner_item_openclose(SpaceOutliner *space_outliner,
- TreeElement *te,
- bool open,
- bool toggle_all)
+void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
{
- /* Prevent opening leaf elements in the tree unless in the Data API display mode because in that
- * mode subtrees are empty unless expanded. */
- if (space_outliner->outlinevis != SO_DATA_API && BLI_listbase_is_empty(&te->subtree)) {
+ /* Only allow opening elements with children. */
+ if (!(te->flag & TE_PRETEND_HAS_CHILDREN) && BLI_listbase_is_empty(&te->subtree)) {
return;
}
@@ -197,7 +197,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv
/* Only toggle openclose on the same level as the first clicked element */
if (te->xs == data->x_location) {
- outliner_item_openclose(space_outliner, te, data->open, false);
+ outliner_item_openclose(te, data->open, false);
outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region);
}
@@ -241,7 +241,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE
const bool open = (tselem->flag & TSE_CLOSED) ||
(toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)));
- outliner_item_openclose(space_outliner, te, open, toggle_all);
+ outliner_item_openclose(te, open, toggle_all);
outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region);
/* Only toggle once for single click toggling */
@@ -447,7 +447,7 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
/** \name ID Delete Operator
* \{ */
-static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
+static void id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
@@ -484,35 +484,39 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
return;
}
if (te->idcode == ID_WS) {
- BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
- if (id->tag & LIB_TAG_DOIT) {
+ BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_PRE_EXISTING);
+ if (id->tag & LIB_TAG_PRE_EXISTING) {
BKE_reportf(
reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
+ BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
return;
}
+ BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
}
- BKE_id_delete(bmain, id);
+ id->tag |= LIB_TAG_DOIT;
WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
-void id_delete_fn(bContext *C,
- ReportList *reports,
- Scene *UNUSED(scene),
- TreeElement *te,
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+void id_delete_tag_fn(bContext *C,
+ ReportList *reports,
+ Scene *UNUSED(scene),
+ TreeElement *te,
+ TreeStoreElem *UNUSED(tsep),
+ TreeStoreElem *tselem,
+ void *UNUSED(user_data))
{
- id_delete(C, reports, te, tselem);
+ id_delete_tag(C, reports, te, tselem);
}
-static int outliner_id_delete_invoke_do(bContext *C,
- ReportList *reports,
- TreeElement *te,
- const float mval[2])
+static int outliner_id_delete_tag(bContext *C,
+ ReportList *reports,
+ TreeElement *te,
+ const float mval[2])
{
+ int id_tagged_num = 0;
+
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -522,26 +526,27 @@ static int outliner_id_delete_invoke_do(bContext *C,
RPT_ERROR_INVALID_INPUT,
"Cannot delete indirectly linked library '%s'",
((Library *)tselem->id)->filepath_abs);
- return OPERATOR_CANCELLED;
}
- id_delete(C, reports, te, tselem);
- return OPERATOR_FINISHED;
+ else {
+ id_delete_tag(C, reports, te, tselem);
+ id_tagged_num++;
+ }
}
}
else {
LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
- int ret;
- if ((ret = outliner_id_delete_invoke_do(C, reports, te_sub, mval))) {
- return ret;
+ if ((id_tagged_num += outliner_id_delete_tag(C, reports, te_sub, mval)) != 0) {
+ break;
}
}
}
- return 0;
+ return id_tagged_num;
}
static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Main *bmain = CTX_data_main(C);
ARegion *region = CTX_wm_region(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
float fmval[2];
@@ -550,15 +555,21 @@ static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+ int id_tagged_num = 0;
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
- int ret;
-
- if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
- return ret;
+ if ((id_tagged_num += outliner_id_delete_tag(C, op->reports, te, fmval)) != 0) {
+ break;
}
}
+ if (id_tagged_num == 0) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ return OPERATOR_CANCELLED;
+ }
- return OPERATOR_CANCELLED;
+ BKE_id_multi_tagged_delete(bmain);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ return OPERATOR_FINISHED;
}
void OUTLINER_OT_id_delete(wmOperatorType *ot)
@@ -586,9 +597,9 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
- ID *old_id = reinterpret_cast<ID *>(
+ ID *old_id = static_cast<ID *>(
BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
- ID *new_id = reinterpret_cast<ID *>(
+ ID *new_id = static_cast<ID *>(
BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
/* check for invalid states */
@@ -682,9 +693,9 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C,
int i = 0;
short id_type = (short)RNA_enum_get(ptr, "id_type");
- ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
+ ID *id = static_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
- for (; id; id = reinterpret_cast<ID *>(id->next)) {
+ for (; id; id = static_cast<ID *>(id->next)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
@@ -1255,7 +1266,7 @@ static TreeElement *outliner_show_active_get_element(bContext *C,
{
TreeElement *te;
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
if (!obact) {
return nullptr;
@@ -1398,129 +1409,6 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
/** \} */
-#if 0 /* TODO: probably obsolete now with filtering? */
-
-/* -------------------------------------------------------------------- */
-/** \name Search
- * \{ */
-
-
-/* find next element that has this name */
-static TreeElement *outliner_find_name(
- SpaceOutliner *space_outliner, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound)
-{
- TreeElement *te, *tes;
-
- for (te = lb->first; te; te = te->next) {
- int found = outliner_filter_has_name(te, name, flags);
-
- if (found) {
- /* name is right, but is element the previous one? */
- if (prev) {
- if ((te != prev) && (*prevFound)) {
- return te;
- }
- if (te == prev) {
- *prevFound = 1;
- }
- }
- else {
- return te;
- }
- }
-
- tes = outliner_find_name(space_outliner, &te->subtree, name, flags, prev, prevFound);
- if (tes) {
- return tes;
- }
- }
-
- /* nothing valid found */
- return nullptr;
-}
-
-static void outliner_find_panel(
- Scene *UNUSED(scene), ARegion *region, SpaceOutliner *space_outliner, int again, int flags)
-{
- ReportList *reports = nullptr; /* CTX_wm_reports(C); */
- TreeElement *te = nullptr;
- TreeElement *last_find;
- TreeStoreElem *tselem;
- int ytop, xdelta, prevFound = 0;
- char name[sizeof(space_outliner->search_string)];
-
- /* get last found tree-element based on stored search_tse */
- last_find = outliner_find_tse(space_outliner, &space_outliner->search_tse);
-
- /* determine which type of search to do */
- if (again && last_find) {
- /* no popup panel - previous + user wanted to search for next after previous */
- BLI_strncpy(name, space_outliner->search_string, sizeof(name));
- flags = space_outliner->search_flags;
-
- /* try to find matching element */
- te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
- if (te == nullptr) {
- /* no more matches after previous, start from beginning again */
- prevFound = 1;
- te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
- }
- }
- else {
- /* pop up panel - no previous, or user didn't want search after previous */
- name[0] = '\0';
- // XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
- // te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, nullptr, &prevFound);
- // }
- // else return; XXX RETURN! XXX
- }
-
- /* do selection and reveal */
- if (te) {
- tselem = TREESTORE(te);
- if (tselem) {
- /* expand branches so that it will be visible, we need to get correct coordinates */
- if (outliner_open_back(space_outliner, te)) {
- outliner_set_coordinates(region, space_outliner);
- }
-
- /* deselect all visible, and select found element */
- outliner_flag_set(space_outliner, &space_outliner->tree, TSE_SELECTED, 0);
- tselem->flag |= TSE_SELECTED;
-
- /* Make `te->ys` center of view. */
- ytop = (int)(te->ys + BLI_rctf_size_y(&region->v2d.mask) / 2);
- if (ytop > 0) {
- ytop = 0;
- }
- region->v2d.cur.ymax = (float)ytop;
- region->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&region->v2d.mask));
-
- /* Make `te->xs` ==> `te->xend` center of view. */
- xdelta = (int)(te->xs - region->v2d.cur.xmin);
- region->v2d.cur.xmin += xdelta;
- region->v2d.cur.xmax += xdelta;
-
- /* store selection */
- space_outliner->search_tse = *tselem;
-
- BLI_strncpy(space_outliner->search_string, name, sizeof(space_outliner->search_string));
- space_outliner->search_flags = flags;
-
- /* redraw */
- ED_region_tag_redraw_no_rebuild(region);
- }
- }
- else {
- /* no tree-element found */
- BKE_reportf(reports, RPT_WARNING, "Not found: %s", name);
- }
-}
-
-/** \} */
-
-#endif /* if 0 */
-
/* -------------------------------------------------------------------- */
/** \name Show One Level Operator
* \{ */
@@ -1806,7 +1694,7 @@ static void tree_element_to_path(TreeElement *te,
/* ptr->data not ptr->owner_id seems to be the one we want,
* since ptr->data is sometimes the owner of this ID? */
if (RNA_struct_is_ID(ptr.type)) {
- *id = reinterpret_cast<ID *>(ptr.data);
+ *id = static_cast<ID *>(ptr.data);
/* clear path */
if (*path) {
@@ -2041,8 +1929,7 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add)
/* try to find one from scene */
if (scene->active_keyingset > 0) {
- ks = reinterpret_cast<KeyingSet *>(
- BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
+ ks = static_cast<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
}
/* Add if none found */
@@ -2346,3 +2233,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index a0dcb49aa43..ad5d653949c 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -14,10 +14,6 @@
/* Needed for `tree_element_cast()`. */
#include "tree/tree_element.hh"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* internal exports only */
struct ARegion;
@@ -27,7 +23,6 @@ struct ListBase;
struct Main;
struct Object;
struct Scene;
-struct TreeElement;
struct TreeStoreElem;
struct ViewLayer;
struct bContext;
@@ -37,47 +32,52 @@ struct View2D;
struct wmKeyConfig;
struct wmOperatorType;
+namespace blender::bke::outliner::treehash {
+class TreeHash;
+}
+
namespace blender::ed::outliner {
+
class AbstractTreeDisplay;
class AbstractTreeElement;
-} // namespace blender::ed::outliner
-namespace outliner = blender::ed::outliner;
+namespace treehash = blender::bke::outliner::treehash;
+
+struct TreeElement;
struct SpaceOutliner_Runtime {
/** Object to create and manage the tree for a specific display type (View Layers, Scenes,
* Blender File, etc.). */
- std::unique_ptr<outliner::AbstractTreeDisplay> tree_display;
+ std::unique_ptr<AbstractTreeDisplay> tree_display;
- /** Pointers to tree-store elements, grouped by `(id, type, nr)`
- * in hash-table for faster searching. */
- struct GHash *treehash;
+ /* Hash table for tree-store elements, using `(id, type, index)` as key. */
+ std::unique_ptr<treehash::TreeHash> tree_hash;
SpaceOutliner_Runtime() = default;
/** Used for copying runtime data to a duplicated space. */
SpaceOutliner_Runtime(const SpaceOutliner_Runtime &);
- ~SpaceOutliner_Runtime();
+ ~SpaceOutliner_Runtime() = default;
};
-typedef enum TreeElementInsertType {
+enum TreeElementInsertType {
TE_INSERT_BEFORE,
TE_INSERT_AFTER,
TE_INSERT_INTO,
-} TreeElementInsertType;
+};
-typedef enum TreeTraversalAction {
+enum TreeTraversalAction {
/** Continue traversal regularly, don't skip children. */
TRAVERSE_CONTINUE = 0,
/** Stop traversal. */
TRAVERSE_BREAK,
/** Continue traversal, but skip children of traversed element. */
TRAVERSE_SKIP_CHILDS,
-} TreeTraversalAction;
+};
-typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata);
+typedef TreeTraversalAction (*TreeTraversalFunc)(TreeElement *te, void *customdata);
-typedef struct TreeElement {
- struct TreeElement *next, *prev, *parent;
+struct TreeElement {
+ TreeElement *next, *prev, *parent;
/**
* The new inheritance based representation of the element (a derived type of base
@@ -85,7 +85,7 @@ typedef struct TreeElement {
* be moved to it and operations based on the type should become virtual methods of the class
* hierarchy.
*/
- std::unique_ptr<outliner::AbstractTreeElement> abstract_element;
+ std::unique_ptr<AbstractTreeElement> abstract_element;
ListBase subtree;
int xs, ys; /* Do selection. */
@@ -96,12 +96,12 @@ typedef struct TreeElement {
short xend; /* Width of item display, for select. */
const char *name;
void *directdata; /* Armature Bones, Base, ... */
-} TreeElement;
+};
-typedef struct TreeElementIcon {
+struct TreeElementIcon {
struct ID *drag_id, *drag_parent;
int icon;
-} TreeElementIcon;
+};
#define TREESTORE_ID_TYPE(_id) \
(ELEM(GS((_id)->name), \
@@ -153,7 +153,10 @@ enum {
/* Closed items display their children as icon within the row. TE_ICONROW is for
* these child-items that are visible but only within the row of the closed parent. */
TE_ICONROW = (1 << 1),
- TE_LAZY_CLOSED = (1 << 2),
+ /** Treat the element as if it had children, e.g. draw an icon to un-collapse it, even if it
+ * doesn't. Used where children are lazy-built only if the parent isn't collapsed (see
+ * #AbstractTreeDisplay::is_lazy_built()). */
+ TE_PRETEND_HAS_CHILDREN = (1 << 2),
TE_FREE_NAME = (1 << 3),
TE_DRAGGING = (1 << 4),
TE_CHILD_NOT_IN_COLLECTION = (1 << 6),
@@ -165,17 +168,17 @@ enum {
/* button events */
#define OL_NAMEBUTTON 1
-typedef enum {
+enum eOLDrawState {
OL_DRAWSEL_NONE = 0, /* inactive (regular black text) */
OL_DRAWSEL_NORMAL = 1, /* active object (draws white text) */
OL_DRAWSEL_ACTIVE = 2, /* active obdata (draws a circle around the icon) */
-} eOLDrawState;
+};
-typedef enum {
+enum eOLSetState {
OL_SETSEL_NONE = 0, /* don't change the selection state */
OL_SETSEL_NORMAL = 1, /* select the item */
OL_SETSEL_EXTEND = 2, /* select the item and extend (also toggles selection) */
-} eOLSetState;
+};
/* get TreeStoreElem associated with a TreeElement
* < a: (TreeElement) tree element to find stored element for
@@ -225,29 +228,29 @@ typedef enum {
* Container to avoid passing around these variables to many functions.
* Also so we can have one place to assign these variables.
*/
-typedef struct TreeViewContext {
+struct TreeViewContext {
/* Scene level. */
struct Scene *scene;
struct ViewLayer *view_layer;
/* Object level. */
- /** Avoid OBACT macro everywhere. */
+ /** Avoid `BKE_view_layer_active_object_get` everywhere. */
Object *obact;
Object *ob_edit;
/**
* The pose object may not be the active object (when in weight paint mode).
* Checking this in draw loops isn't efficient, so set only once. */
Object *ob_pose;
-} TreeViewContext;
+};
-typedef enum TreeItemSelectAction {
+enum TreeItemSelectAction {
OL_ITEM_DESELECT = 0, /* Deselect the item */
OL_ITEM_SELECT = (1 << 0), /* Select the item */
OL_ITEM_SELECT_DATA = (1 << 1), /* Select object data */
OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */
OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */
OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */
-} TreeItemSelectAction;
+};
/* outliner_tree.c ----------------------------------------------- */
@@ -270,24 +273,19 @@ void outliner_build_tree(struct Main *mainvar,
struct SpaceOutliner *space_outliner,
struct ARegion *region);
-struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- struct Collection *collection,
- TreeElement *ten);
+TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ struct Collection *collection,
+ TreeElement *ten);
bool outliner_requires_rebuild_on_select_or_active_change(
const struct SpaceOutliner *space_outliner);
-/**
- * Check if a display mode needs a full rebuild if the open/collapsed state changes.
- * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
- */
-bool outliner_requires_rebuild_on_open_change(const struct SpaceOutliner *space_outliner);
typedef struct IDsSelectedData {
struct ListBase selected_array;
} IDsSelectedData;
-TreeTraversalAction outliner_find_selected_collections(struct TreeElement *te, void *customdata);
-TreeTraversalAction outliner_find_selected_objects(struct TreeElement *te, void *customdata);
+TreeTraversalAction outliner_collect_selected_collections(TreeElement *te, void *customdata);
+TreeTraversalAction outliner_collect_selected_objects(TreeElement *te, void *customdata);
/* outliner_draw.c ---------------------------------------------- */
@@ -349,7 +347,7 @@ struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_
*/
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
- struct TreeElement *te,
+ TreeElement *te,
short select_flag);
/**
@@ -379,7 +377,7 @@ void outliner_item_mode_toggle(struct bContext *C,
typedef void (*outliner_operation_fn)(struct bContext *C,
struct ReportList *,
struct Scene *scene,
- struct TreeElement *,
+ TreeElement *,
struct TreeStoreElem *,
TreeStoreElem *,
void *);
@@ -408,12 +406,10 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel);
* Set or unset \a flag for all outliner elements in \a lb and sub-trees.
* \return if any flag was modified.
*/
-extern "C++" {
bool outliner_flag_set(const SpaceOutliner &space_outliner, short flag, short set);
bool outliner_flag_set(const ListBase &lb, short flag, short set);
bool outliner_flag_flip(const SpaceOutliner &space_outliner, short flag);
bool outliner_flag_flip(const ListBase &lb, short flag);
-}
void item_rename_fn(struct bContext *C,
struct ReportList *reports,
@@ -425,29 +421,29 @@ void item_rename_fn(struct bContext *C,
void lib_relocate_fn(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
- struct TreeElement *te,
+ TreeElement *te,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
void lib_reload_fn(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
- struct TreeElement *te,
+ TreeElement *te,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
-void id_delete_fn(struct bContext *C,
- struct ReportList *reports,
- struct Scene *scene,
- struct TreeElement *te,
- struct TreeStoreElem *tsep,
- struct TreeStoreElem *tselem,
- void *user_data);
+void id_delete_tag_fn(struct bContext *C,
+ struct ReportList *reports,
+ struct Scene *scene,
+ TreeElement *te,
+ struct TreeStoreElem *tsep,
+ struct TreeStoreElem *tselem,
+ void *user_data);
void id_remap_fn(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
- struct TreeElement *te,
+ TreeElement *te,
struct TreeStoreElem *tsep,
struct TreeStoreElem *tselem,
void *user_data);
@@ -461,10 +457,7 @@ void outliner_set_coordinates(const struct ARegion *region,
/**
* Open or close a tree element, optionally toggling all children recursively.
*/
-void outliner_item_openclose(struct SpaceOutliner *space_outliner,
- TreeElement *te,
- bool open,
- bool toggle_all);
+void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all);
/* outliner_dragdrop.c */
@@ -530,6 +523,8 @@ void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_liboverride_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_liboverride_troubleshoot_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
void OUTLINER_OT_id_copy(struct wmOperatorType *ot);
@@ -610,10 +605,6 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
bool *r_is_merged_icon,
bool *r_is_over_icon);
/**
- * `tse` is not in the tree-store, we use its contents to find a match.
- */
-TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse);
-/**
* Find specific item from the trees-tore.
*/
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
@@ -689,12 +680,6 @@ int outliner_context(const struct bContext *C,
const char *member,
struct bContextDataResult *result);
-#ifdef __cplusplus
-}
-#endif
-
-namespace blender::ed::outliner {
-
/**
* Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible.
* \return nullptr if the tree-element doesn't match the requested type \a TreeElementT or the
diff --git a/source/blender/editors/space_outliner/outliner_ops.cc b/source/blender/editors/space_outliner/outliner_ops.cc
index 8baac45666e..cf9c4834667 100644
--- a/source/blender/editors/space_outliner/outliner_ops.cc
+++ b/source/blender/editors/space_outliner/outliner_ops.cc
@@ -11,6 +11,7 @@
#include "outliner_intern.hh"
+namespace blender::ed::outliner {
/* -------------------------------------------------------------------- */
/** \name Registration
* \{ */
@@ -29,6 +30,8 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_lib_operation);
WM_operatortype_append(OUTLINER_OT_lib_relocate);
+ WM_operatortype_append(OUTLINER_OT_liboverride_operation);
+ WM_operatortype_append(OUTLINER_OT_liboverride_troubleshoot_operation);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_id_delete);
WM_operatortype_append(OUTLINER_OT_id_remap);
@@ -101,3 +104,5 @@ void outliner_keymap(wmKeyConfig *keyconf)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_query.cc b/source/blender/editors/space_outliner/outliner_query.cc
index d6483c44fce..11929cbe2f0 100644
--- a/source/blender/editors/space_outliner/outliner_query.cc
+++ b/source/blender/editors/space_outliner/outliner_query.cc
@@ -13,7 +13,7 @@
#include "outliner_intern.hh"
#include "tree/tree_display.hh"
-using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
bool outliner_shows_mode_column(const SpaceOutliner &space_outliner)
{
@@ -46,3 +46,5 @@ bool outliner_has_element_warnings(const SpaceOutliner &space_outliner)
return recursive_fn(space_outliner.tree);
}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index 877e0fc325c..17e78ece941 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -70,7 +70,7 @@
#include "tree/tree_element_seq.hh"
#include "tree/tree_iterator.hh"
-using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -220,7 +220,7 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te)
return;
}
- ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
+ ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
@@ -237,9 +237,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
Object *ob_parent,
bool select)
{
- Base *base;
-
- for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) &&
BKE_object_is_child_recursive(ob_parent, ob))) {
@@ -301,7 +299,7 @@ static void tree_element_object_activate(bContext *C,
ob = (Object *)parent_tselem->id;
/* Don't return when activating children of the previous active object. */
- if (ob == OBACT(view_layer) && set == OL_SETSEL_NONE) {
+ if (ob == BKE_view_layer_active_object_get(view_layer) && set == OL_SETSEL_NONE) {
return;
}
}
@@ -321,7 +319,7 @@ static void tree_element_object_activate(bContext *C,
if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
if (base != nullptr) {
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT;
if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
@@ -388,7 +386,8 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
/* we search for the object parent */
Object *ob = (Object *)outliner_search_back(te, ID_OB);
/* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
- if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
+ if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
+ ob->matbits == nullptr) {
return; /* just paranoia */
}
@@ -418,7 +417,7 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement
scene->camera = ob;
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first);
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
WM_windows_scene_data_sync(&wm->windows, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -458,7 +457,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto
static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
bGPdata *gpd = (bGPdata *)tselem->id;
- bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
+ bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
/* We can only have a single "active" layer at a time
* and there must always be an active layer... */
@@ -486,8 +485,8 @@ static void tree_element_posechannel_activate(bContext *C,
bool recursive)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
- bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
if (!(pchan->bone->flag & BONE_HIDDEN_P)) {
if (set != OL_SETSEL_EXTEND) {
@@ -508,7 +507,7 @@ static void tree_element_posechannel_activate(bContext *C,
}
if (ob != ob_iter) {
- DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -541,14 +540,14 @@ static void tree_element_bone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = reinterpret_cast<Bone *>(te->directdata);
+ Bone *bone = static_cast<Bone *>(te->directdata);
if (!(bone->flag & BONE_HIDDEN_P)) {
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
- for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
+ for (Bone *bone_iter = static_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
bone_iter = bone_iter->next) {
bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
do_outliner_bone_select_recursive(arm, bone_iter, false);
@@ -590,7 +589,7 @@ static void tree_element_ebone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
+ EditBone *ebone = static_cast<EditBone *>(te->directdata);
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
@@ -703,7 +702,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
#if 0
select_single_seq(seq, 1);
#endif
- Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first);
+ Sequence *p = static_cast<Sequence *>(ed->seqbasep->first);
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
p = p->next;
@@ -722,7 +721,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
static void tree_element_master_collection_activate(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(
view_layer->layer_collections.first);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
@@ -733,7 +732,7 @@ static void tree_element_master_collection_activate(const bContext *C)
static void tree_element_layer_collection_activate(bContext *C, TreeElement *te)
{
Scene *scene = CTX_data_scene(C);
- LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
+ LayerCollection *layer_collection = static_cast<LayerCollection *>(te->directdata);
ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
@@ -844,7 +843,7 @@ static eOLDrawState tree_element_defgroup_state_get(const ViewLayer *view_layer,
const TreeStoreElem *tselem)
{
const Object *ob = (const Object *)tselem->id;
- if (ob == OBACT(view_layer)) {
+ if (ob == BKE_view_layer_active_object_get(view_layer)) {
if (BKE_object_defgroup_active_index_get(ob) == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
@@ -857,8 +856,8 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
const TreeStoreElem *tselem)
{
const bArmature *arm = (const bArmature *)tselem->id;
- const Bone *bone = reinterpret_cast<Bone *>(te->directdata);
- const Object *ob = OBACT(view_layer);
+ const Bone *bone = static_cast<Bone *>(te->directdata);
+ const Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob && ob->data == arm) {
if (bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
@@ -869,7 +868,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
static eOLDrawState tree_element_ebone_state_get(const TreeElement *te)
{
- const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
+ const EditBone *ebone = static_cast<EditBone *>(te->directdata);
if (ebone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -913,7 +912,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose,
const TreeStoreElem *tselem)
{
const Object *ob = (const Object *)tselem->id;
- const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
+ const bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
if (ob == ob_pose && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
@@ -929,7 +928,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr
return OL_DRAWSEL_NONE;
}
- const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
+ const ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
if (CTX_data_view_layer(C) == view_layer) {
return OL_DRAWSEL_NORMAL;
@@ -943,7 +942,7 @@ static eOLDrawState tree_element_posegroup_state_get(const ViewLayer *view_layer
{
const Object *ob = (const Object *)tselem->id;
- if (ob == OBACT(view_layer) && ob->pose) {
+ if (ob == BKE_view_layer_active_object_get(view_layer) && ob->pose) {
if (ob->pose->active_group == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
@@ -1009,7 +1008,8 @@ static eOLDrawState tree_element_active_material_get(const ViewLayer *view_layer
/* we search for the object parent */
const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
/* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
- if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
+ if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
+ ob->matbits == nullptr) {
return OL_DRAWSEL_NONE; /* just paranoia */
}
@@ -1229,7 +1229,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
/* Expand the selected constraint in the properties editor. */
if (tselem->type != TSE_CONSTRAINT_BASE) {
- BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata));
+ BKE_constraint_panel_expand(static_cast<bConstraint *>(te->directdata));
}
break;
}
@@ -1242,8 +1242,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
Object *ob = (Object *)tselem->id;
if (ob->type == OB_GPENCIL) {
- BKE_gpencil_modifier_panel_expand(
- reinterpret_cast<GpencilModifierData *>(te->directdata));
+ BKE_gpencil_modifier_panel_expand(static_cast<GpencilModifierData *>(te->directdata));
}
else {
ModifierData *md = (ModifierData *)te->directdata;
@@ -1276,12 +1275,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
context = BCONTEXT_SHADERFX;
if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
- BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata));
+ BKE_shaderfx_panel_expand(static_cast<ShaderFxData *>(te->directdata));
}
break;
case TSE_BONE: {
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = reinterpret_cast<Bone *>(te->directdata);
+ Bone *bone = static_cast<Bone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
context = BCONTEXT_BONE;
@@ -1289,7 +1288,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
+ EditBone *ebone = static_cast<EditBone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr);
context = BCONTEXT_BONE;
@@ -1297,8 +1296,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_CHANNEL: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
- bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr);
context = BCONTEXT_BONE;
@@ -1306,7 +1305,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_BASE: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1314,7 +1313,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_R_LAYER_BASE:
case TSE_R_LAYER: {
- ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
+ ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr);
context = BCONTEXT_VIEW_LAYER;
@@ -1323,7 +1322,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
case TSE_POSEGRP_BASE:
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1571,7 +1570,7 @@ static bool outliner_is_co_within_active_mode_column(bContext *C,
const float view_mval[2])
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
return outliner_is_co_within_mode_column(space_outliner, view_mval) && obact &&
obact->mode != OB_MODE_OBJECT;
@@ -1823,7 +1822,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o
{
while (te->subtree.last) {
if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
- te = reinterpret_cast<TreeElement *>(te->subtree.last);
+ te = static_cast<TreeElement *>(te->subtree.last);
}
else {
break;
@@ -1867,7 +1866,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr
TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
- te = reinterpret_cast<TreeElement *>(te->subtree.first);
+ te = static_cast<TreeElement *>(te->subtree.first);
}
else if (te->next) {
te = te->next;
@@ -1886,7 +1885,7 @@ static TreeElement *outliner_walk_left(SpaceOutliner *space_outliner,
TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_item_openclose(space_outliner, te, false, toggle_all);
+ outliner_item_openclose(te, false, toggle_all);
}
/* Only walk up a level if the element is closed and not toggling expand */
else if (!toggle_all && te->parent) {
@@ -1904,10 +1903,10 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
/* Only walk down a level if the element is open and not toggling expand */
if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
- te = reinterpret_cast<TreeElement *>(te->subtree.first);
+ te = static_cast<TreeElement *>(te->subtree.first);
}
else {
- outliner_item_openclose(space_outliner, te, true, toggle_all);
+ outliner_item_openclose(te, true, toggle_all);
}
return te;
@@ -1955,7 +1954,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner
/* If no active element exists, use the first element in the tree */
if (!active_te) {
- active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
+ active_te = static_cast<TreeElement *>(space_outliner->tree.first);
*changed = true;
}
@@ -2041,3 +2040,5 @@ void OUTLINER_OT_select_walk(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_sync.cc b/source/blender/editors/space_outliner/outliner_sync.cc
index 36bc7c31b91..8f1c15873b4 100644
--- a/source/blender/editors/space_outliner/outliner_sync.cc
+++ b/source/blender/editors/space_outliner/outliner_sync.cc
@@ -77,8 +77,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen;
- screen = reinterpret_cast<bScreen *>(screen->id.next)) {
+ for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
+ screen = static_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -94,6 +94,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
wm->outliner_sync_select_dirty = 0;
}
+namespace blender::ed::outliner {
+
/**
* Outliner sync select dirty flags are not enough to determine which types to sync,
* outliner display mode also needs to be considered. This stores the types of data
@@ -248,7 +250,7 @@ static void outliner_select_sync_to_edit_bone(ViewLayer *view_layer,
/* Tag if selection changed */
if (bone_flag != ebone->flag) {
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, obedit);
}
@@ -259,7 +261,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te,
GSet *selected_pbones)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
short bone_flag = pchan->bone->flag;
@@ -335,8 +337,12 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
}
}
+} // namespace blender::ed::outliner
+
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
{
+ using namespace blender::ed::outliner;
+
/* Don't sync if not checked or in certain outliner display modes */
if (!(space_outliner->flag & SO_SYNC_SELECT) || ELEM(space_outliner->outlinevis,
SO_LIBRARIES,
@@ -380,6 +386,8 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_out
}
}
+namespace blender::ed::outliner {
+
static void outliner_select_sync_from_object(ViewLayer *view_layer,
Object *obact,
TreeElement *te,
@@ -523,7 +531,7 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- active_data->object = OBACT(view_layer);
+ active_data->object = BKE_view_layer_active_object_get(view_layer);
active_data->edit_bone = CTX_data_active_bone(C);
active_data->pose_channel = CTX_data_active_pose_bone(C);
active_data->sequence = SEQ_select_active_get(scene);
@@ -561,3 +569,5 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
}
}
}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index ec19e8d5e5b..b0d24c88eea 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -31,8 +31,11 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
@@ -86,11 +89,15 @@
#include "tree/tree_element_seq.hh"
#include "tree/tree_iterator.hh"
+namespace blender::ed::outliner {
+
static CLG_LogRef LOG = {"ed.outliner.tools"};
using namespace blender::ed::outliner;
+using blender::Map;
using blender::Set;
+using blender::Vector;
/* -------------------------------------------------------------------- */
/** \name ID/Library/Data Set/Un-link Utilities
@@ -448,6 +455,99 @@ static void outliner_do_libdata_operation(bContext *C,
});
}
+enum eOutlinerLibOpSelectionSet {
+ /* Only selected items. */
+ OUTLINER_LIB_SELECTIONSET_SELECTED,
+ /* Only content 'inside' selected items (their sub-tree). */
+ OUTLINER_LIB_LIB_SELECTIONSET_CONTENT,
+ /* Combining both options above. */
+ OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT,
+};
+
+static const EnumPropertyItem prop_lib_op_selection_set[] = {
+ {OUTLINER_LIB_SELECTIONSET_SELECTED,
+ "SELECTED",
+ 0,
+ "Selected",
+ "Apply the operation over selected data-blocks only"},
+ {OUTLINER_LIB_LIB_SELECTIONSET_CONTENT,
+ "CONTENT",
+ 0,
+ "Content",
+ "Apply the operation over content of the selected items only (the data-blocks in their "
+ "sub-tree)"},
+ {OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT,
+ "SELECTED_AND_CONTENT",
+ 0,
+ "Selected & Content",
+ "Apply the operation over selected data-blocks and all their dependencies"},
+ {0, nullptr, 0, nullptr, nullptr},
+};
+
+static void outliner_do_libdata_operation_selection_set(bContext *C,
+ ReportList *reports,
+ Scene *scene,
+ SpaceOutliner *space_outliner,
+ const ListBase &subtree,
+ const bool has_parent_selected,
+ outliner_operation_fn operation_fn,
+ eOutlinerLibOpSelectionSet selection_set,
+ void *user_data)
+{
+ const bool do_selected = ELEM(selection_set,
+ OUTLINER_LIB_SELECTIONSET_SELECTED,
+ OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT);
+ const bool do_content = ELEM(selection_set,
+ OUTLINER_LIB_LIB_SELECTIONSET_CONTENT,
+ OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT);
+
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
+ /* Get needed data out in case element gets freed. */
+ TreeStoreElem *tselem = TREESTORE(element);
+ const ListBase subtree = element->subtree;
+
+ bool is_selected = tselem->flag & TSE_SELECTED;
+ if ((is_selected && do_selected) || (has_parent_selected && do_content)) {
+ if (((tselem->type == TSE_SOME_ID) && (element->idcode != 0)) ||
+ tselem->type == TSE_LAYER_COLLECTION) {
+ TreeStoreElem *tsep = element->parent ? TREESTORE(element->parent) : nullptr;
+ operation_fn(C, reports, scene, element, tsep, tselem, user_data);
+ }
+ }
+
+ /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
+ * also have been changed in the visitor callback. */
+ outliner_do_libdata_operation_selection_set(C,
+ reports,
+ scene,
+ space_outliner,
+ subtree,
+ is_selected || has_parent_selected,
+ operation_fn,
+ selection_set,
+ user_data);
+ }
+}
+
+static void outliner_do_libdata_operation_selection_set(bContext *C,
+ ReportList *reports,
+ Scene *scene,
+ SpaceOutliner *space_outliner,
+ outliner_operation_fn operation_fn,
+ eOutlinerLibOpSelectionSet selection_set,
+ void *user_data)
+{
+ outliner_do_libdata_operation_selection_set(C,
+ reports,
+ scene,
+ space_outliner,
+ space_outliner->tree,
+ false,
+ operation_fn,
+ selection_set,
+ user_data);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -777,6 +877,25 @@ static void id_local_fn(bContext *C,
}
}
+struct OutlinerLiboverrideDataIDRoot {
+ /** The linked ID that was selected for override. */
+ ID *id_root_reference;
+
+ /** The root of the override hierarchy to which the override of `id_root` belongs, once
+ * known/created. */
+ ID *id_hierarchy_root_override;
+
+ /** The ID that was detected as being a good candidate as instantiation hint for newly overridden
+ * objects, may be null.
+ *
+ * \note Typically currently only used when the root ID to override is a collection instanced by
+ * an empty object. */
+ ID *id_instance_hint;
+
+ /** If this override comes from an instancing object (which would be `id_instance_hint` then). */
+ bool is_override_instancing_object;
+};
+
struct OutlinerLibOverrideData {
bool do_hierarchy;
@@ -789,35 +908,82 @@ struct OutlinerLibOverrideData {
* solving broken overrides while not losing *all* of your overrides. */
bool do_resync_hierarchy_enforce;
- /** The override hierarchy root, when known/created. */
- ID *id_hierarchy_root_override;
-
- /** A hash of the selected tree elements' ID 'uuid'. Used to clear 'system override' flags on
+ /** A set of the selected tree elements' ID 'uuid'. Used to clear 'system override' flags on
* their newly-created liboverrides in post-process step of override hierarchy creation. */
Set<uint> selected_id_uid;
+
+ /** A mapping from the found hierarchy roots to a linked list of IDs to override for each of
+ * these roots.
+ *
+ * \note the key may be either linked (in which case it will be replaced by the newly created
+ * override), or an actual already existing override. */
+ Map<ID *, Vector<OutlinerLiboverrideDataIDRoot>> id_hierarchy_roots;
+
+ /** All 'session_uuid' of all hierarchy root IDs used or created by the operation. */
+ Set<uint> id_hierarchy_roots_uid;
+
+ void id_root_add(ID *id_hierarchy_root_reference,
+ ID *id_root_reference,
+ ID *id_instance_hint,
+ const bool is_override_instancing_object)
+ {
+ OutlinerLiboverrideDataIDRoot id_root_data;
+ id_root_data.id_root_reference = id_root_reference;
+ id_root_data.id_hierarchy_root_override = nullptr;
+ id_root_data.id_instance_hint = id_instance_hint;
+ id_root_data.is_override_instancing_object = is_override_instancing_object;
+
+ Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
+ id_hierarchy_root_reference);
+ value.append(id_root_data);
+ }
+ void id_root_set(ID *id_hierarchy_root_reference)
+ {
+ OutlinerLiboverrideDataIDRoot id_root_data;
+ id_root_data.id_root_reference = nullptr;
+ id_root_data.id_hierarchy_root_override = nullptr;
+ id_root_data.id_instance_hint = nullptr;
+ id_root_data.is_override_instancing_object = false;
+
+ Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
+ id_hierarchy_root_reference);
+ if (value.is_empty()) {
+ value.append(id_root_data);
+ }
+ }
};
/* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override
* hierarchy. */
-static void id_override_library_create_hierarchy_pre_process_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
+static void id_override_library_create_hierarchy_pre_process_fn(bContext *C,
+ ReportList *reports,
Scene *UNUSED(scene),
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
+ TreeElement *te,
+ TreeStoreElem *tsep,
TreeStoreElem *tselem,
void *user_data)
{
BLI_assert(TSE_IS_REAL_ID(tselem));
- OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
+ OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
ID *id_root_reference = tselem->id;
+ if (!BKE_idtype_idcode_is_linkable(GS(id_root_reference->name)) ||
+ (id_root_reference->flag & (LIB_EMBEDDED_DATA | LIB_EMBEDDED_DATA_LIB_OVERRIDE)) != 0) {
+ return;
+ }
+
BLI_assert(do_hierarchy);
UNUSED_VARS_NDEBUG(do_hierarchy);
data->selected_id_uid.add(id_root_reference->session_uuid);
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root_reference) && !ID_IS_LINKED(id_root_reference)) {
+ id_root_reference->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ return;
+ }
+
if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) {
/* If selected element is a (closed) collection, check all of its objects recursively, and also
* consider the armature ones as 'selected' (i.e. to not become system overrides). */
@@ -829,28 +995,6 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *UNUSED
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
-}
-
-static void id_override_library_create_fn(bContext *C,
- ReportList *reports,
- Scene *scene,
- TreeElement *te,
- TreeStoreElem *tsep,
- TreeStoreElem *tselem,
- void *user_data)
-{
- BLI_assert(TSE_IS_REAL_ID(tselem));
-
- /* We can only safely apply this operation on one item at a time, so only do it on the active
- * one. */
- if ((tselem->flag & TSE_ACTIVE) == 0) {
- return;
- }
-
- ID *id_root_reference = tselem->id;
- OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
- const bool do_hierarchy = data->do_hierarchy;
- bool success = false;
ID *id_instance_hint = nullptr;
bool is_override_instancing_object = false;
@@ -866,195 +1010,259 @@ static void id_override_library_create_fn(bContext *C,
}
}
- if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference) ||
- (ID_IS_LINKED(id_root_reference) && do_hierarchy)) {
- Main *bmain = CTX_data_main(C);
+ if (!ID_IS_OVERRIDABLE_LIBRARY(id_root_reference) &&
+ !(ID_IS_LINKED(id_root_reference) && do_hierarchy)) {
+ return;
+ }
- id_root_reference->tag |= LIB_TAG_DOIT;
+ Main *bmain = CTX_data_main(C);
- /* For now, remap all local usages of linked ID to local override one here. */
- ID *id_iter;
- FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (ID_IS_LINKED(id_iter)) {
- id_iter->tag &= ~LIB_TAG_DOIT;
- }
- else {
- id_iter->tag |= LIB_TAG_DOIT;
+ if (do_hierarchy) {
+ /* Tag all linked parents in tree hierarchy to be also overridden. */
+ ID *id_hierarchy_root_reference = id_root_reference;
+ while ((te = te->parent) != nullptr) {
+ if (!TSE_IS_REAL_ID(te->store_elem)) {
+ continue;
}
- }
- FOREACH_MAIN_ID_END;
- if (do_hierarchy) {
- /* Tag all linked parents in tree hierarchy to be also overridden. */
- ID *id_hierarchy_root_reference = id_root_reference;
- while ((te = te->parent) != nullptr) {
- if (!TSE_IS_REAL_ID(te->store_elem)) {
+ /* Tentative hierarchy root. */
+ ID *id_current_hierarchy_root = te->store_elem->id;
+
+ /* If the parent ID is from a different library than the reference root one, we are done
+ * with upwards tree processing in any case. */
+ if (id_current_hierarchy_root->lib != id_root_reference->lib) {
+ if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_current_hierarchy_root)) {
+ /* Virtual overrides (i.e. embedded IDs), we can simply keep processing their parent to
+ * get an actual real override. */
continue;
}
- /* Tentative hierarchy root. */
- ID *id_current_hierarchy_root = te->store_elem->id;
-
- /* If the parent ID is from a different library than the reference root one, we are done
- * with upwards tree processing in any case. */
- if (id_current_hierarchy_root->lib != id_root_reference->lib) {
- if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_current_hierarchy_root)) {
- /* Virtual overrides (i.e. embedded IDs), we can simply keep processing their parent to
- * get an actual real override. */
- continue;
- }
-
- /* If the parent ID is already an override, and is valid (i.e. local override), we can
- * access its hierarchy root directly. */
- if (!ID_IS_LINKED(id_current_hierarchy_root) &&
- ID_IS_OVERRIDE_LIBRARY_REAL(id_current_hierarchy_root) &&
- id_current_hierarchy_root->override_library->reference->lib ==
- id_root_reference->lib) {
- id_hierarchy_root_reference =
- id_current_hierarchy_root->override_library->hierarchy_root;
- BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
- break;
- }
-
- if (ID_IS_LINKED(id_current_hierarchy_root)) {
- /* No local 'anchor' was found for the hierarchy to override, do not proceed, as this
- * would most likely generate invisible/confusing/hard to use and manage overrides. */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- BKE_reportf(reports,
- RPT_WARNING,
- "Invalid anchor ('%s') found, needed to create library override from "
- "data-block '%s'",
- id_current_hierarchy_root->name,
- id_root_reference->name);
- return;
- }
-
- /* In all other cases, `id_current_hierarchy_root` cannot be a valid hierarchy root, so
- * current `id_hierarchy_root_reference` is our best candidate. */
-
+ /* If the parent ID is already an override, and is valid (i.e. local override), we can
+ * access its hierarchy root directly. */
+ if (!ID_IS_LINKED(id_current_hierarchy_root) &&
+ ID_IS_OVERRIDE_LIBRARY_REAL(id_current_hierarchy_root) &&
+ id_current_hierarchy_root->override_library->reference->lib ==
+ id_root_reference->lib) {
+ id_hierarchy_root_reference =
+ id_current_hierarchy_root->override_library->hierarchy_root;
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
break;
}
- /* If some element in the tree needs to be overridden, but its ID is not overridable,
- * abort. */
- if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_current_hierarchy_root)) {
+ if (ID_IS_LINKED(id_current_hierarchy_root)) {
+ /* No local 'anchor' was found for the hierarchy to override, do not proceed, as this
+ * would most likely generate invisible/confusing/hard to use and manage overrides. */
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
BKE_reportf(reports,
RPT_WARNING,
- "Could not create library override from data-block '%s', one of its parents "
- "is not overridable ('%s')",
- id_root_reference->name,
- id_current_hierarchy_root->name);
+ "Invalid anchor ('%s') found, needed to create library override from "
+ "data-block '%s'",
+ id_current_hierarchy_root->name,
+ id_root_reference->name);
return;
}
- id_current_hierarchy_root->tag |= LIB_TAG_DOIT;
- id_hierarchy_root_reference = id_current_hierarchy_root;
+
+ /* In all other cases, `id_current_hierarchy_root` cannot be a valid hierarchy root, so
+ * current `id_hierarchy_root_reference` is our best candidate. */
+
+ break;
}
- /* That case can happen when linked data is a complex mix involving several libraries and/or
- * linked overrides. E.g. a mix of overrides from one library, and indirectly linked data
- * from another library. Do not try to support such cases for now. */
- if (!((id_hierarchy_root_reference->lib == id_root_reference->lib) ||
- (!ID_IS_LINKED(id_hierarchy_root_reference) &&
- ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference) &&
- id_hierarchy_root_reference->override_library->reference->lib ==
- id_root_reference->lib))) {
+ /* If some element in the tree needs to be overridden, but its ID is not overridable,
+ * abort. */
+ if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_current_hierarchy_root)) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
BKE_reportf(reports,
RPT_WARNING,
- "Invalid hierarchy root ('%s') found, needed to create library override from "
- "data-block '%s'",
- id_hierarchy_root_reference->name,
- id_root_reference->name);
+ "Could not create library override from data-block '%s', one of its parents "
+ "is not overridable ('%s')",
+ id_root_reference->name,
+ id_current_hierarchy_root->name);
return;
}
+ id_current_hierarchy_root->tag |= LIB_TAG_DOIT;
+ id_hierarchy_root_reference = id_current_hierarchy_root;
+ }
+
+ /* That case can happen when linked data is a complex mix involving several libraries and/or
+ * linked overrides. E.g. a mix of overrides from one library, and indirectly linked data
+ * from another library. Do not try to support such cases for now. */
+ if (!((id_hierarchy_root_reference->lib == id_root_reference->lib) ||
+ (!ID_IS_LINKED(id_hierarchy_root_reference) &&
+ ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference) &&
+ id_hierarchy_root_reference->override_library->reference->lib ==
+ id_root_reference->lib))) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Invalid hierarchy root ('%s') found, needed to create library override from "
+ "data-block '%s'",
+ id_hierarchy_root_reference->name,
+ id_root_reference->name);
+ return;
+ }
+
+ /* While ideally this should not be needed, in practice user almost _never_ wants to actually
+ * create liboverrides for all data under a selected hierarchy node, and this has currently a
+ * dreadful consequences over performances (since it would call
+ * #BKE_lib_override_library_create over _all_ items in the hierarchy). So only the clearing of
+ * the system override flag is supported for non-selected items for now.
+ */
+ const bool is_selected = tselem->flag & TSE_SELECTED;
+ if (!is_selected && data->id_hierarchy_roots.contains(id_hierarchy_root_reference)) {
+ return;
+ }
+
+ data->id_root_add(id_hierarchy_root_reference,
+ id_root_reference,
+ id_instance_hint,
+ is_override_instancing_object);
+ }
+ else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) {
+ data->id_root_add(
+ id_root_reference, id_root_reference, id_instance_hint, is_override_instancing_object);
+ }
+}
+
+static void id_override_library_create_hierarchy(
+ Main &bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ OutlinerLibOverrideData &data,
+ ID *id_hierarchy_root_reference,
+ Vector<OutlinerLiboverrideDataIDRoot> &data_idroots,
+ bool &r_aggregated_success)
+{
+ BLI_assert(ID_IS_LINKED(id_hierarchy_root_reference) ||
+ ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
+
+ const bool do_hierarchy = data.do_hierarchy;
+
+ /* NOTE: This process is not the most efficient, but allows to re-use existing code.
+ * If this becomes a bottle-neck at some point, we need to implement a new
+ * `BKE_lib_override_library_hierarchy_create()` function able to process several roots inside of
+ * a same hierarchy in a single call. */
+ for (OutlinerLiboverrideDataIDRoot &data_idroot : data_idroots) {
+ /* For now, remap all local usages of linked ID to local override one here. */
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (&bmain, id_iter) {
+ if (ID_IS_LINKED(id_iter) || ID_IS_OVERRIDE_LIBRARY(id_iter)) {
+ id_iter->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ id_iter->tag |= LIB_TAG_DOIT;
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ bool success = false;
+ if (do_hierarchy) {
ID *id_root_override = nullptr;
- success = BKE_lib_override_library_create(bmain,
- CTX_data_scene(C),
- CTX_data_view_layer(C),
+ success = BKE_lib_override_library_create(&bmain,
+ scene,
+ view_layer,
nullptr,
- id_root_reference,
+ data_idroot.id_root_reference,
id_hierarchy_root_reference,
- id_instance_hint,
+ data_idroot.id_instance_hint,
&id_root_override,
- data->do_fully_editable);
-
- BLI_assert(id_root_override != nullptr);
- BLI_assert(!ID_IS_LINKED(id_root_override));
- BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
- if (ID_IS_LINKED(id_hierarchy_root_reference)) {
- BLI_assert(
- id_root_override->override_library->hierarchy_root->override_library->reference ==
- id_hierarchy_root_reference);
- data->id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
- }
- else {
- BLI_assert(id_root_override->override_library->hierarchy_root ==
- id_hierarchy_root_reference);
- data->id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
+ data.do_fully_editable);
+
+ if (success) {
+ BLI_assert(id_root_override != nullptr);
+ BLI_assert(!ID_IS_LINKED(id_root_override));
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
+
+ ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_override));
+ if (ID_IS_LINKED(id_hierarchy_root_reference)) {
+ BLI_assert(id_hierarchy_root_override->override_library->reference ==
+ id_hierarchy_root_reference);
+ /* If the hierarchy root reference was a linked data, after the first iteration there is
+ * now a matching override, which shall be used for all further partial overrides with
+ * this same hierarchy. */
+ id_hierarchy_root_reference = id_hierarchy_root_override;
+ }
+ else {
+ BLI_assert(id_hierarchy_root_override == id_hierarchy_root_reference);
+ }
+ data_idroot.id_hierarchy_root_override = id_hierarchy_root_override;
+ data.id_hierarchy_roots_uid.add(id_hierarchy_root_override->session_uuid);
}
}
- else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) {
- success = BKE_lib_override_library_create_from_id(bmain, id_root_reference, true) != nullptr;
+ else if (ID_IS_OVERRIDABLE_LIBRARY(data_idroot.id_root_reference)) {
+ ID *id_root_override = BKE_lib_override_library_create_from_id(
+ &bmain, data_idroot.id_root_reference, true);
+ success = id_root_override != nullptr;
+ if (success) {
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
+ id_root_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ }
/* Cleanup. */
- BKE_main_id_newptr_and_tag_clear(bmain);
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ BKE_main_id_newptr_and_tag_clear(&bmain);
+ BKE_main_id_tag_all(&bmain, LIB_TAG_DOIT, false);
+ }
+ else {
+ BLI_assert_unreachable();
}
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
- if (success && is_override_instancing_object) {
- ED_object_base_free_and_unlink(bmain, scene, (Object *)id_instance_hint);
+ if (success && data_idroot.is_override_instancing_object) {
+ BLI_assert(GS(data_idroot.id_instance_hint) == ID_OB);
+ ED_object_base_free_and_unlink(
+ &bmain, scene, reinterpret_cast<Object *>(data_idroot.id_instance_hint));
}
- }
- if (!success) {
- BKE_reportf(reports,
- RPT_WARNING,
- "Could not create library override from data-block '%s'",
- id_root_reference->name);
+
+ r_aggregated_success = r_aggregated_success && success;
}
}
/* Clear system override flag from newly created overrides which linked reference were previously
* selected in the Outliner tree. */
-static void id_override_library_create_hierarchy_post_process(bContext *C,
- OutlinerLibOverrideData *data)
+static void id_override_library_create_hierarchy_process(bContext *C,
+ ReportList *reports,
+ OutlinerLibOverrideData &data)
{
Main *bmain = CTX_data_main(C);
- ID *id_hierarchy_root_override = data->id_hierarchy_root_override;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool do_hierarchy = data.do_hierarchy;
+
+ bool success = true;
+ for (auto &&[id_hierarchy_root_reference, data_idroots] : data.id_hierarchy_roots.items()) {
+ id_override_library_create_hierarchy(
+ *bmain, scene, view_layer, data, id_hierarchy_root_reference, data_idroots, success);
+ }
+
+ if (!success) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Could not create library override from one or more of the selected data-blocks");
+ }
+
+ if (!do_hierarchy) {
+ return;
+ }
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) ||
- id_iter->override_library->hierarchy_root != id_hierarchy_root_override) {
+ if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
+ continue;
+ }
+ if (!data.id_hierarchy_roots_uid.contains(
+ id_iter->override_library->hierarchy_root->session_uuid)) {
continue;
}
- if (data->selected_id_uid.contains(id_iter->override_library->reference->session_uuid)) {
+ if (data.selected_id_uid.contains(id_iter->override_library->reference->session_uuid) ||
+ data.selected_id_uid.contains(id_iter->session_uuid)) {
id_iter->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
}
}
FOREACH_MAIN_ID_END;
}
-static void id_override_library_toggle_flag_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
- Scene *UNUSED(scene),
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *user_data)
-{
- BLI_assert(TSE_IS_REAL_ID(tselem));
- ID *id = tselem->id;
-
- if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
- const uint flag = POINTER_AS_UINT(user_data);
- id->override_library->flag ^= flag;
- }
-}
-
static void id_override_library_reset_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -1065,137 +1273,157 @@ static void id_override_library_reset_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
+ OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
- if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
- Main *bmain = CTX_data_main(C);
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
+ CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
+ return;
+ }
- if (do_hierarchy) {
- BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false);
- }
- else {
- BKE_lib_override_library_id_reset(bmain, id_root, false);
- }
+ Main *bmain = CTX_data_main(C);
- WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+ if (do_hierarchy) {
+ BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false);
}
else {
- CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
+ BKE_lib_override_library_id_reset(bmain, id_root, false);
}
}
-static void id_override_library_resync_fn(bContext *C,
- ReportList *reports,
- Scene *scene,
- TreeElement *te,
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *user_data)
+static void id_override_library_clear_single_fn(bContext *C,
+ ReportList *reports,
+ Scene *scene,
+ TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep),
+ TreeStoreElem *tselem,
+ void *UNUSED(user_data))
{
BLI_assert(TSE_IS_REAL_ID(tselem));
- ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
- const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce;
-
- if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ID *id = tselem->id;
- id_root->tag |= LIB_TAG_DOIT;
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot clear embedded library override id '%s', only overrides of real "
+ "data-blocks can be directly deleted",
+ id->name);
+ return;
+ }
- /* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != nullptr) {
- if (!TSE_IS_REAL_ID(te->store_elem)) {
- continue;
- }
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) {
- break;
+ /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy),
+ * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system
+ * override. */
+ if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) {
+ bool do_remap_active = false;
+ if (BKE_view_layer_active_object_get(view_layer) == reinterpret_cast<Object *>(id)) {
+ BLI_assert(GS(id->name) == ID_OB);
+ do_remap_active = true;
+ }
+ BKE_libblock_remap(bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (do_remap_active) {
+ Object *ref_object = reinterpret_cast<Object *>(id->override_library->reference);
+ Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
+ if (basact != nullptr) {
+ view_layer->basact = basact;
}
- te->store_elem->id->tag |= LIB_TAG_DOIT;
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
}
-
- BlendFileReadReport report{};
- report.reports = reports;
- BKE_lib_override_library_resync(
- bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report);
-
- WM_event_add_notifier(C, NC_WINDOW, nullptr);
+ BKE_id_delete(bmain, id);
}
else {
- CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
+ BKE_lib_override_library_id_reset(bmain, id, true);
}
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
}
-static void id_override_library_clear_hierarchy_fn(bContext *C,
- ReportList *UNUSED(reports),
- Scene *UNUSED(scene),
- TreeElement *te,
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+static void id_override_library_resync_fn(bContext *UNUSED(C),
+ ReportList *UNUSED(reports),
+ Scene *UNUSED(scene),
+ TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep),
+ TreeStoreElem *tselem,
+ void *user_data)
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
+ OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data);
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
- CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
+ CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
return;
}
+ if (id_root->override_library->hierarchy_root != nullptr) {
+ id_root = id_root->override_library->hierarchy_root;
+ }
+
+ data->id_root_set(id_root);
+}
+
+/* Resync a hierarchy of library overrides. */
+static void id_override_library_resync_hierarchy_process(bContext *C,
+ ReportList *reports,
+ OutlinerLibOverrideData &data)
+{
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ const bool do_hierarchy_enforce = data.do_resync_hierarchy_enforce;
- id_root->tag |= LIB_TAG_DOIT;
+ BlendFileReadReport report{};
+ report.reports = reports;
- /* Tag all override parents in tree hierarchy to be also processed. */
- while ((te = te->parent) != nullptr) {
- if (!TSE_IS_REAL_ID(te->store_elem)) {
- continue;
- }
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) {
- break;
- }
- te->store_elem->id->tag |= LIB_TAG_DOIT;
+ for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
+ BKE_lib_override_library_resync(bmain,
+ scene,
+ CTX_data_view_layer(C),
+ id_hierarchy_root,
+ nullptr,
+ do_hierarchy_enforce,
+ &report);
}
- BKE_lib_override_library_delete(bmain, id_root);
-
WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
-static void id_override_library_clear_single_fn(bContext *C,
- ReportList *reports,
- Scene *UNUSED(scene),
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+static void id_override_library_delete_hierarchy_fn(bContext *UNUSED(C),
+ ReportList *UNUSED(reports),
+ Scene *UNUSED(scene),
+ TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep),
+ TreeStoreElem *tselem,
+ void *user_data)
{
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
+
BLI_assert(TSE_IS_REAL_ID(tselem));
- Main *bmain = CTX_data_main(C);
- ID *id = tselem->id;
+ ID *id_root = tselem->id;
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
- BKE_reportf(reports,
- RPT_WARNING,
- "Cannot clear embedded library override id '%s', only overrides of real "
- "data-blocks can be directly deleted",
- id->name);
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
+ CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
return;
}
- /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy),
- * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system
- * override. */
- if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) {
- BKE_libblock_remap(bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE);
- BKE_id_delete(bmain, id);
- }
- else {
- BKE_lib_override_library_id_reset(bmain, id, true);
+ if (id_root->override_library->hierarchy_root != nullptr) {
+ id_root = id_root->override_library->hierarchy_root;
}
- WM_event_add_notifier(C, NC_WINDOW, nullptr);
+ data->id_root_set(id_root);
+}
+
+/* Clear (delete) a hierarchy of library overrides. */
+static void id_override_library_delete_hierarchy_process(bContext *C,
+ ReportList *UNUSED(reports),
+ OutlinerLibOverrideData &data)
+{
+ Main *bmain = CTX_data_main(C);
+
+ for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
+ BKE_lib_override_library_delete(bmain, id_hierarchy_root);
+ }
}
static void id_fake_user_set_fn(bContext *UNUSED(C),
@@ -1399,6 +1627,251 @@ static void refreshdrivers_animdata_fn(int UNUSED(event),
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Library Overrides Operation Menu.
+ * \{ */
+
+enum eOutlinerLibOverrideOpTypes {
+ OUTLINER_LIBOVERRIDE_OP_INVALID = 0,
+
+ OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY,
+ OUTLINER_LIBOVERRIDE_OP_RESET,
+ OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE,
+
+ OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY,
+ OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE,
+ OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY,
+};
+
+static const EnumPropertyItem prop_liboverride_op_types[] = {
+ {OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY,
+ "OVERRIDE_LIBRARY_CREATE_HIERARCHY",
+ 0,
+ "Make",
+ "Create a local override of the selected linked data-blocks, and their hierarchy of "
+ "dependencies"},
+ {OUTLINER_LIBOVERRIDE_OP_RESET,
+ "OVERRIDE_LIBRARY_RESET",
+ 0,
+ "Reset",
+ "Reset the selected local overrides to their linked references values"},
+ {OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE,
+ "OVERRIDE_LIBRARY_CLEAR_SINGLE",
+ 0,
+ "Clear",
+ "Delete the selected local overrides and relink their usages to the linked data-blocks if "
+ "possible, else reset them and mark them as non editable"},
+ {0, nullptr, 0, nullptr, nullptr},
+};
+
+static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[] = {
+ {OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY,
+ "OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
+ 0,
+ "Resync",
+ "Rebuild the selected local overrides from their linked references, as well as their "
+ "hierarchies of dependencies"},
+ {OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE,
+ "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
+ 0,
+ "Resync Enforce",
+ "Rebuild the selected local overrides from their linked references, as well as their "
+ "hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. "
+ "ignoring existing overrides on data-blocks pointer properties)"},
+ RNA_ENUM_ITEM_SEPR,
+ {OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY,
+ "OVERRIDE_LIBRARY_DELETE_HIERARCHY",
+ 0,
+ "Delete",
+ "Delete the selected local overrides (including their hierarchies of override dependencies) "
+ "and relink their usages to the linked data-blocks"},
+ {0, nullptr, 0, nullptr, nullptr},
+};
+
+static bool outliner_liboverride_operation_poll(bContext *C)
+{
+ if (!outliner_operation_tree_element_poll(C)) {
+ return false;
+ }
+ return true;
+}
+
+static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+
+ /* check for invalid states */
+ if (space_outliner == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ TreeElement *te = get_target_element(space_outliner);
+ get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ const eOutlinerLibOpSelectionSet selection_set = static_cast<eOutlinerLibOpSelectionSet>(
+ RNA_enum_get(op->ptr, "selection_set"));
+ const eOutlinerLibOverrideOpTypes event = static_cast<eOutlinerLibOverrideOpTypes>(
+ RNA_enum_get(op->ptr, "type"));
+ switch (event) {
+ case OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_fully_editable = false;
+
+ outliner_do_libdata_operation_selection_set(
+ C,
+ op->reports,
+ scene,
+ space_outliner,
+ id_override_library_create_hierarchy_pre_process_fn,
+ selection_set,
+ &override_data);
+
+ id_override_library_create_hierarchy_process(C, op->reports, override_data);
+
+ ED_undo_push(C, "Overridden Data Hierarchy");
+ break;
+ }
+ case OUTLINER_LIBOVERRIDE_OP_RESET: {
+ OutlinerLibOverrideData override_data{};
+ outliner_do_libdata_operation_selection_set(C,
+ op->reports,
+ scene,
+ space_outliner,
+ id_override_library_reset_fn,
+ selection_set,
+ &override_data);
+ ED_undo_push(C, "Reset Overridden Data");
+ break;
+ }
+ case OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE: {
+ outliner_do_libdata_operation_selection_set(C,
+ op->reports,
+ scene,
+ space_outliner,
+ id_override_library_clear_single_fn,
+ selection_set,
+ nullptr);
+ ED_undo_push(C, "Clear Overridden Data");
+ break;
+ }
+
+ case OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ outliner_do_libdata_operation_selection_set(C,
+ op->reports,
+ scene,
+ space_outliner,
+ id_override_library_resync_fn,
+ OUTLINER_LIB_SELECTIONSET_SELECTED,
+ &override_data);
+
+ id_override_library_resync_hierarchy_process(C, op->reports, override_data);
+
+ ED_undo_push(C, "Resync Overridden Data Hierarchy");
+ break;
+ }
+ case OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_resync_hierarchy_enforce = true;
+ outliner_do_libdata_operation_selection_set(C,
+ op->reports,
+ scene,
+ space_outliner,
+ id_override_library_resync_fn,
+ OUTLINER_LIB_SELECTIONSET_SELECTED,
+ &override_data);
+
+ id_override_library_resync_hierarchy_process(C, op->reports, override_data);
+
+ ED_undo_push(C, "Resync Overridden Data Hierarchy Enforce");
+ break;
+ }
+ case OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ outliner_do_libdata_operation_selection_set(C,
+ op->reports,
+ scene,
+ space_outliner,
+ id_override_library_delete_hierarchy_fn,
+ OUTLINER_LIB_SELECTIONSET_SELECTED,
+ nullptr);
+
+ id_override_library_delete_hierarchy_process(C, op->reports, override_data);
+
+ ED_undo_push(C, "Delete Overridden Data Hierarchy");
+ break;
+ }
+ default:
+ /* Invalid - unhandled. */
+ break;
+ }
+
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
+ WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_liboverride_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Library Override Operation";
+ ot->idname = "OUTLINER_OT_liboverride_operation";
+ ot->description = "Create, reset or clear library override hierarchies";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_liboverride_operation_exec;
+ ot->poll = outliner_liboverride_operation_poll;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "type", prop_liboverride_op_types, 0, "Library Override Operation", "");
+ ot->prop = RNA_def_enum(ot->srna,
+ "selection_set",
+ prop_lib_op_selection_set,
+ 0,
+ "Selection Set",
+ "Over which part of the tree items to apply the operation");
+}
+
+void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Library Override Troubleshoot Operation";
+ ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation";
+ ot->description = "Advanced operations over library override to help fix broken hierarchies";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_liboverride_operation_exec;
+ ot->poll = outliner_liboverride_operation_poll;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna,
+ "type",
+ prop_liboverride_troubleshoot_op_types,
+ 0,
+ "Library Override Troubleshoot Operation",
+ "");
+ RNA_def_enum(ot->srna,
+ "selection_set",
+ prop_lib_op_selection_set,
+ 0,
+ "Selection Set",
+ "Over which part of the tree items to apply the operation");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Object Operation Utilities
* \{ */
@@ -1542,7 +2015,7 @@ static void data_select_linked_fn(int event,
const PointerRNA &ptr = te_rna_struct->getPointerRNA();
if (RNA_struct_is_ID(ptr.type)) {
bContext *C = (bContext *)C_v;
- ID *id = reinterpret_cast<ID *>(ptr.data);
+ ID *id = static_cast<ID *>(ptr.data);
ED_object_select_linked_by_id(C, id);
}
@@ -1551,7 +2024,7 @@ static void data_select_linked_fn(int event,
static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- bContext *C = reinterpret_cast<bContext *>(C_v);
+ bContext *C = static_cast<bContext *>(C_v);
Main *bmain = CTX_data_main(C);
bConstraint *constraint = (bConstraint *)te->directdata;
Object *ob = (Object *)outliner_search_back(te, ID_OB);
@@ -1642,7 +2115,7 @@ static Base *outliner_batch_delete_hierarchy(
}
object = base->object;
- for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base;
+ for (child_base = static_cast<Base *>(view_layer->object_bases.first); child_base;
child_base = base_next) {
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != object);
@@ -1863,9 +2336,9 @@ static void outliner_do_object_delete(bContext *C,
}
}
-static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void *customdata)
+static TreeTraversalAction outliner_collect_objects_to_delete(TreeElement *te, void *customdata)
{
- ObjectEditData *data = reinterpret_cast<ObjectEditData *>(customdata);
+ ObjectEditData *data = static_cast<ObjectEditData *>(customdata);
GSet *objects_to_delete = data->objects_set;
TreeStoreElem *tselem = TREESTORE(te);
@@ -1878,6 +2351,17 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_SKIP_CHILDS;
}
+ /* Do not allow to delete children objects of an override collection. */
+ TreeElement *te_parent = te->parent;
+ if (outliner_is_collection_tree_element(te_parent)) {
+ TreeStoreElem *tselem_parent = TREESTORE(te_parent);
+ ID *id_parent = tselem_parent->id;
+ BLI_assert(GS(id_parent->name) == ID_GR);
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_parent)) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+ }
+
ID *id = tselem->id;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
@@ -1905,7 +2389,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
+ const Base *basact_prev = view_layer->basact;
const bool delete_hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
@@ -1919,7 +2403,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
&space_outliner->tree,
0,
TSE_SELECTED,
- outliner_find_objects_to_delete,
+ outliner_collect_objects_to_delete,
&object_delete_data);
if (delete_hierarchy) {
@@ -1949,7 +2433,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- if (basact_prev != BASACT(view_layer)) {
+ if (basact_prev != view_layer->basact) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
}
@@ -1993,16 +2477,6 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
OUTLINER_IDOP_REMAP,
@@ -2029,65 +2503,6 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Remap Users",
"Make all users of selected data-blocks to use instead current (clicked) one"},
RNA_ENUM_ITEM_SEPR,
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
- "OVERRIDE_LIBRARY_CREATE",
- 0,
- "Make Library Override Single",
- "Make a single, out-of-hierarchy local override of this linked data-block - only applies to "
- "active Outliner item"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
- "OVERRIDE_LIBRARY_CREATE_HIERARCHY",
- 0,
- "Make Library Override Hierarchy",
- "Make a local override of this linked data-block, and its hierarchy of dependencies - only "
- "applies to active Outliner item"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
- "OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE",
- 0,
- "Make Library Override Hierarchy Fully Editable",
- "Make a local override of this linked data-block, and its hierarchy of dependencies, making "
- "them all fully user-editable - only applies to active Outliner item"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
- "OVERRIDE_LIBRARY_MAKE_EDITABLE",
- 0,
- "Make Library Override Editable",
- "Make the library override data-block editable"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
- "OVERRIDE_LIBRARY_RESET",
- 0,
- "Reset Library Override Single",
- "Reset this local override to its linked values"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
- "OVERRIDE_LIBRARY_RESET_HIERARCHY",
- 0,
- "Reset Library Override Hierarchy",
- "Reset this local override to its linked values, as well as its hierarchy of dependencies"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY,
- "OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
- 0,
- "Resync Library Override Hierarchy",
- "Rebuild this local override from its linked reference, as well as its hierarchy of "
- "dependencies"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE,
- "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
- 0,
- "Resync Library Override Hierarchy Enforce",
- "Rebuild this local override from its linked reference, as well as its hierarchy of "
- "dependencies, enforcing that hierarchy to match the linked data (i.e. ignoring exiting "
- "overrides on data-blocks pointer properties)"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE,
- "OVERRIDE_LIBRARY_CLEAR_SINGLE",
- 0,
- "Clear Library Override Single",
- "Delete this local override and relink its usages to the linked data-blocks if possible, "
- "else reset it and mark it as non editable"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY,
- "OVERRIDE_LIBRARY_CLEAR_HIERARCHY",
- 0,
- "Clear Library Override Hierarchy",
- "Delete this local override (including its hierarchy of override dependencies) and relink "
- "its usages to the linked data-blocks"},
- RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
RNA_ENUM_ITEM_SEPR,
@@ -2120,34 +2535,6 @@ static bool outliner_id_operation_item_poll(bContext *C,
}
switch (enum_value) {
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE:
- if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id)) {
- return true;
- }
- return false;
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE:
- if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id) || (ID_IS_LINKED(tselem->id))) {
- return true;
- }
- return false;
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE:
- if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) {
- if (tselem->id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) {
- return true;
- }
- }
- return false;
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE:
- if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) {
- return true;
- }
- return false;
case OUTLINER_IDOP_SINGLE:
if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
return true;
@@ -2185,6 +2572,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -2259,101 +2647,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Localized Data");
break;
}
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: {
- OutlinerLibOverrideData override_data{};
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
- ED_undo_push(C, "Overridden Data");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: {
- OutlinerLibOverrideData override_data{};
- override_data.do_hierarchy = true;
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- id_override_library_create_hierarchy_pre_process_fn,
- &override_data);
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
- id_override_library_create_hierarchy_post_process(C, &override_data);
-
- ED_undo_push(C, "Overridden Data Hierarchy");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE: {
- OutlinerLibOverrideData override_data{};
- override_data.do_hierarchy = true;
- override_data.do_fully_editable = true;
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- id_override_library_create_hierarchy_pre_process_fn,
- &override_data);
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
- id_override_library_create_hierarchy_post_process(C, &override_data);
-
- ED_undo_push(C, "Overridden Data Hierarchy Fully Editable");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: {
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- id_override_library_toggle_flag_fn,
- POINTER_FROM_UINT(IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED));
-
- ED_undo_push(C, "Make Overridden Data Editable");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
- OutlinerLibOverrideData override_data{};
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data);
- ED_undo_push(C, "Reset Overridden Data");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: {
- OutlinerLibOverrideData override_data{};
- override_data.do_hierarchy = true;
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data);
- ED_undo_push(C, "Reset Overridden Data Hierarchy");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: {
- OutlinerLibOverrideData override_data{};
- override_data.do_hierarchy = true;
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
- ED_undo_push(C, "Resync Overridden Data Hierarchy");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: {
- OutlinerLibOverrideData override_data{};
- override_data.do_hierarchy = true;
- override_data.do_resync_hierarchy_enforce = true;
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data);
- ED_undo_push(C, "Resync Overridden Data Hierarchy");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_clear_hierarchy_fn, nullptr);
- ED_undo_push(C, "Clear Overridden Data Hierarchy");
- break;
- }
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_clear_single_fn, nullptr);
- ED_undo_push(C, "Clear Overridden Data Hierarchy");
- break;
- }
case OUTLINER_IDOP_SINGLE: {
/* make single user */
switch (idlevel) {
@@ -2381,8 +2674,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
+ C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
+ BKE_id_multi_tagged_delete(bmain);
ED_undo_push(C, "Delete");
}
break;
@@ -2463,6 +2758,7 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/* identifiers */
ot->name = "Outliner ID Data Operation";
ot->idname = "OUTLINER_OT_id_operation";
+ ot->description = "General data-block management operations";
/* callbacks */
ot->invoke = WM_menu_invoke;
@@ -2507,6 +2803,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@@ -2522,7 +2819,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_DELETE: {
- outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
+ BKE_id_multi_tagged_delete(bmain);
ED_undo_push(C, "Delete Library");
break;
}
@@ -2623,8 +2923,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
/* get action to use */
- act = reinterpret_cast<bAction *>(
- BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
+ act = static_cast<bAction *>(BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
if (act == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No valid action to add");
@@ -3163,3 +3462,5 @@ void OUTLINER_OT_operation(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index aa739758ecb..070df284c6f 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -41,6 +41,7 @@
#include "BLI_fnmatch.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
+#include "BLI_timeit.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -51,7 +52,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
-#include "BKE_outliner_treehash.h"
+#include "BKE_outliner_treehash.hh"
#include "ED_screen.h"
@@ -69,7 +70,7 @@
# include "BLI_math_base.h" /* M_PI */
#endif
-using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
/* prototypes */
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
@@ -90,7 +91,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool_iter iter;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
tselem->used = 0;
}
@@ -100,7 +101,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
if (tselem->id == nullptr) {
unused++;
}
@@ -110,34 +111,30 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
if (BLI_mempool_len(ts) == unused) {
BLI_mempool_destroy(ts);
space_outliner->treestore = nullptr;
- if (space_outliner->runtime->treehash) {
- BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- space_outliner->runtime->treehash = nullptr;
- }
+ space_outliner->runtime->tree_hash = nullptr;
}
else {
TreeStoreElem *tsenew;
BLI_mempool *new_ts = BLI_mempool_create(
sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER);
BLI_mempool_iternew(ts, &iter);
- while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
if (tselem->id) {
- tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts));
+ tsenew = static_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts));
*tsenew = *tselem;
}
}
BLI_mempool_destroy(ts);
space_outliner->treestore = new_ts;
- if (space_outliner->runtime->treehash) {
+ if (space_outliner->runtime->tree_hash) {
/* update hash table to fix broken pointers */
- BKE_outliner_treehash_rebuild_from_treestore(space_outliner->runtime->treehash,
- space_outliner->treestore);
+ space_outliner->runtime->tree_hash->rebuild_from_treestore(*space_outliner->treestore);
}
}
}
}
- else if (space_outliner->runtime->treehash) {
- BKE_outliner_treehash_clear_used(space_outliner->runtime->treehash);
+ else if (space_outliner->runtime->tree_hash) {
+ space_outliner->runtime->tree_hash->clear_used();
}
}
}
@@ -150,15 +147,14 @@ static void check_persistent(
space_outliner->treestore = BLI_mempool_create(
sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
}
- if (space_outliner->runtime->treehash == nullptr) {
- space_outliner->runtime->treehash = reinterpret_cast<GHash *>(
- BKE_outliner_treehash_create_from_treestore(space_outliner->treestore));
+ if (space_outliner->runtime->tree_hash == nullptr) {
+ space_outliner->runtime->tree_hash = treehash::TreeHash::create_from_treestore(
+ *space_outliner->treestore);
}
/* find any unused tree element in treestore and mark it as used
* (note that there may be multiple unused elements in case of linked objects) */
- TreeStoreElem *tselem = BKE_outliner_treehash_lookup_unused(
- space_outliner->runtime->treehash, type, nr, id);
+ TreeStoreElem *tselem = space_outliner->runtime->tree_hash->lookup_unused(type, nr, id);
if (tselem) {
te->store_elem = tselem;
tselem->used = 1;
@@ -166,14 +162,14 @@ static void check_persistent(
}
/* add 1 element to treestore */
- tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore));
+ tselem = static_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore));
tselem->type = type;
tselem->nr = type ? nr : 0;
tselem->id = id;
tselem->used = 0;
tselem->flag = TSE_CLOSED;
te->store_elem = tselem;
- BKE_outliner_treehash_add_element(space_outliner->runtime->treehash, tselem);
+ space_outliner->runtime->tree_hash->add_element(*tselem);
}
/** \} */
@@ -221,11 +217,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s
return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
}
-bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner)
-{
- return ELEM(space_outliner->outlinevis, SO_DATA_API);
-}
-
/* special handling of hierarchical non-lib data */
static void outliner_add_bone(SpaceOutliner *space_outliner,
ListBase *lb,
@@ -293,7 +284,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
- bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bArmature *arm = static_cast<bArmature *>(ob->data);
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
tenla->name = IFACE_("Pose");
@@ -339,7 +330,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
/* make hierarchy */
- TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first);
+ TreeElement *ten = static_cast<TreeElement *>(tenla->subtree.first);
while (ten) {
TreeElement *nten = ten->next, *par;
tselem = TREESTORE(ten);
@@ -694,15 +685,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
ebone->temp.p = ten;
}
/* make hierarchy */
- TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>(
- ((EditBone *)arm->edbo->first)->temp.p) :
- nullptr;
+ TreeElement *ten = arm->edbo->first ?
+ static_cast<TreeElement *>(((EditBone *)arm->edbo->first)->temp.p) :
+ nullptr;
while (ten) {
TreeElement *nten = ten->next, *par;
EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p);
+ par = static_cast<TreeElement *>(ebone->parent->temp.p);
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -795,8 +786,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
-namespace blender::ed::outliner {
-
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@@ -805,21 +794,24 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short index,
const bool expand)
{
- ID *id = reinterpret_cast<ID *>(idv);
+ ID *id = static_cast<ID *>(idv);
if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
id = ((PointerRNA *)idv)->owner_id;
if (!id) {
- id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data);
+ id = static_cast<ID *>(((PointerRNA *)idv)->data);
}
}
else if (type == TSE_GP_LAYER) {
/* idv is the layer itself */
id = TREESTORE(parent)->id;
}
+ else if (ELEM(type, TSE_GENERIC_LABEL)) {
+ id = nullptr;
+ }
/* exceptions */
- if (type == TSE_ID_BASE) {
+ if (ELEM(type, TSE_ID_BASE, TSE_GENERIC_LABEL)) {
/* pass */
}
else if (id == nullptr) {
@@ -869,7 +861,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
/* pass */
}
- else if (type == TSE_ID_BASE) {
+ else if (ELEM(type, TSE_ID_BASE, TSE_GENERIC_LABEL)) {
/* pass */
}
else if (type == TSE_SOME_ID) {
@@ -877,7 +869,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert_msg(0, "Expected this ID type to be ported to new Outliner tree-element design");
}
}
- else if (ELEM(type, TSE_LIBRARY_OVERRIDE_BASE, TSE_LIBRARY_OVERRIDE)) {
+ else if (ELEM(type,
+ TSE_LIBRARY_OVERRIDE_BASE,
+ TSE_LIBRARY_OVERRIDE,
+ TSE_LIBRARY_OVERRIDE_OPERATION)) {
if (!te->abstract_element) {
BLI_assert_msg(0,
"Expected override types to be ported to new Outliner tree-element design");
@@ -895,10 +890,13 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (expand && te->abstract_element && te->abstract_element->isExpandValid()) {
+ if (!expand) {
+ /* Pass */
+ }
+ else if (te->abstract_element && te->abstract_element->isExpandValid()) {
tree_element_expand(*te->abstract_element, *space_outliner);
}
- else if (expand && (type == TSE_SOME_ID)) {
+ else if (type == TSE_SOME_ID) {
/* ID types not (fully) ported to new design yet. */
if (te->abstract_element->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
@@ -916,15 +914,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
TSE_RNA_ARRAY_ELEM,
TSE_SEQUENCE,
TSE_SEQ_STRIP,
- TSE_SEQUENCE_DUP)) {
+ TSE_SEQUENCE_DUP,
+ TSE_GENERIC_LABEL)) {
BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
}
return te;
}
-} // namespace blender::ed::outliner
-
/* ======================================================= */
BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
@@ -980,8 +977,8 @@ struct tTreeSort {
/* alphabetical comparator, trying to put objects first */
static int treesort_alpha_ob(const void *v1, const void *v2)
{
- const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
- const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
+ const tTreeSort *x1 = static_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = static_cast<const tTreeSort *>(v2);
/* first put objects last (hierarchy) */
int comp = (x1->idcode == ID_OB);
@@ -1019,8 +1016,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2)
/* Move children that are not in the collection to the end of the list. */
static int treesort_child_not_in_collection(const void *v1, const void *v2)
{
- const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
- const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
+ const tTreeSort *x1 = static_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = static_cast<const tTreeSort *>(v2);
/* Among objects first come the ones in the collection, followed by the ones not on it.
* This way we can have the dashed lines in a separate style connecting the former. */
@@ -1033,8 +1030,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2)
/* alphabetical comparator */
static int treesort_alpha(const void *v1, const void *v2)
{
- const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
- const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
+ const tTreeSort *x1 = static_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = static_cast<const tTreeSort *>(v2);
int comp = BLI_strcasecmp_natural(x1->name, x2->name);
@@ -1091,7 +1088,7 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
/* sort happens on each subtree individual */
static void outliner_sort(ListBase *lb)
{
- TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ TreeElement *last_te = static_cast<TreeElement *>(lb->last);
if (last_te == nullptr) {
return;
}
@@ -1103,7 +1100,7 @@ static void outliner_sort(ListBase *lb)
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ tTreeSort *tear = static_cast<tTreeSort *>(
MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
int skip = 0;
@@ -1159,7 +1156,7 @@ static void outliner_sort(ListBase *lb)
static void outliner_collections_children_sort(ListBase *lb)
{
- TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ TreeElement *last_te = static_cast<TreeElement *>(lb->last);
if (last_te == nullptr) {
return;
}
@@ -1170,7 +1167,7 @@ static void outliner_collections_children_sort(ListBase *lb)
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ tTreeSort *tear = static_cast<tTreeSort *>(
MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
@@ -1478,7 +1475,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
else {
BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
- if (base != BASACT(view_layer)) {
+ if (base != view_layer->basact) {
is_visible = false;
}
}
@@ -1541,8 +1538,7 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element,
if (outliner_element_is_collection_or_object(element)) {
TreeElement *te_prev = nullptr;
- for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te;
- te = te_prev) {
+ for (TreeElement *te = static_cast<TreeElement *>(element->subtree.last); te; te = te_prev) {
te_prev = te->prev;
if (!outliner_element_is_collection_or_object(te)) {
@@ -1569,7 +1565,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
TreeElement *te, *te_next;
TreeStoreElem *tselem;
- for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) {
+ for (te = static_cast<TreeElement *>(lb->first); te; te = te_next) {
te_next = te->next;
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
/* Don't free the tree, but extract the children from the parent and add to this tree. */
@@ -1675,10 +1671,9 @@ void outliner_build_tree(Main *mainvar,
space_outliner->search_flags &= ~SO_SEARCH_RECURSIVE;
}
- if (space_outliner->runtime->treehash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) &&
+ if (space_outliner->runtime->tree_hash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) &&
space_outliner->treestore) {
- BKE_outliner_treehash_rebuild_from_treestore(space_outliner->runtime->treehash,
- space_outliner->treestore);
+ space_outliner->runtime->tree_hash->rebuild_from_treestore(*space_outliner->treestore);
}
space_outliner->storeflag &= ~SO_TREESTORE_REBUILD;
@@ -1689,6 +1684,10 @@ void outliner_build_tree(Main *mainvar,
return;
}
+ /* Enable for benchmarking. Starts a timer, results will be printed on function exit. */
+ // SCOPED_TIMER("Outliner Rebuild");
+ // SCOPED_TIMER_AVERAGED("Outliner Rebuild");
+
OutlinerTreeElementFocus focus;
outliner_store_scrolling_position(space_outliner, region, &focus);
@@ -1724,3 +1723,5 @@ void outliner_build_tree(Main *mainvar,
}
/** \} */
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc
index 0db612ce6db..ff5292e2883 100644
--- a/source/blender/editors/space_outliner/outliner_utils.cc
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -18,7 +18,7 @@
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_object.h"
-#include "BKE_outliner_treehash.h"
+#include "BKE_outliner_treehash.hh"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -27,9 +27,10 @@
#include "UI_view2d.h"
#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
#include "tree/tree_iterator.hh"
-using namespace blender::ed::outliner;
+namespace blender::ed::outliner {
/* -------------------------------------------------------------------- */
/** \name Tree View Context
@@ -44,7 +45,7 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
tvc->view_layer = CTX_data_view_layer(C);
/* Objects. */
- tvc->obact = OBACT(tvc->view_layer);
+ tvc->obact = BKE_view_layer_active_object_get(tvc->view_layer);
if (tvc->obact != nullptr) {
tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact);
@@ -98,7 +99,7 @@ static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *
float view_co_x,
bool *r_is_merged_icon)
{
- TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first);
+ TreeElement *child_te = static_cast<TreeElement *>(parent_te->subtree.first);
while (child_te) {
const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
@@ -175,24 +176,6 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
return nullptr;
}
-TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse)
-{
- TreeStoreElem *tselem;
-
- if (tse->id == nullptr) {
- return nullptr;
- }
-
- /* Check if 'tse' is in tree-store. */
- tselem = BKE_outliner_treehash_lookup_any(
- space_outliner->runtime->treehash, tse->type, tse->nr, tse->id);
- if (tselem) {
- return outliner_find_tree_element(&space_outliner->tree, tselem);
- }
-
- return nullptr;
-}
-
TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -282,8 +265,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata)
{
- for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te;
- te = te_next) {
+ for (TreeElement *te = static_cast<TreeElement *>(tree->first), *te_next; te; te = te_next) {
TreeTraversalAction func_retval = TRAVERSE_CONTINUE;
/* in case te is freed in callback */
TreeStoreElem *tselem = TREESTORE(te);
@@ -455,7 +437,7 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space
ARegion *region)
{
/* Avoid rebuild if possible. */
- if (outliner_requires_rebuild_on_open_change(space_outliner)) {
+ if (space_outliner->runtime->tree_display->is_lazy_built()) {
ED_region_tag_redraw(region);
}
else {
@@ -463,6 +445,10 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space
}
}
+} // namespace blender::ed::outliner
+
+using namespace blender::ed::outliner;
+
Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
{
ARegion *region = CTX_wm_region(C);
diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc
index 5bcd1edebc0..76b7197b86a 100644
--- a/source/blender/editors/space_outliner/space_outliner.cc
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -16,7 +16,7 @@
#include "BKE_context.h"
#include "BKE_lib_remap.h"
-#include "BKE_outliner_treehash.h"
+#include "BKE_outliner_treehash.hh"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -37,16 +37,11 @@
#include "outliner_intern.hh"
#include "tree/tree_display.hh"
-SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/)
- : tree_display(nullptr), treehash(nullptr)
-{
-}
+namespace blender::ed::outliner {
-SpaceOutliner_Runtime::~SpaceOutliner_Runtime()
+SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/)
+ : tree_display(nullptr), tree_hash(nullptr)
{
- if (treehash) {
- BKE_outliner_treehash_free(treehash);
- }
}
static void outliner_main_region_init(wmWindowManager *wm, ARegion *region)
@@ -100,8 +95,8 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
{
ScrArea *area = params->area;
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
- SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
+ const wmNotifier *wmn = params->notifier;
+ SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first);
/* context changes */
switch (wmn->category) {
@@ -191,7 +186,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
}
break;
case NC_ID:
- if (ELEM(wmn->action, NA_RENAME, NA_ADDED)) {
+ if (ELEM(wmn->action, NA_RENAME, NA_ADDED, NA_REMOVED)) {
ED_region_tag_redraw(region);
}
break;
@@ -264,7 +259,7 @@ static void outliner_main_region_message_subscribe(const wmRegionMessageSubscrib
struct wmMsgBus *mbus = params->message_bus;
ScrArea *area = params->area;
ARegion *region = params->region;
- SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
+ SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
msg_sub_value_region_tag_redraw.owner = region;
@@ -296,7 +291,7 @@ static void outliner_header_region_free(ARegion *UNUSED(region))
static void outliner_header_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -361,7 +356,7 @@ static void outliner_free(SpaceLink *sl)
/* spacetype; init callback */
static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
+ SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first);
if (space_outliner->runtime == nullptr) {
space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime");
@@ -391,8 +386,6 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
- BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT);
-
if (!space_outliner->treestore) {
return;
}
@@ -420,7 +413,7 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe
/* Note that the Outliner may not be the active editor of the area, and hence not initialized.
* So runtime data might not have been created yet. */
- if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
+ if (space_outliner->runtime && space_outliner->runtime->tree_hash && changed) {
/* rebuild hash table, because it depends on ids too */
/* postpone a full rebuild because this can be called many times on-free */
space_outliner->storeflag |= SO_TREESTORE_REBUILD;
@@ -437,13 +430,17 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe
static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
- SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
+ SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first);
outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY, false);
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
+} // namespace blender::ed::outliner
+
void ED_spacetype_outliner(void)
{
+ using namespace blender::ed::outliner;
+
SpaceType *st = MEM_cnew<SpaceType>("spacetype time");
ARegionType *art;
diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc
index 349d36e2fe6..199c80f021a 100644
--- a/source/blender/editors/space_outliner/tree/common.cc
+++ b/source/blender/editors/space_outliner/tree/common.cc
@@ -21,6 +21,8 @@
#include "common.hh"
#include "tree_display.hh"
+namespace blender::ed::outliner {
+
/* -------------------------------------------------------------------- */
/** \name ID Helpers.
* \{ */
@@ -38,7 +40,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb)
{
/* build hierarchy */
/* XXX also, set extents here... */
- TreeElement *te = reinterpret_cast<TreeElement *>(lb->first);
+ TreeElement *te = static_cast<TreeElement *>(lb->first);
while (te) {
TreeElement *ten = te->next;
TreeStoreElem *tselem = TREESTORE(te);
@@ -63,3 +65,5 @@ bool outliner_animdata_test(const AnimData *adt)
}
return false;
}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/common.hh b/source/blender/editors/space_outliner/tree/common.hh
index 96c1eb34354..ba2d1c3fab6 100644
--- a/source/blender/editors/space_outliner/tree/common.hh
+++ b/source/blender/editors/space_outliner/tree/common.hh
@@ -8,7 +8,11 @@
struct ListBase;
+namespace blender::ed::outliner {
+
const char *outliner_idcode_to_plural(short idcode);
void outliner_make_object_parent_hierarchy(ListBase *lb);
bool outliner_animdata_test(const struct AnimData *adt);
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc
index 6ab497b3fbb..fe4937829d6 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display.cc
@@ -50,4 +50,9 @@ bool AbstractTreeDisplay::supportsModeColumn() const
return false;
}
+bool AbstractTreeDisplay::is_lazy_built() const
+{
+ return false;
+}
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 190e35c81d6..295eeb59eaa 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -30,11 +30,11 @@ struct Main;
struct Scene;
struct Sequence;
struct SpaceOutliner;
-struct TreeElement;
struct ViewLayer;
namespace blender::ed::outliner {
+struct TreeElement;
class TreeElementID;
/**
@@ -84,6 +84,15 @@ class AbstractTreeDisplay {
*/
virtual bool supportsModeColumn() const;
+ /**
+ * Some trees may want to skip building children of collapsed parents. This should be done if the
+ * tree type may become very complex, which could cause noticeable slowdowns.
+ * Problem: This doesn't address performance issues while searching, since all elements are
+ * constructed for that. Trees of this type have to be rebuilt for any change to the collapsed
+ * state of any element.
+ */
+ virtual bool is_lazy_built() const;
+
protected:
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
SpaceOutliner &space_outliner_;
@@ -157,11 +166,12 @@ class TreeDisplayOverrideLibraryHierarchies final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
+ bool is_lazy_built() const override;
+
private:
ListBase build_hierarchy_for_lib_or_main(Main *bmain,
TreeElement &parent_te,
Library *lib = nullptr);
- void build_hierarchy_for_ID(Main *bmain, ID &override_root_id, TreeElementID &te_id) const;
};
/* -------------------------------------------------------------------- */
@@ -233,6 +243,8 @@ class TreeDisplayDataAPI final : public AbstractTreeDisplay {
TreeDisplayDataAPI(SpaceOutliner &space_outliner);
ListBase buildTree(const TreeSourceData &source_data) override;
+
+ bool is_lazy_built() const override;
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc
index bfeb8ce2bdc..3d9b927fbf1 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc
@@ -42,4 +42,9 @@ ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data)
return tree;
}
+bool TreeDisplayDataAPI::is_lazy_built() const
+{
+ return true;
+}
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
index 67798e978ab..fa4479d0d9d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
@@ -4,25 +4,24 @@
* \ingroup spoutliner
*/
-#include "DNA_ID.h"
-#include "DNA_collection_types.h"
#include "DNA_key_types.h"
#include "DNA_space_types.h"
-#include "BLI_listbase.h"
+#include "BLI_function_ref.hh"
+#include "BLI_ghash.h"
#include "BLI_map.hh"
+
#include "BLI_set.hh"
#include "BLT_translation.h"
-#include "BKE_collection.h"
+#include "BKE_lib_override.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "../outliner_intern.hh"
#include "common.hh"
#include "tree_display.hh"
-#include "tree_element_id.hh"
namespace blender::ed::outliner {
@@ -42,8 +41,8 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &
TreeElement *current_file_te = outliner_add_element(
&space_outliner_, &tree, source_data.bmain, nullptr, TSE_ID_BASE, -1);
current_file_te->name = IFACE_("Current File");
+ AbstractTreeElement::uncollapse_by_default(current_file_te);
{
- AbstractTreeElement::uncollapse_by_default(current_file_te);
build_hierarchy_for_lib_or_main(source_data.bmain, *current_file_te);
/* Add dummy child if there's nothing to display. */
@@ -76,11 +75,57 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &
return tree;
}
+bool TreeDisplayOverrideLibraryHierarchies::is_lazy_built() const
+{
+ return true;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Library override hierarchy building
+ * \{ */
+
+class OverrideIDHierarchyBuilder {
+ SpaceOutliner &space_outliner_;
+ Main &bmain_;
+ MainIDRelations &id_relations_;
+
+ struct HierarchyBuildData {
+ const ID &override_root_id_;
+ /* The ancestor IDs leading to the current ID, to avoid IDs recursing into themselves. Changes
+ * with every level of recursion. */
+ Set<const ID *> parent_ids{};
+ /* The IDs that were already added to #parent_te, to avoid duplicates. Entirely new set with
+ * every level of recursion. */
+ Set<const ID *> sibling_ids{};
+ };
+
+ public:
+ OverrideIDHierarchyBuilder(SpaceOutliner &space_outliner,
+ Main &bmain,
+ MainIDRelations &id_relations)
+ : space_outliner_(space_outliner), bmain_(bmain), id_relations_(id_relations)
+ {
+ }
+
+ void build_hierarchy_for_ID(ID &root_id, TreeElement &te_to_expand);
+
+ private:
+ void build_hierarchy_for_ID_recursive(const ID &parent_id,
+ HierarchyBuildData &build_data,
+ TreeElement &te_to_expand);
+};
+
ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
Main *bmain, TreeElement &parent_te, Library *lib)
{
ListBase tree = {nullptr};
+ /* Ensure #Main.relations contains the latest mapping of relations. Must be freed before
+ * returning. */
+ BKE_main_relations_create(bmain, 0);
+
+ OverrideIDHierarchyBuilder builder(space_outliner_, *bmain, *bmain->relations);
+
/* Keep track over which ID base elements were already added, and expand them once added. */
Map<ID_Type, TreeElement *> id_base_te_map;
/* Index for the ID base elements ("Objects", "Materials", etc). */
@@ -109,108 +154,194 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
TreeElement *new_id_te = outliner_add_element(
&space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0, false);
- build_hierarchy_for_ID(bmain, *iter_id, *tree_element_cast<TreeElementID>(new_id_te));
+ builder.build_hierarchy_for_ID(*iter_id, *new_id_te);
}
FOREACH_MAIN_ID_END;
+ BKE_main_relations_free(bmain);
+
return tree;
}
-struct BuildHierarchyForeachIDCbData {
- /* Don't allow copies, the sets below would need deep copying. */
- BuildHierarchyForeachIDCbData(const BuildHierarchyForeachIDCbData &) = delete;
-
- Main &bmain;
- SpaceOutliner &space_outliner;
- ID &override_root_id;
-
- /* The tree element to expand. Changes with every level of recursion. */
- TreeElementID *parent_te;
- /* The ancestor IDs leading to the current ID, to avoid IDs recursing into themselves. Changes
- * with every level of recursion. */
- Set<ID *> parent_ids{};
- /* The IDs that were already added to #parent_te, to avoid duplicates. Entirely new set with
- * every level of recursion. */
- Set<ID *> sibling_ids{};
+void OverrideIDHierarchyBuilder::build_hierarchy_for_ID(ID &override_root_id,
+ TreeElement &te_to_expand)
+{
+ HierarchyBuildData build_data{override_root_id};
+ build_hierarchy_for_ID_recursive(override_root_id, build_data, te_to_expand);
+}
+
+enum ForeachChildReturn {
+ FOREACH_CONTINUE,
+ FOREACH_BREAK,
};
+/* Helpers (defined below). */
+static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations,
+ const ID &parent_id,
+ FunctionRef<ForeachChildReturn(ID &)> fn);
+static bool id_is_in_override_hierarchy(const Main &bmain,
+ const ID &id,
+ const ID &relationship_parent_id,
+ const ID &override_root_id);
+
+void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &parent_id,
+ HierarchyBuildData &build_data,
+ TreeElement &te_to_expand)
+{
+ /* In case this isn't added to the parents yet (does nothing if already there). */
+ build_data.parent_ids.add(&parent_id);
+
+ foreach_natural_hierarchy_child(id_relations_, parent_id, [&](ID &id) {
+ /* Some IDs can use themselves, early abort. */
+ if (&id == &parent_id) {
+ return FOREACH_CONTINUE;
+ }
+ if (!id_is_in_override_hierarchy(bmain_, id, parent_id, build_data.override_root_id_)) {
+ return FOREACH_CONTINUE;
+ }
+
+ /* Avoid endless recursion: If there is an ancestor for this ID already, it recurses into
+ * itself. */
+ if (build_data.parent_ids.lookup_key_default(&id, nullptr)) {
+ return FOREACH_CONTINUE;
+ }
+
+ /* Avoid duplicates: If there is a sibling for this ID already, the same ID is just used
+ * multiple times by the same parent. */
+ if (build_data.sibling_ids.lookup_key_default(&id, nullptr)) {
+ return FOREACH_CONTINUE;
+ }
+
+ /* We only want to add children whose parent isn't collapsed. Otherwise, in complex scenes with
+ * thousands of relationships, the building can slow down tremendously. Tag the parent to allow
+ * un-collapsing, but don't actually add the children. */
+ if (!TSELEM_OPEN(TREESTORE(&te_to_expand), &space_outliner_)) {
+ te_to_expand.flag |= TE_PRETEND_HAS_CHILDREN;
+ return FOREACH_BREAK;
+ }
+
+ TreeElement *new_te = outliner_add_element(
+ &space_outliner_, &te_to_expand.subtree, &id, &te_to_expand, TSE_SOME_ID, 0, false);
+
+ build_data.sibling_ids.add(&id);
+
+ /* Recurse into this ID. */
+ HierarchyBuildData child_build_data{build_data.override_root_id_};
+ child_build_data.parent_ids = build_data.parent_ids;
+ child_build_data.parent_ids.add(&id);
+ child_build_data.sibling_ids.reserve(10);
+ build_hierarchy_for_ID_recursive(id, child_build_data, *new_te);
-static int build_hierarchy_foreach_ID_cb(LibraryIDLinkCallbackData *cb_data)
+ return FOREACH_CONTINUE;
+ });
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helpers for library override hierarchy building
+ * \{ */
+
+/**
+ * Iterate over the IDs \a parent_id uses. E.g. the child collections and contained objects of a
+ * parent collection. Also does special handling for object parenting, so that:
+ * - When iterating over a child object, \a fn is executed for the parent instead.
+ * - When iterating over a parent object, \a fn is _additionally_ executed for all children. Given
+ * that the parent object isn't skipped, the caller has to ensure it's not added in the hierarchy
+ * twice.
+ * This allows us to build the hierarchy in the expected ("natural") order, where parent objects
+ * are actual parent elements in the hierarchy, even though in data, the relation goes the other
+ * way around (children point to or "use" the parent).
+ *
+ * Only handles regular object parenting, not cases like the "Child of" constraint. Other Outliner
+ * display modes don't show this as parent in the hierarchy either.
+ */
+static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations,
+ const ID &parent_id,
+ FunctionRef<ForeachChildReturn(ID &)> fn)
{
- if (!*cb_data->id_pointer) {
- return IDWALK_RET_NOP;
+ const MainIDRelationsEntry *relations_of_id = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(id_relations.relations_from_pointers, &parent_id));
+
+ /* Iterate over all IDs used by the parent ID (e.g. the child-collections of a collection). */
+ for (MainIDRelationsEntryItem *to_id_entry = relations_of_id->to_ids; to_id_entry;
+ to_id_entry = to_id_entry->next) {
+ /* An ID pointed to (used) by the ID to recurse into. */
+ ID &target_id = **to_id_entry->id_pointer.to;
+
+ /* Don't walk up the hierarchy, e.g. ignore pointers to parent collections. */
+ if (to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) {
+ continue;
+ }
+
+ /* Special case for objects: Process the parent object instead of the child object. Below the
+ * parent will add the child objects then. */
+ if (GS(target_id.name) == ID_OB) {
+ const Object &potential_child_ob = reinterpret_cast<const Object &>(target_id);
+ if (potential_child_ob.parent) {
+ if (fn(potential_child_ob.parent->id) == FOREACH_BREAK) {
+ return;
+ }
+ continue;
+ }
+ }
+
+ if (fn(target_id) == FOREACH_BREAK) {
+ return;
+ }
+ }
+
+ /* If the ID is an object, find and iterate over any child objects. */
+ if (GS(parent_id.name) == ID_OB) {
+ for (MainIDRelationsEntryItem *from_id_entry = relations_of_id->from_ids; from_id_entry;
+ from_id_entry = from_id_entry->next) {
+ ID &potential_child_id = *from_id_entry->id_pointer.from;
+
+ if (GS(potential_child_id.name) != ID_OB) {
+ continue;
+ }
+
+ const Object &potential_child_ob = reinterpret_cast<Object &>(potential_child_id);
+ if (!potential_child_ob.parent || &potential_child_ob.parent->id != &parent_id) {
+ continue;
+ }
+
+ if (fn(potential_child_id) == FOREACH_BREAK) {
+ return;
+ }
+ }
}
+}
- BuildHierarchyForeachIDCbData &build_data = *reinterpret_cast<BuildHierarchyForeachIDCbData *>(
- cb_data->user_data);
- /* Note that this may be an embedded ID (see #real_override_id). */
- ID &id = **cb_data->id_pointer;
+static bool id_is_in_override_hierarchy(const Main &bmain,
+ const ID &id,
+ const ID &relationship_parent_id,
+ const ID &override_root_id)
+{
/* If #id is an embedded ID, this will be set to the owner, which is a real ID and contains the
* override data. So queries of override data should be done via this, but the actual tree
* element we add is the embedded ID. */
const ID *real_override_id = &id;
if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(&id)) {
- if (GS(id.name) == ID_KE) {
- Key *key = (Key *)&id;
- real_override_id = key->from;
- }
- else if (id.flag & LIB_EMBEDDED_DATA) {
- /* TODO Needs double-checking if this handles all embedded IDs correctly. */
- real_override_id = cb_data->id_owner;
- }
+ /* In many cases, `relationship_parent_id` is the owner, but not always (e.g. there can be
+ * drivers directly between an object and a shapekey). */
+ BKE_lib_override_library_get(const_cast<Main *>(&bmain),
+ const_cast<ID *>(&id),
+ const_cast<ID *>(&relationship_parent_id),
+ const_cast<ID **>(&real_override_id));
}
if (!ID_IS_OVERRIDE_LIBRARY(real_override_id)) {
- return IDWALK_RET_NOP;
+ return false;
}
/* Is this ID part of the same override hierarchy? */
- if (real_override_id->override_library->hierarchy_root != &build_data.override_root_id) {
- return IDWALK_RET_NOP;
+ if (real_override_id->override_library->hierarchy_root != &override_root_id) {
+ return false;
}
- /* Avoid endless recursion: If there is an ancestor for this ID already, it recurses into itself.
- */
- if (build_data.parent_ids.lookup_key_default(&id, nullptr)) {
- return IDWALK_RET_NOP;
- }
-
- /* Avoid duplicates: If there is a sibling for this ID already, the same ID is just used multiple
- * times by the same parent. */
- if (build_data.sibling_ids.lookup_key_default(&id, nullptr)) {
- return IDWALK_RET_NOP;
- }
-
- TreeElement *new_te = outliner_add_element(&build_data.space_outliner,
- &build_data.parent_te->getLegacyElement().subtree,
- &id,
- &build_data.parent_te->getLegacyElement(),
- TSE_SOME_ID,
- 0,
- false);
- build_data.sibling_ids.add(&id);
-
- BuildHierarchyForeachIDCbData child_build_data{build_data.bmain,
- build_data.space_outliner,
- build_data.override_root_id,
- tree_element_cast<TreeElementID>(new_te)};
- child_build_data.parent_ids = build_data.parent_ids;
- child_build_data.parent_ids.add(&id);
- child_build_data.sibling_ids.reserve(10);
- BKE_library_foreach_ID_link(
- &build_data.bmain, &id, build_hierarchy_foreach_ID_cb, &child_build_data, IDWALK_READONLY);
-
- return IDWALK_RET_NOP;
+ return true;
}
-void TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_ID(Main *bmain,
- ID &override_root_id,
- TreeElementID &te_id) const
-{
- BuildHierarchyForeachIDCbData build_data{*bmain, space_outliner_, override_root_id, &te_id};
- build_data.parent_ids.add(&override_root_id);
-
- BKE_library_foreach_ID_link(
- bmain, &te_id.get_ID(), build_hierarchy_foreach_ID_cb, &build_data, IDWALK_READONLY);
-}
+/** \} */
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 94d55b70e3c..4a540c3ce87 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -4,6 +4,9 @@
* \ingroup spoutliner
*/
+#include <string>
+#include <string_view>
+
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
#include "DNA_space_types.h"
@@ -17,6 +20,7 @@
#include "tree_element_driver.hh"
#include "tree_element_gpencil_layer.hh"
#include "tree_element_id.hh"
+#include "tree_element_label.hh"
#include "tree_element_nla.hh"
#include "tree_element_overrides.hh"
#include "tree_element_rna.hh"
@@ -52,9 +56,11 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i
switch (type) {
case TSE_SOME_ID:
return TreeElementID::createFromID(legacy_te, *static_cast<ID *>(idv));
+ case TSE_GENERIC_LABEL:
+ return std::make_unique<TreeElementLabel>(legacy_te, static_cast<const char *>(idv));
case TSE_ANIM_DATA:
return std::make_unique<TreeElementAnimData>(legacy_te,
- *reinterpret_cast<IdAdtTemplate *>(idv)->adt);
+ *static_cast<IdAdtTemplate *>(idv)->adt);
case TSE_DRIVER_BASE:
return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA:
@@ -76,23 +82,24 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i
case TSE_LIBRARY_OVERRIDE:
return std::make_unique<TreeElementOverridesProperty>(
legacy_te, *static_cast<TreeElementOverridesData *>(idv));
+ case TSE_LIBRARY_OVERRIDE_OPERATION:
+ return std::make_unique<TreeElementOverridesPropertyOperation>(
+ legacy_te, *static_cast<TreeElementOverridesData *>(idv));
case TSE_RNA_STRUCT:
- return std::make_unique<TreeElementRNAStruct>(legacy_te,
- *reinterpret_cast<PointerRNA *>(idv));
+ return std::make_unique<TreeElementRNAStruct>(legacy_te, *static_cast<PointerRNA *>(idv));
case TSE_RNA_PROPERTY:
return std::make_unique<TreeElementRNAProperty>(
- legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ legacy_te, *static_cast<PointerRNA *>(idv), legacy_te.index);
case TSE_RNA_ARRAY_ELEM:
return std::make_unique<TreeElementRNAArrayElement>(
- legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ legacy_te, *static_cast<PointerRNA *>(idv), legacy_te.index);
case TSE_SEQUENCE:
- return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv));
+ return std::make_unique<TreeElementSequence>(legacy_te, *static_cast<Sequence *>(idv));
case TSE_SEQ_STRIP:
- return std::make_unique<TreeElementSequenceStrip>(legacy_te,
- *reinterpret_cast<Strip *>(idv));
+ return std::make_unique<TreeElementSequenceStrip>(legacy_te, *static_cast<Strip *>(idv));
case TSE_SEQUENCE_DUP:
- return std::make_unique<TreeElementSequenceStripDuplicate>(
- legacy_te, *reinterpret_cast<Sequence *>(idv));
+ return std::make_unique<TreeElementSequenceStripDuplicate>(legacy_te,
+ *static_cast<Sequence *>(idv));
default:
break;
}
@@ -105,6 +112,22 @@ StringRefNull AbstractTreeElement::getWarning() const
return "";
}
+std::optional<BIFIconID> AbstractTreeElement::getIcon() const
+{
+ return {};
+}
+
+void AbstractTreeElement::print_path()
+{
+ std::string path = legacy_te_.name;
+
+ for (TreeElement *parent = legacy_te_.parent; parent; parent = parent->parent) {
+ path = parent->name + std::string_view("/") + path;
+ }
+
+ std::cout << path << std::endl;
+}
+
void AbstractTreeElement::uncollapse_by_default(TreeElement *legacy_te)
{
if (!TREESTORE(legacy_te)->used) {
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 1098068d628..1b145a48daa 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -7,15 +7,18 @@
#pragma once
#include <memory>
+#include <optional>
#include "BLI_string_ref.hh"
+#include "UI_resources.h"
struct ListBase;
struct SpaceOutliner;
-struct TreeElement;
namespace blender::ed::outliner {
+struct TreeElement;
+
/* -------------------------------------------------------------------- */
/* Tree-Display Interface */
@@ -64,6 +67,25 @@ class AbstractTreeElement {
virtual StringRefNull getWarning() const;
/**
+ * Define the icon to be displayed for this element. If this returns an icon, this will be
+ * displayed. Otherwise, #tree_element_get_icon() may still determine an icon. By default no
+ * value is returned (#std::nullopt).
+ *
+ * All elements should be ported to use this over #tree_element_get_icon().
+ */
+ virtual std::optional<BIFIconID> getIcon() const;
+
+ /**
+ * Debugging helper: Print effective path of this tree element, constructed out of the
+ * #TreeElement.name of each element. E.g.:
+ * - Lorem
+ * - ipsum dolor sit
+ * - amet
+ * will print: Lorem/ipsum dolor sit/amet.
+ */
+ void print_path();
+
+ /**
* Expand this tree element if it is displayed for the first time (as identified by its
* tree-store element).
*
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh
index 956cf3dec48..f3372329dd1 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh
@@ -8,8 +8,6 @@
#include "tree_element.hh"
-struct TreeElement;
-
namespace blender::ed::outliner {
class TreeElementAnimData final : public AbstractTreeElement {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.hh b/source/blender/editors/space_outliner/tree/tree_element_driver.hh
index 053217e18ec..f0213dd39f2 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.hh
@@ -8,8 +8,6 @@
#include "tree_element.hh"
-struct TreeElement;
-
namespace blender::ed::outliner {
class TreeElementDriverBase final : public AbstractTreeElement {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_label.cc b/source/blender/editors/space_outliner/tree/tree_element_label.cc
new file mode 100644
index 00000000000..32fa62c5f5e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_label.cc
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "DNA_outliner_types.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_element_label.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementLabel::TreeElementLabel(TreeElement &legacy_te, const char *label)
+ : AbstractTreeElement(legacy_te), label_(label)
+{
+ BLI_assert(legacy_te_.store_elem->type == TSE_GENERIC_LABEL);
+ /* The draw string is actually accessed via #TreeElement.name, so make sure this always points to
+ * our string. */
+ legacy_te_.name = label_.c_str();
+}
+
+void TreeElementLabel::setIcon(const BIFIconID icon)
+{
+ icon_ = icon;
+}
+
+std::optional<BIFIconID> TreeElementLabel::getIcon() const
+{
+ return icon_;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_label.hh b/source/blender/editors/space_outliner/tree/tree_element_label.hh
new file mode 100644
index 00000000000..fc730c7b8f4
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_label.hh
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include <string>
+
+#include "UI_resources.h"
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+/**
+ * A basic, general purpose tree element to just display a label and an icon. Can be used to group
+ * together items underneath as well of course.
+ *
+ * Make sure to give this a unique index, so the element can be identified uniquely. Otherwise
+ * glitches like multiple highlighted elements happen, that share all state (e.g. collapsed,
+ * selected, etc.).
+ */
+class TreeElementLabel final : public AbstractTreeElement {
+ const std::string label_;
+ BIFIconID icon_ = ICON_NONE;
+
+ public:
+ TreeElementLabel(TreeElement &legacy_te, const char *label);
+
+ void setIcon(BIFIconID icon);
+ std::optional<BIFIconID> getIcon() const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 871de39b1dd..11067d37966 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -7,30 +7,60 @@
#include "BKE_collection.h"
#include "BKE_lib_override.h"
-#include "BLI_utildefines.h"
-
+#include "BLI_function_ref.hh"
#include "BLI_listbase_wrapper.hh"
+#include "BLI_map.hh"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "DNA_space_types.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "../outliner_intern.hh"
+#include "tree_element_label.hh"
#include "tree_element_overrides.hh"
namespace blender::ed::outliner {
+class OverrideRNAPathTreeBuilder {
+ SpaceOutliner &space_outliner_;
+ Map<std::string, TreeElement *> path_te_map;
+
+ public:
+ OverrideRNAPathTreeBuilder(SpaceOutliner &space_outliner);
+ void build_path(TreeElement &parent, TreeElementOverridesData &override_data, short &index);
+
+ private:
+ TreeElement &ensure_label_element_for_prop(
+ TreeElement &parent, StringRef elem_path, PointerRNA &ptr, PropertyRNA &prop, short &index);
+ TreeElement &ensure_label_element_for_ptr(TreeElement &parent,
+ StringRef elem_path,
+ PointerRNA &ptr,
+ short &index);
+ void ensure_entire_collection(TreeElement &te_to_expand,
+ const TreeElementOverridesData &override_data,
+ const char *coll_prop_path,
+ short &index);
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Base Element
+ *
+ * Represents an ID that has overridden properties. The expanding will invoke building of tree
+ * elements for the full RNA path of the property.
+ *
+ * \{ */
+
TreeElementOverridesBase::TreeElementOverridesBase(TreeElement &legacy_te, ID &id)
: AbstractTreeElement(legacy_te), id(id)
{
BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE_BASE);
if (legacy_te.parent != nullptr &&
- ELEM(legacy_te.parent->store_elem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))
-
- {
+ ELEM(legacy_te.parent->store_elem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
legacy_te.name = IFACE_("Library Overrides");
}
else {
@@ -51,21 +81,17 @@ StringRefNull TreeElementOverridesBase::getWarning() const
return {};
}
-void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
+static void iterate_properties_to_display(ID &id,
+ const bool show_system_overrides,
+ FunctionRef<void(TreeElementOverridesData &data)> fn)
{
- BLI_assert(id.override_library != nullptr);
+ PointerRNA override_rna_ptr;
+ PropertyRNA *override_rna_prop;
- const bool show_system_overrides = (SUPPORT_FILTER_OUTLINER(&space_outliner) &&
- (space_outliner.filter & SO_FILTER_SHOW_SYSTEM_OVERRIDES) !=
- 0);
PointerRNA idpoin;
RNA_id_pointer_create(&id, &idpoin);
- PointerRNA override_rna_ptr;
- PropertyRNA *override_rna_prop;
- short index = 0;
-
- for (auto *override_prop :
+ for (IDOverrideLibraryProperty *override_prop :
ListBaseWrapper<IDOverrideLibraryProperty>(id.override_library->properties)) {
int rnaprop_index = 0;
const bool is_rna_path_valid = BKE_lib_override_rna_property_find(
@@ -80,15 +106,13 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
/* Matching ID pointers are considered as system overrides. */
if (ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
- for (auto *override_prop_op :
+ for (IDOverrideLibraryPropertyOperation *override_prop_op :
ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
do_skip = false;
break;
}
- else {
- is_system_override = true;
- }
+ is_system_override = true;
}
}
@@ -105,11 +129,36 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
TreeElementOverridesData data = {
id, *override_prop, override_rna_ptr, *override_rna_prop, is_rna_path_valid};
- outliner_add_element(
- &space_outliner, &legacy_te_.subtree, &data, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++);
+
+ fn(data);
}
}
+void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
+{
+ BLI_assert(id.override_library != nullptr);
+
+ const bool show_system_overrides = (SUPPORT_FILTER_OUTLINER(&space_outliner) &&
+ (space_outliner.filter & SO_FILTER_SHOW_SYSTEM_OVERRIDES) !=
+ 0);
+
+ OverrideRNAPathTreeBuilder path_builder(space_outliner);
+ short index = 0;
+
+ iterate_properties_to_display(id, show_system_overrides, [&](TreeElementOverridesData &data) {
+ path_builder.build_path(legacy_te_, data, index);
+ });
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Overridden Property
+ *
+ * Represents an RNA property that was overridden.
+ *
+ * \{ */
+
TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_te,
TreeElementOverridesData &override_data)
: AbstractTreeElement(legacy_te),
@@ -118,9 +167,10 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t
rna_path(override_data.override_property.rna_path),
is_rna_path_valid(override_data.is_rna_path_valid)
{
- BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE);
+ BLI_assert(
+ ELEM(legacy_te.store_elem->type, TSE_LIBRARY_OVERRIDE, TSE_LIBRARY_OVERRIDE_OPERATION));
- legacy_te.name = override_data.override_property.rna_path;
+ legacy_te.name = RNA_property_ui_name(&override_data.override_rna_prop);
}
StringRefNull TreeElementOverridesProperty::getWarning() const
@@ -134,4 +184,305 @@ StringRefNull TreeElementOverridesProperty::getWarning() const
return {};
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Overridden Property Operation
+ *
+ * See #TreeElementOverridesPropertyOperation.
+ * \{ */
+
+TreeElementOverridesPropertyOperation::TreeElementOverridesPropertyOperation(
+ TreeElement &legacy_te, TreeElementOverridesData &override_data)
+ : TreeElementOverridesProperty(legacy_te, override_data)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE_OPERATION);
+ BLI_assert_msg(RNA_property_type(&override_rna_prop) == PROP_COLLECTION,
+ "Override operations are only supported for collections right now");
+ /* Quiet Clang Static Analyzer warning by throwing instead of asserting (possible
+ * null-dereference). */
+ if (!override_data.operation) {
+ throw std::invalid_argument("missing operation");
+ }
+
+ operation_ = std::make_unique<IDOverrideLibraryPropertyOperation>(*override_data.operation);
+ /* Just for extra sanity. */
+ operation_->next = operation_->prev = nullptr;
+
+ if (std::optional<PointerRNA> col_item_ptr = get_collection_ptr()) {
+ const char *dyn_name = RNA_struct_name_get_alloc(&*col_item_ptr, nullptr, 0, nullptr);
+ if (dyn_name) {
+ legacy_te.name = dyn_name;
+ legacy_te.flag |= TE_FREE_NAME;
+ }
+ else {
+ legacy_te.name = RNA_struct_ui_name(col_item_ptr->type);
+ }
+ }
+}
+
+StringRefNull TreeElementOverridesPropertyOperation::getOverrideOperationLabel() const
+{
+ if (ELEM(operation_->operation,
+ IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
+ IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) {
+ return TIP_("Added through override");
+ }
+
+ BLI_assert_unreachable();
+ return {};
+}
+
+std::optional<BIFIconID> TreeElementOverridesPropertyOperation::getIcon() const
+{
+ if (const std::optional<PointerRNA> col_item_ptr = get_collection_ptr()) {
+ return (BIFIconID)RNA_struct_ui_icon(col_item_ptr->type);
+ }
+
+ return {};
+}
+
+std::optional<PointerRNA> TreeElementOverridesPropertyOperation::get_collection_ptr() const
+{
+ PointerRNA col_item_ptr;
+ if (RNA_property_collection_lookup_int(const_cast<PointerRNA *>(&override_rna_ptr),
+ &override_rna_prop,
+ operation_->subitem_local_index,
+ &col_item_ptr)) {
+ return col_item_ptr;
+ }
+
+ return {};
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper to build a hierarchy from an RNA path.
+ *
+ * Builds a nice hierarchy representing the nested structs of the override property's RNA path
+ * using UI names and icons. For example `animation_visualization_mothion_path.frame_end` becomes:
+ * - Animation Visualization
+ * - Motion Paths
+ * - End Frame
+ *
+ * Paths are merged so that each RNA sub-path is only represented once in the tree. So there is
+ * some finicky path building going on to create a path -> tree-element map.
+ *
+ * This is more complicated than you'd think it needs to be. Mostly because of RNA collection
+ * overrides:
+ * - A single override may add (and in future remove) multiple collection items. So all operations
+ * of the override have to be considered.
+ * - The order of collection items may matter (e.g. for modifiers), so if collection items are
+ * added/removed, we want to show all other collection items too, in the right order.
+ *
+ * - If the override is inside some collection item, the collection item has to be built, but the
+ * RNA path iterator doesn't
+ * \{ */
+
+OverrideRNAPathTreeBuilder::OverrideRNAPathTreeBuilder(SpaceOutliner &space_outliner)
+ : space_outliner_(space_outliner)
+{
+}
+
+void OverrideRNAPathTreeBuilder::build_path(TreeElement &parent,
+ TreeElementOverridesData &override_data,
+ short &index)
+{
+ PointerRNA idpoin;
+ RNA_id_pointer_create(&override_data.id, &idpoin);
+
+ ListBase path_elems = {nullptr};
+ if (!RNA_path_resolve_elements(&idpoin, override_data.override_property.rna_path, &path_elems)) {
+ return;
+ }
+
+ const char *elem_path = nullptr;
+ TreeElement *te_to_expand = &parent;
+
+ LISTBASE_FOREACH (PropertyElemRNA *, elem, &path_elems) {
+ if (!elem->next) {
+ /* The last element is added as #TSE_LIBRARY_OVERRIDE below. */
+ break;
+ }
+ const char *previous_path = elem_path;
+ const char *new_path = RNA_path_append(previous_path, &elem->ptr, elem->prop, -1, nullptr);
+
+ te_to_expand = &ensure_label_element_for_prop(
+ *te_to_expand, new_path, elem->ptr, *elem->prop, index);
+
+ /* Above the collection property was added (e.g. "Modifiers"), to get the actual collection
+ * item the path refers to, we have to peek at the following path element and add a tree
+ * element for its pointer (e.g. "My Subdiv Modifier"). */
+ if (RNA_property_type(elem->prop) == PROP_COLLECTION) {
+ const int coll_item_idx = RNA_property_collection_lookup_index(
+ &elem->ptr, elem->prop, &elem->next->ptr);
+ const char *coll_item_path = RNA_path_append(
+ previous_path, &elem->ptr, elem->prop, coll_item_idx, nullptr);
+
+ te_to_expand = &ensure_label_element_for_ptr(
+ *te_to_expand, coll_item_path, elem->next->ptr, index);
+
+ MEM_delete(new_path);
+ new_path = coll_item_path;
+ }
+
+ if (new_path) {
+ MEM_delete(elem_path);
+ elem_path = new_path;
+ }
+ }
+ BLI_freelistN(&path_elems);
+
+ /* Special case: Overriding collections, e.g. adding or removing items. In this case we add
+ * elements for all collection items to show full context, and indicate which ones were
+ * added/removed (currently added only). Note that a single collection override may add/remove
+ * multiple items. */
+ if (RNA_property_type(&override_data.override_rna_prop) == PROP_COLLECTION) {
+ /* Tree element for the actual collection item (e.g. "Modifiers"). Can just use the override
+ * ptr & prop here, since they point to the collection property (e.g. `modifiers`). */
+ te_to_expand = &ensure_label_element_for_prop(*te_to_expand,
+ override_data.override_property.rna_path,
+ override_data.override_rna_ptr,
+ override_data.override_rna_prop,
+ index);
+
+ ensure_entire_collection(*te_to_expand, override_data, elem_path, index);
+ }
+ /* Some properties have multiple operations (e.g. an array property with multiple changed
+ * values), so the element may already be present. At this point they are displayed as a single
+ * property in the tree, so don't add it multiple times here. */
+ else if (!path_te_map.contains(override_data.override_property.rna_path)) {
+ outliner_add_element(&space_outliner_,
+ &te_to_expand->subtree,
+ &override_data,
+ te_to_expand,
+ TSE_LIBRARY_OVERRIDE,
+ index++);
+ }
+
+ MEM_delete(elem_path);
+}
+
+void OverrideRNAPathTreeBuilder::ensure_entire_collection(
+ TreeElement &te_to_expand,
+ const TreeElementOverridesData &override_data,
+ /* The path of the owning collection property. */
+ const char *coll_prop_path,
+ short &index)
+{
+ BLI_assert(tree_element_cast<AbstractTreeElement>(&te_to_expand) != nullptr);
+
+ TreeElement *previous_te = nullptr;
+ int item_idx = 0;
+ RNA_PROP_BEGIN (&override_data.override_rna_ptr, itemptr, &override_data.override_rna_prop) {
+ const char *coll_item_path = RNA_path_append(coll_prop_path,
+ &override_data.override_rna_ptr,
+ &override_data.override_rna_prop,
+ item_idx,
+ nullptr);
+ IDOverrideLibraryPropertyOperation *item_operation =
+ BKE_lib_override_library_property_operation_find(
+ &override_data.override_property, nullptr, nullptr, -1, item_idx, false, nullptr);
+ TreeElement *current_te = nullptr;
+
+ TreeElement *existing_te = path_te_map.lookup_default(coll_item_path, nullptr);
+
+ if (existing_te) {
+ /* Reinsert the element to make sure the order is right. It may have been inserted by a
+ * previous override. */
+ BLI_remlink(&te_to_expand.subtree, existing_te);
+ BLI_insertlinkafter(&te_to_expand.subtree, previous_te, existing_te);
+ current_te = existing_te;
+ }
+ /* Is there an operation for this item (added or removed the item to/from the collection)? If
+ * so indicate it as override using #TSE_LIBRARY_OVERRIDE_OPERATION. Otherwise it's just a
+ * regular collection we display for context. */
+ else if (item_operation) {
+ TreeElementOverridesData override_op_data = override_data;
+ override_op_data.operation = item_operation;
+
+ current_te = outliner_add_element(&space_outliner_,
+ &te_to_expand.subtree,
+ /* Element will store a copy. */
+ &override_op_data,
+ &te_to_expand,
+ TSE_LIBRARY_OVERRIDE_OPERATION,
+ index++);
+ }
+ else {
+ current_te = &ensure_label_element_for_ptr(te_to_expand, coll_item_path, itemptr, index);
+ }
+
+ MEM_delete(coll_item_path);
+ item_idx++;
+ previous_te = current_te;
+ }
+ RNA_PROP_END;
+}
+
+static BIFIconID get_property_icon(PointerRNA &ptr, PropertyRNA &prop)
+{
+ BIFIconID icon = (BIFIconID)RNA_property_ui_icon(&prop);
+ if (icon) {
+ return icon;
+ }
+
+ /* Try if the collection item type has a dedicated icon (e.g. #ICON_MODIFIER for the
+ * #Object.modifiers property). */
+ if (RNA_property_type(&prop) == PROP_COLLECTION) {
+ const StructRNA *coll_ptr_type = RNA_property_pointer_type(&ptr, &prop);
+ icon = (BIFIconID)RNA_struct_ui_icon(coll_ptr_type);
+ if (icon != ICON_DOT) {
+ return icon;
+ }
+ }
+
+ return ICON_NONE;
+}
+
+TreeElement &OverrideRNAPathTreeBuilder::ensure_label_element_for_prop(
+ TreeElement &parent, StringRef elem_path, PointerRNA &ptr, PropertyRNA &prop, short &index)
+{
+ return *path_te_map.lookup_or_add_cb(elem_path, [&]() {
+ TreeElement *new_te = outliner_add_element(&space_outliner_,
+ &parent.subtree,
+ (void *)RNA_property_ui_name(&prop),
+ &parent,
+ TSE_GENERIC_LABEL,
+ index++,
+ false);
+ TreeElementLabel *te_label = tree_element_cast<TreeElementLabel>(new_te);
+
+ te_label->setIcon(get_property_icon(ptr, prop));
+ return new_te;
+ });
+}
+
+TreeElement &OverrideRNAPathTreeBuilder::ensure_label_element_for_ptr(TreeElement &parent,
+ StringRef elem_path,
+ PointerRNA &ptr,
+ short &index)
+{
+ return *path_te_map.lookup_or_add_cb(elem_path, [&]() {
+ const char *dyn_name = RNA_struct_name_get_alloc(&ptr, nullptr, 0, nullptr);
+
+ TreeElement *new_te = outliner_add_element(
+ &space_outliner_,
+ &parent.subtree,
+ (void *)(dyn_name ? dyn_name : RNA_struct_ui_name(ptr.type)),
+ &parent,
+ TSE_GENERIC_LABEL,
+ index++);
+ TreeElementLabel *te_label = tree_element_cast<TreeElementLabel>(new_te);
+ te_label->setIcon((BIFIconID)RNA_struct_ui_icon(ptr.type));
+
+ MEM_delete(dyn_name);
+
+ return new_te;
+ });
+}
+
+/** \} */
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
index 1db46d9af1d..f8ca146a4ea 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -14,6 +14,7 @@
struct ID;
struct IDOverrideLibraryProperty;
+struct IDOverrideLibraryPropertyOperation;
namespace blender::ed::outliner {
@@ -24,6 +25,11 @@ struct TreeElementOverridesData {
PropertyRNA &override_rna_prop;
bool is_rna_path_valid;
+
+ /* In case the property references a specific operation. Only used for collection overrides
+ * currently, where a single override may add/remove multiple collection items (only add
+ * currently). */
+ IDOverrideLibraryPropertyOperation *operation = nullptr;
};
class TreeElementOverridesBase final : public AbstractTreeElement {
@@ -38,7 +44,12 @@ class TreeElementOverridesBase final : public AbstractTreeElement {
StringRefNull getWarning() const override;
};
-class TreeElementOverridesProperty final : public AbstractTreeElement {
+/**
+ * Represent a single overridden property. Collection properties may support multiple override
+ * operations, e.g. to insert/remove multiple collection items. For these multiple operation cases,
+ * use #TreeElementOverridesPropertyOperation.
+ */
+class TreeElementOverridesProperty : public AbstractTreeElement {
public:
PointerRNA override_rna_ptr;
PropertyRNA &override_rna_prop;
@@ -50,6 +61,33 @@ class TreeElementOverridesProperty final : public AbstractTreeElement {
TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
StringRefNull getWarning() const override;
+
+ bool isCollectionOperation() const;
+};
+
+/**
+ * Represent a single operation within an overridden property. While usually a single override
+ * property represents a single operation (changing the value), a single overridden collection
+ * property may have multiple operations, e.g. to insert or remove collection items.
+ *
+ * Inherits from the override property class since it should look/behave mostly the same.
+ */
+class TreeElementOverridesPropertyOperation final : public TreeElementOverridesProperty {
+ /** See #TreeElementOverridesData::operation. Operations are recreated as part of the diffing
+ * (e.g. on undo pushes) so store a copy of the data here. */
+ std::unique_ptr<IDOverrideLibraryPropertyOperation> operation_;
+
+ public:
+ TreeElementOverridesPropertyOperation(TreeElement &legacy_te,
+ TreeElementOverridesData &override_data);
+
+ /** Return a short string to display in the right column of the properties mode, indicating what
+ * the override operation did (e.g. added or removed a collection item). */
+ StringRefNull getOverrideOperationLabel() const;
+ std::optional<BIFIconID> getIcon() const override;
+
+ private:
+ std::optional<PointerRNA> get_collection_ptr() const;
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
index 914104f1f06..9e1f22b49d6 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
@@ -117,14 +117,14 @@ void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const
for (int index = 0; index < tot; index++) {
PointerRNA propptr;
RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr);
- if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
+ if (!(RNA_property_flag(static_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
outliner_add_element(
&space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index);
}
}
}
else if (tot) {
- legacy_te_.flag |= TE_LAZY_CLOSED;
+ legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
}
}
@@ -146,7 +146,7 @@ TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te,
PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type);
RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr);
- PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data);
+ PropertyRNA *prop = static_cast<PropertyRNA *>(propptr.data);
legacy_te_.name = RNA_property_ui_name(prop);
rna_prop_ = prop;
@@ -172,7 +172,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
&space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1);
}
else {
- legacy_te_.flag |= TE_LAZY_CLOSED;
+ legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
}
}
}
@@ -189,7 +189,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
}
}
else if (tot) {
- legacy_te_.flag |= TE_LAZY_CLOSED;
+ legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
}
}
else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
@@ -207,7 +207,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
}
}
else if (tot) {
- legacy_te_.flag |= TE_LAZY_CLOSED;
+ legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN;
}
}
}
@@ -232,8 +232,7 @@ TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te,
char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index);
- legacy_te_.name = reinterpret_cast<char *>(
- MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
+ legacy_te_.name = static_cast<char *>(MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
if (c) {
sprintf((char *)legacy_te_.name, " %c", c);
}
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh
index de5bcd2c462..0c94c2f95cf 100644
--- a/source/blender/editors/space_outliner/tree/tree_iterator.hh
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh
@@ -10,9 +10,11 @@
struct ListBase;
struct SpaceOutliner;
-struct TreeElement;
namespace blender::ed::outliner {
+
+struct TreeElement;
+
namespace tree_iterator {
using VisitorFn = FunctionRef<void(TreeElement *)>;
diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt
index 8486fa0e872..f7fc4e38c17 100644
--- a/source/blender/editors/space_script/CMakeLists.txt
+++ b/source/blender/editors/space_script/CMakeLists.txt
@@ -8,7 +8,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index e8c7590c1fe..a32c8a3f85a 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -100,7 +100,7 @@ static int script_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* TODO(campbell): this crashes on netrender and keying sets, need to look into why
+ /* TODO(@campbellbarton): this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode. */
/* It would be nice if we could detect when this is called from the Python
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 44f919ca361..deaec0136c4 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -15,7 +15,6 @@ set(INC
../../sequencer
../../windowmanager
../../../../intern/atomic
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 647d13a4d56..dd6d58ee5a2 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -85,6 +85,7 @@ typedef struct SequencerAddData {
#define SEQPROP_NOCHAN (1 << 3)
#define SEQPROP_FIT_METHOD (1 << 4)
#define SEQPROP_VIEW_TRANSFORM (1 << 5)
+#define SEQPROP_PLAYBACK_RATE (1 << 6)
static const EnumPropertyItem scale_fit_methods[] = {
{SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"},
@@ -158,6 +159,14 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
"Set View Transform",
"Set appropriate view transform based on media color space");
}
+
+ if (flag & SEQPROP_PLAYBACK_RATE) {
+ ot->prop = RNA_def_boolean(ot->srna,
+ "adjust_playback_rate",
+ true,
+ "Adjust Playback Rate",
+ "Play at normal speed regardless of scene FPS");
+ }
}
static void sequencer_generic_invoke_path__internal(bContext *C,
@@ -183,7 +192,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
Sequence *seq;
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_ensure(scene);
- int timeline_frame = (int)CFRA;
+ int timeline_frame = (int)scene->r.cfra;
int proximity = INT_MAX;
if (!ed || !ed->seqbasep) {
@@ -191,7 +200,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- const int strip_end = SEQ_time_right_handle_frame_get(seq);
+ const int strip_end = SEQ_time_right_handle_frame_get(scene, seq);
if ((ELEM(type, -1, seq->type)) && (strip_end < timeline_frame) &&
(timeline_frame - strip_end < proximity)) {
tgt = seq;
@@ -209,7 +218,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i
{
Scene *scene = CTX_data_scene(C);
- int timeline_frame = (int)CFRA;
+ int timeline_frame = (int)scene->r.cfra;
/* Effect strips don't need a channel initialized from the mouse. */
if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) {
@@ -250,6 +259,10 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm
SEQ_tool_settings_fit_method_set(CTX_data_scene(C), load_data->fit_method);
}
+ if ((prop = RNA_struct_find_property(op->ptr, "adjust_playback_rate"))) {
+ load_data->adjust_playback_rate = RNA_boolean_get(op->ptr, "adjust_playback_rate");
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
RNA_property_string_get(op->ptr, prop, load_data->path);
BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name));
@@ -327,7 +340,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence
}
if (RNA_boolean_get(op->ptr, "overlap") == true ||
- !SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ !SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
/* No overlap should be handled or the strip is not overlapping, exit early. */
return;
}
@@ -370,7 +383,7 @@ static bool seq_load_apply_generic_options_only_test_overlap(bContext *C,
SEQ_collection_append_strip(seq, strip_col);
- return SEQ_transform_test_overlap(ed->seqbasep, seq);
+ return SEQ_transform_test_overlap(scene, ed->seqbasep, seq);
}
static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
@@ -793,8 +806,10 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
return;
}
- SEQ_time_right_handle_frame_set(scene, seq_sound, SEQ_time_right_handle_frame_get(seq_movie));
- SEQ_time_left_handle_frame_set(scene, seq_sound, SEQ_time_left_handle_frame_get(seq_movie));
+ SEQ_time_right_handle_frame_set(
+ scene, seq_sound, SEQ_time_right_handle_frame_get(scene, seq_movie));
+ SEQ_time_left_handle_frame_set(
+ scene, seq_sound, SEQ_time_left_handle_frame_get(scene, seq_movie));
}
static void sequencer_add_movie_multiple_strips(bContext *C,
@@ -841,8 +856,8 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
}
}
- load_data->start_frame += SEQ_time_right_handle_frame_get(seq_movie) -
- SEQ_time_left_handle_frame_get(seq_movie);
+ load_data->start_frame += SEQ_time_right_handle_frame_get(scene, seq_movie) -
+ SEQ_time_left_handle_frame_get(scene, seq_movie);
if (overlap_shuffle_override) {
has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap(
C, op, seq_sound, strip_col);
@@ -976,6 +991,7 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
sequencer_disable_one_time_properties(C, op);
RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene));
+ RNA_boolean_set(op->ptr, "adjust_playback_rate", true);
/* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") &&
@@ -1042,8 +1058,9 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- sequencer_generic_props__internal(
- ot, SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD | SEQPROP_VIEW_TRANSFORM);
+ sequencer_generic_props__internal(ot,
+ SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD |
+ SEQPROP_VIEW_TRANSFORM | SEQPROP_PLAYBACK_RATE);
RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie");
RNA_def_boolean(ot->srna,
"use_framerate",
@@ -1073,8 +1090,8 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
}
else {
seq_load_apply_generic_options(C, op, seq);
- load_data->start_frame += SEQ_time_right_handle_frame_get(seq) -
- SEQ_time_left_handle_frame_get(seq);
+ load_data->start_frame += SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq);
}
}
RNA_END;
@@ -1250,8 +1267,12 @@ static int sequencer_add_image_strip_calculate_length(wmOperator *op,
return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
}
-static void sequencer_add_image_strip_load_files(
- wmOperator *op, Sequence *seq, SeqLoadData *load_data, const int minframe, const int numdigits)
+static void sequencer_add_image_strip_load_files(wmOperator *op,
+ Scene *scene,
+ Sequence *seq,
+ SeqLoadData *load_data,
+ const int minframe,
+ const int numdigits)
{
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
/* size of Strip->dir. */
@@ -1267,7 +1288,7 @@ static void sequencer_add_image_strip_load_files(
size_t strip_frame = 0;
RNA_BEGIN (op->ptr, itemptr, "files") {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
- SEQ_add_image_load_file(seq, strip_frame, filename);
+ SEQ_add_image_load_file(scene, seq, strip_frame, filename);
MEM_freeN(filename);
strip_frame++;
}
@@ -1296,7 +1317,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
}
Sequence *seq = SEQ_add_image_strip(CTX_data_main(C), scene, ed->seqbasep, &load_data);
- sequencer_add_image_strip_load_files(op, seq, &load_data, minframe, numdigits);
+ sequencer_add_image_strip_load_files(op, scene, seq, &load_data, minframe, numdigits);
SEQ_add_image_init_alpha_mode(seq);
/* Adjust length. */
diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
index c11388e8555..81fc87598f8 100644
--- a/source/blender/editors/space_sequencer/sequencer_channels_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
@@ -97,7 +97,7 @@ static void displayed_channel_range_get(const SeqChannelDrawContext *context,
rctf strip_boundbox;
BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, r_channel_range[1]);
- SEQ_timeline_expand_boundbox(context->seqbase, &strip_boundbox);
+ SEQ_timeline_expand_boundbox(context->scene, context->seqbase, &strip_boundbox);
CLAMP(r_channel_range[0], strip_boundbox.ymin, strip_boundbox.ymax);
CLAMP(r_channel_range[1], strip_boundbox.ymin, MAXSEQ);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c
index 8dadb9360e3..c892e7d7e55 100644
--- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c
+++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c
@@ -51,7 +51,9 @@
typedef struct SeqDropCoords {
float start_frame, channel;
int strip_len, channel_len;
+ float playback_rate;
bool in_use;
+ bool has_read_mouse_pos;
bool is_intersecting;
bool use_snapping;
float snap_point_x;
@@ -63,7 +65,7 @@ typedef struct SeqDropCoords {
* preloading data on drag start.
* Therefore we will for now use a global variable for this.
*/
-static SeqDropCoords g_drop_coords = {.in_use = false};
+static SeqDropCoords g_drop_coords = {.in_use = false, .has_read_mouse_pos = false};
static void generic_poll_operations(const wmEvent *event, uint8_t type)
{
@@ -82,31 +84,134 @@ static bool image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *ev
}
}
- return WM_drag_is_ID_type(drag, ID_IM);
+ if (WM_drag_is_ID_type(drag, ID_IM)) {
+ generic_poll_operations(event, TH_SEQ_IMAGE);
+ return true;
+ }
+
+ return false;
}
-static bool movie_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event)
+static bool is_movie(wmDrag *drag)
{
if (drag->type == WM_DRAG_PATH) {
- if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */
- generic_poll_operations(event, TH_SEQ_MOVIE);
+ if (ELEM(drag->icon, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */
return true;
}
}
+ if (WM_drag_is_ID_type(drag, ID_MC)) {
+ return true;
+ }
+ return false;
+}
+
+static bool movie_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event)
+{
+ if (is_movie(drag)) {
+ generic_poll_operations(event, TH_SEQ_MOVIE);
+ return true;
+ }
- return WM_drag_is_ID_type(drag, ID_MC);
+ return false;
}
-static bool sound_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event)
+static bool is_sound(wmDrag *drag)
{
if (drag->type == WM_DRAG_PATH) {
if (ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { /* Rule might not work? */
- generic_poll_operations(event, TH_SEQ_AUDIO);
return true;
}
}
+ if (WM_drag_is_ID_type(drag, ID_SO)) {
+ return true;
+ }
+ return false;
+}
- return WM_drag_is_ID_type(drag, ID_SO);
+static bool sound_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event)
+{
+ if (is_sound(drag)) {
+ generic_poll_operations(event, TH_SEQ_AUDIO);
+ return true;
+ }
+
+ return false;
+}
+
+static float update_overlay_strip_position_data(bContext *C, const int mval[2])
+{
+ SeqDropCoords *coords = &g_drop_coords;
+ ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ int hand;
+ View2D *v2d = &region->v2d;
+
+ /* Update the position were we would place the strip if we complete the drag and drop action.
+ */
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &coords->start_frame, &coords->channel);
+ coords->start_frame = roundf(coords->start_frame);
+ if (coords->channel < 1.0f) {
+ coords->channel = 1;
+ }
+
+ float start_frame = coords->start_frame;
+ float end_frame;
+ float strip_len;
+
+ if (coords->playback_rate != 0.0f) {
+ float scene_playback_rate = (float)scene->r.frs_sec / scene->r.frs_sec_base;
+ strip_len = coords->strip_len / (coords->playback_rate / scene_playback_rate);
+ }
+ else {
+ strip_len = coords->strip_len;
+ }
+
+ end_frame = coords->start_frame + strip_len;
+
+ if (coords->use_snapping) {
+ /* Do snapping via the existing transform code. */
+ int snap_delta;
+ float snap_frame;
+ bool valid_snap;
+
+ valid_snap = ED_transform_snap_sequencer_to_closest_strip_calc(
+ scene, region, start_frame, end_frame, &snap_delta, &snap_frame);
+
+ if (valid_snap) {
+ /* We snapped onto something! */
+ start_frame += snap_delta;
+ coords->start_frame = start_frame;
+ end_frame = start_frame + strip_len;
+ coords->snap_point_x = snap_frame;
+ }
+ else {
+ /* Nothing was snapped to, disable snap drawing. */
+ coords->use_snapping = false;
+ }
+ }
+
+ if (strip_len < 1) {
+ /* Only check if there is a strip already under the mouse cursor. */
+ coords->is_intersecting = find_nearest_seq(scene, &region->v2d, &hand, mval);
+ }
+ else {
+ /* Check if there is a strip that would intersect with the new strip(s). */
+ coords->is_intersecting = false;
+ Sequence dummy_seq = {.machine = coords->channel,
+ .start = coords->start_frame,
+ .len = coords->strip_len,
+ .speed_factor = 1.0f,
+ .media_playback_rate = coords->playback_rate,
+ .flag = SEQ_AUTO_PLAYBACK_RATE};
+ Editing *ed = SEQ_editing_ensure(scene);
+
+ for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) {
+ coords->is_intersecting = SEQ_transform_test_overlap(scene, ed->seqbasep, &dummy_seq);
+ dummy_seq.machine++;
+ }
+ }
+
+ return strip_len;
}
static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
@@ -153,92 +258,77 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
RNA_collection_add(drop->ptr, "files", &itemptr);
RNA_string_set(&itemptr, "name", file);
}
-
- if (g_drop_coords.in_use) {
- RNA_int_set(drop->ptr, "frame_start", g_drop_coords.start_frame);
- RNA_int_set(drop->ptr, "channel", g_drop_coords.channel);
- RNA_boolean_set(drop->ptr, "overlap_shuffle_override", true);
- }
- else {
- Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_active_seqbase_get(ed);
- ListBase *channels = SEQ_channels_displayed_get(ed);
- SpaceSeq *sseq = CTX_wm_space_seq(C);
-
- SeqCollection *strips = SEQ_query_rendered_strips(
- channels, seqbase, scene->r.cfra, sseq->chanshown);
-
- /* Get the top most strip channel that is in view.*/
- Sequence *seq;
- int max_channel = -1;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- max_channel = max_ii(seq->machine, max_channel);
- }
-
- if (max_channel != -1) {
- RNA_int_set(drop->ptr, "channel", max_channel);
- }
- }
}
-}
-static void update_overlay_strip_poistion_data(bContext *C, const int mval[2])
-{
- SeqDropCoords *coords = &g_drop_coords;
- ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- int hand;
- View2D *v2d = &region->v2d;
+ if (g_drop_coords.in_use) {
+ if (!g_drop_coords.has_read_mouse_pos) {
+ /* We didn't read the mouse position, so we need to do it manually here. */
+ int xy[2];
+ wmWindow *win = CTX_wm_window(C);
+ xy[0] = win->eventstate->xy[0];
+ xy[1] = win->eventstate->xy[1];
+
+ ARegion *region = CTX_wm_region(C);
+ int mval[2];
+ /* Convert mouse coordinates to region local coordinates. */
+ mval[0] = xy[0] - region->winrct.xmin;
+ mval[1] = xy[1] - region->winrct.ymin;
+
+ update_overlay_strip_position_data(C, mval);
+ }
- /* Update the position were we would place the strip if we complete the drag and drop action.
- */
- UI_view2d_region_to_view(v2d, mval[0], mval[1], &coords->start_frame, &coords->channel);
- coords->start_frame = roundf(coords->start_frame);
- if (coords->channel < 1.0f) {
- coords->channel = 1;
+ RNA_int_set(drop->ptr, "frame_start", g_drop_coords.start_frame);
+ RNA_int_set(drop->ptr, "channel", g_drop_coords.channel);
+ RNA_boolean_set(drop->ptr, "overlap_shuffle_override", true);
}
+ else {
+ /* We are dropped inside the preview region. Put the strip on top of the
+ * current displayed frame. */
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
+ ListBase *channels = SEQ_channels_displayed_get(ed);
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
- float start_frame = coords->start_frame;
- float end_frame = coords->start_frame + coords->strip_len;
-
- if (coords->use_snapping) {
- /* Do snapping via the existing transform code. */
- int snap_delta;
- float snap_frame;
- bool valid_snap;
+ SeqCollection *strips = SEQ_query_rendered_strips(
+ scene, channels, seqbase, scene->r.cfra, sseq->chanshown);
- valid_snap = ED_transform_snap_sequencer_to_closest_strip_calc(
- scene, region, start_frame, end_frame, &snap_delta, &snap_frame);
-
- if (valid_snap) {
- /* We snapped onto something! */
- start_frame += snap_delta;
- coords->start_frame = start_frame;
- end_frame = start_frame + coords->strip_len;
- coords->snap_point_x = snap_frame;
+ /* Get the top most strip channel that is in view. */
+ Sequence *seq;
+ int max_channel = -1;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ max_channel = max_ii(seq->machine, max_channel);
}
- else {
- /* Nothing was snapped to, disable snap drawing. */
- coords->use_snapping = false;
+
+ if (max_channel != -1) {
+ RNA_int_set(drop->ptr, "channel", max_channel);
}
+ SEQ_collection_free(strips);
}
+}
- if (coords->strip_len < 1) {
- /* Only check if there is a strip already under the mouse cursor. */
- coords->is_intersecting = find_nearest_seq(scene, &region->v2d, &hand, mval);
+static void get_drag_path(wmDrag *drag, char r_path[FILE_MAX])
+{
+ ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
+ /* ID dropped. */
+ if (id != NULL) {
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_IM) {
+ Image *ima = (Image *)id;
+ BLI_strncpy(r_path, ima->filepath, FILE_MAX);
+ }
+ else if (id_type == ID_MC) {
+ MovieClip *clip = (MovieClip *)id;
+ BLI_strncpy(r_path, clip->filepath, FILE_MAX);
+ }
+ else if (id_type == ID_SO) {
+ bSound *sound = (bSound *)id;
+ BLI_strncpy(r_path, sound->filepath, FILE_MAX);
+ }
+ BLI_path_abs(r_path, BKE_main_blendfile_path_from_global());
}
else {
- /* Check if there is a strip that would intersect with the new strip(s). */
- coords->is_intersecting = false;
- Sequence dummy_seq = {
- .machine = coords->channel, .start = coords->start_frame, .len = coords->strip_len};
- Editing *ed = SEQ_editing_get(scene);
-
- for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) {
- coords->is_intersecting = SEQ_transform_test_overlap(ed->seqbasep, &dummy_seq);
- dummy_seq.machine++;
- }
+ BLI_strncpy(r_path, drag->path, FILE_MAX);
}
}
@@ -255,7 +345,7 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c
mval[0] = xy[0] - region->winrct.xmin;
mval[1] = xy[1] - region->winrct.ymin;
- update_overlay_strip_poistion_data(C, mval);
+ float strip_len = update_overlay_strip_position_data(C, mval);
GPU_matrix_push();
UI_view2d_view_ortho(&region->v2d);
@@ -275,11 +365,11 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw strips. The code here is taken from sequencer_draw. */
float x1 = coords->start_frame;
- float x2 = coords->start_frame + coords->strip_len;
+ float x2 = coords->start_frame + floorf(strip_len);
float strip_color[3];
uchar text_color[4] = {255, 255, 255, 255};
float pixelx = BLI_rctf_size_x(&region->v2d.cur) / BLI_rcti_size_x(&region->v2d.mask);
@@ -353,21 +443,22 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c
const char *text_array[5];
char text_display[FILE_MAX];
char filename[FILE_MAX];
- char rel_path[FILE_MAX];
+ char path[FILE_MAX];
char strip_duration_text[16];
int len_text_arr = 0;
+ get_drag_path(drag, path);
+
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) {
- BLI_split_file_part(drag->path, filename, FILE_MAX);
+ BLI_split_file_part(path, filename, FILE_MAX);
text_array[len_text_arr++] = filename;
}
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) {
Main *bmain = CTX_data_main(C);
- BLI_strncpy(rel_path, drag->path, FILE_MAX);
- BLI_path_rel(rel_path, BKE_main_blendfile_path(bmain));
+ BLI_path_rel(path, BKE_main_blendfile_path(bmain));
text_array[len_text_arr++] = text_sep;
- text_array[len_text_arr++] = rel_path;
+ text_array[len_text_arr++] = path;
}
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) {
@@ -441,6 +532,14 @@ static void prefetch_data_fn(void *custom_data,
if (anim != NULL) {
g_drop_coords.strip_len = IMB_anim_get_duration(anim, IMB_TC_NONE);
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base, true)) {
+ g_drop_coords.playback_rate = (float)frs_sec / frs_sec_base;
+ }
+ else {
+ g_drop_coords.playback_rate = 0;
+ }
IMB_free_anim(anim);
#ifdef WITH_AUDASPACE
/* Try to load sound and see if the video has a sound channel. */
@@ -463,7 +562,7 @@ static void free_prefetch_data_fn(void *custom_data)
MEM_freeN(job_data);
}
-static void start_audio_video_job(bContext *C, char *path, bool only_audio)
+static void start_audio_video_job(bContext *C, wmDrag *drag, bool only_audio)
{
g_drop_coords.strip_len = 0;
g_drop_coords.channel_len = 1;
@@ -477,8 +576,8 @@ static void start_audio_video_job(bContext *C, char *path, bool only_audio)
DropJobData *job_data = (DropJobData *)MEM_mallocN(sizeof(DropJobData),
"SeqDragDropPreviewData");
+ get_drag_path(drag, job_data->path);
- BLI_strncpy(job_data->path, path, FILE_MAX);
job_data->only_audio = only_audio;
job_data->scene_fps = FPS;
@@ -491,15 +590,15 @@ static void start_audio_video_job(bContext *C, char *path, bool only_audio)
static void video_prefetch(bContext *C, wmDrag *drag)
{
- if (drag->type == WM_DRAG_PATH && ELEM(drag->icon, ICON_FILE_MOVIE, ICON_FILE_BLANK)) {
- start_audio_video_job(C, drag->path, false);
+ if (is_movie(drag)) {
+ start_audio_video_job(C, drag, false);
}
}
static void audio_prefetch(bContext *C, wmDrag *drag)
{
- if (drag->type == WM_DRAG_PATH && ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) {
- start_audio_video_job(C, drag->path, true);
+ if (is_sound(drag)) {
+ start_audio_video_job(C, drag, true);
}
}
@@ -533,6 +632,7 @@ static void sequencer_drop_draw_deactivate(struct wmDropBox *drop, wmDrag *UNUSE
SeqDropCoords *coords = drop->draw_data;
if (coords) {
coords->in_use = false;
+ coords->has_read_mouse_pos = false;
drop->draw_data = NULL;
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 25701c323b9..71804d29e6b 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -241,327 +241,282 @@ typedef struct WaveVizData {
float pos[2];
float rms_pos;
bool clip;
- bool end;
+ bool draw_line; /* Draw triangle otherwise. */
+ bool final_sample; /* There are no more samples. */
} WaveVizData;
-static int get_section_len(WaveVizData *start, WaveVizData *end)
+static bool seq_draw_waveforms_poll(const bContext *UNUSED(C), SpaceSeq *sseq, Sequence *seq)
{
- int len = 0;
- while (start != end) {
- len++;
- if (start->end) {
- return len;
- }
- start++;
- }
- return len;
-}
+ const bool strip_is_valid = seq->type == SEQ_TYPE_SOUND_RAM && seq->sound != NULL;
+ const bool overlays_enabled = (sseq->flag & SEQ_SHOW_OVERLAY) != 0;
+ const bool ovelay_option = ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) != 0 ||
+ (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM));
-static void draw_waveform(WaveVizData *iter, WaveVizData *end, GPUPrimType prim_type, bool use_rms)
-{
- int strip_len = get_section_len(iter, end);
- if (strip_len > 1) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) != 0) {
+ return false;
+ }
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(prim_type, strip_len);
+ if (strip_is_valid && overlays_enabled && ovelay_option) {
+ return true;
+ }
- while (iter != end) {
- if (iter->clip) {
- immAttr4f(col, 1.0f, 0.0f, 0.0f, 0.5f);
- }
- else if (use_rms) {
- immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.8f);
- }
- else {
- immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.5f);
- }
+ return false;
+}
- if (use_rms) {
- immVertex2f(pos, iter->pos[0], iter->rms_pos);
- }
- else {
- immVertex2f(pos, iter->pos[0], iter->pos[1]);
- }
+static void waveform_job_start_if_needed(const bContext *C, Sequence *seq)
+{
+ bSound *sound = seq->sound;
- if (iter->end) {
- /* End of line. */
- iter++;
- strip_len = get_section_len(iter, end);
- if (strip_len != 0) {
- immEnd();
- immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(prim_type, strip_len);
- }
- }
- else {
- iter++;
- }
+ BLI_spin_lock(sound->spinlock);
+ if (!sound->waveform) {
+ /* Load the waveform data if it hasn't been loaded and cached already. */
+ if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
+ /* Prevent sounds from reloading. */
+ sound->tags |= SOUND_TAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
+ sequencer_preview_add_sound(C, seq);
+ }
+ else {
+ BLI_spin_unlock(sound->spinlock);
}
- immEnd();
- immUnbindProgram();
-
- GPU_blend(GPU_BLEND_NONE);
}
+ BLI_spin_unlock(sound->spinlock);
}
-static float clamp_frame_coord_to_pixel(float frame_coord,
- float pixel_frac,
- float frames_per_pixel)
+static size_t get_vertex_count(WaveVizData *waveform_data)
{
- float cur_pixel = (frame_coord / frames_per_pixel);
- float new_pixel = (int)(frame_coord / frames_per_pixel) + pixel_frac;
- if (cur_pixel > new_pixel) {
- new_pixel += 1.0f;
+ bool draw_line = waveform_data->draw_line;
+ size_t length = 0;
+
+ while (waveform_data->draw_line == draw_line && !waveform_data->final_sample) {
+ waveform_data++;
+ length++;
}
- return new_pixel * frames_per_pixel;
+
+ return length;
}
-/**
- * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
- * \param frames_per_pixel: The amount of pixels a whole frame takes up (x-axis direction).
- */
-static void draw_seq_waveform_overlay(View2D *v2d,
- const bContext *C,
- SpaceSeq *sseq,
- Scene *scene,
- Sequence *seq,
- float x1,
- float y1,
- float x2,
- float y2,
- float frames_per_pixel)
+static size_t draw_waveform_segment(WaveVizData *waveform_data, bool use_rms)
{
- if (seq->sound && ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) ||
- (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
- /* Make sure that the start drawing position is aligned to the pixels on the screen to avoid
- * flickering when moving around the strip.
- * To do this we figure out the fractional offset in pixel space by checking where the
- * window starts.
- * We then append this pixel offset to our strip start coordinate to ensure we are aligned to
- * the screen pixel grid. */
- float pixel_frac = v2d->cur.xmin / frames_per_pixel - floor(v2d->cur.xmin / frames_per_pixel);
- float x1_adj = clamp_frame_coord_to_pixel(x1, pixel_frac, frames_per_pixel);
-
- /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
- float x1_offset = max_ff(v2d->cur.xmin, x1_adj);
- float x2_offset = min_ff(v2d->cur.xmax, x2);
-
- /* Calculate how long the strip that is in view is in pixels. */
- int pix_strip_len = round((x2_offset - x1_offset) / frames_per_pixel);
-
- if (pix_strip_len < 2) {
- return;
- }
+ size_t vertices_done = 0;
+ size_t vertex_count = get_vertex_count(waveform_data);
- bSound *sound = seq->sound;
+ /* Not enough data to draw. */
+ if (vertex_count <= 2) {
+ return vertex_count;
+ }
- BLI_spin_lock(sound->spinlock);
- if (!sound->waveform) {
- /* Load the waveform data if it hasn't been loaded and cached already. */
- if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
- /* Prevent sounds from reloading. */
- sound->tags |= SOUND_TAGS_WAVEFORM_LOADING;
- BLI_spin_unlock(sound->spinlock);
- sequencer_preview_add_sound(C, seq);
- }
- else {
- BLI_spin_unlock(sound->spinlock);
- }
- return; /* Nothing to draw. */
- }
- BLI_spin_unlock(sound->spinlock);
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPUVertFormat *format = immVertexFormat();
+ GPUPrimType prim_type = waveform_data->draw_line ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+ immBegin(prim_type, vertex_count);
- SoundWaveform *waveform = sound->waveform;
+ while (vertices_done < vertex_count && !waveform_data->final_sample) {
+ /* Color. */
+ if (waveform_data->clip) {
+ immAttr4f(col, 1.0f, 0.0f, 0.0f, 0.5f);
+ }
+ else if (use_rms) {
+ immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.8f);
+ }
+ else {
+ immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.5f);
+ }
- /* Waveform could not be built. */
- if (waveform->length == 0) {
- return;
+ /* Vertices. */
+ if (use_rms) {
+ immVertex2f(pos, waveform_data->pos[0], waveform_data->rms_pos);
+ }
+ else {
+ immVertex2f(pos, waveform_data->pos[0], waveform_data->pos[1]);
}
- /* F-Curve lookup is quite expensive, so do this after precondition. */
- FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+ vertices_done++;
+ waveform_data++;
+ }
- WaveVizData *tri_strip_arr = MEM_callocN(sizeof(*tri_strip_arr) * pix_strip_len * 2,
- "tri_strip");
- WaveVizData *line_strip_arr = MEM_callocN(sizeof(*line_strip_arr) * pix_strip_len,
- "line_strip");
+ immEnd();
+ immUnbindProgram();
- WaveVizData *tri_strip_iter = tri_strip_arr;
- WaveVizData *line_strip_iter = line_strip_arr;
+ GPU_blend(GPU_BLEND_NONE);
- /* The y coordinate for the middle of the strip. */
- float y_mid = (y1 + y2) / 2.0f;
- /* The length from the middle of the strip to the top/bottom. */
- float y_scale = (y2 - y1) / 2.0f;
- float volume = seq->volume;
+ return vertices_done;
+}
- /* Value to keep track if the previous item to be drawn was a line strip. */
- int8_t was_line_strip = -1; /* -1 == no previous value. */
+static void draw_waveform(WaveVizData *waveform_data, size_t wave_data_len)
+{
+ size_t items_done = 0;
+ while (items_done < wave_data_len) {
+ if (!waveform_data[items_done].draw_line) { /* Draw RMS. */
+ draw_waveform_segment(&waveform_data[items_done], true);
+ }
+ items_done += draw_waveform_segment(&waveform_data[items_done], false);
+ }
+}
- float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
+static float align_frame_with_pixel(float frame_coord, float frames_per_pixel)
+{
+ return round_fl_to_int(frame_coord / frames_per_pixel) * frames_per_pixel;
+}
- /* How many samples do we have for each pixel? */
- float samples_per_pix = samples_per_frame * frames_per_pixel;
+static void write_waveform_data(WaveVizData *waveform_data,
+ const vec2f pos,
+ const float rms,
+ const bool is_clipping,
+ const bool draw_line)
+{
+ waveform_data->pos[0] = pos.x;
+ waveform_data->pos[1] = pos.y;
+ waveform_data->clip = is_clipping;
+ waveform_data->rms_pos = rms;
+ waveform_data->draw_line = draw_line;
+}
- float strip_start_offset = seq->startofs + seq->anim_startofs;
- float start_sample = 0;
+static size_t waveform_append_sample(WaveVizData *waveform_data,
+ vec2f pos,
+ const float value_min,
+ const float value_max,
+ const float y_mid,
+ const float y_scale,
+ const float rms,
+ const bool is_clipping,
+ const bool is_line_strip)
+{
+ size_t data_written = 0;
+ pos.y = y_mid + value_min * y_scale;
+ float rms_value = y_mid + max_ff(-rms, value_min) * y_scale;
+ write_waveform_data(&waveform_data[0], pos, rms_value, is_clipping, is_line_strip);
+ data_written++;
+
+ /* Use `value_max` as second vertex for triangle drawing. */
+ if (!is_line_strip) {
+ pos.y = y_mid + value_max * y_scale;
+ rms_value = y_mid + min_ff(rms, value_max) * y_scale;
+ write_waveform_data(&waveform_data[1], pos, rms_value, is_clipping, is_line_strip);
+ data_written++;
+ }
+ return data_written;
+}
- if (strip_start_offset != 0) {
- /* If start offset is not zero, we need to make sure that we pick the same start sample as if
- * we simply scrolled the start of the strip off-screen. Otherwise we will get flickering
- * when changing start offset as the pixel alignment will not be the same for the drawn
- * samples. */
- strip_start_offset = clamp_frame_coord_to_pixel(
- x1 - strip_start_offset, pixel_frac, frames_per_pixel);
- start_sample = fabsf(strip_start_offset - x1_adj) * samples_per_frame;
- }
+/**
+ * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
+ * \param frames_per_pixel: The amount of pixels a whole frame takes up (x-axis direction).
+ */
+static void draw_seq_waveform_overlay(
+ const bContext *C, ARegion *region, Sequence *seq, float x1, float y1, float x2, float y2)
+{
+ const View2D *v2d = &region->v2d;
+ Scene *scene = CTX_data_scene(C);
- start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
- /* If we scrolled the start off-screen, then the start sample should be at the first visible
- * sample. */
- start_sample += (x1_offset - x1_adj) * samples_per_frame;
+ const float frames_per_pixel = BLI_rctf_size_x(&region->v2d.cur) / region->winx;
+ const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
+ float samples_per_pixel = samples_per_frame * frames_per_pixel;
- for (int i = 0; i < pix_strip_len; i++) {
- float sample_offset = start_sample + i * samples_per_pix;
- int p = sample_offset;
+ /* Align strip start with nearest pixel to prevent waveform flickering. */
+ const float x1_aligned = align_frame_with_pixel(x1, frames_per_pixel);
+ /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
+ const float frame_start = max_ff(v2d->cur.xmin, x1_aligned);
+ const float frame_end = min_ff(v2d->cur.xmax, x2);
+ const int pixels_to_draw = round_fl_to_int((frame_end - frame_start) / frames_per_pixel);
- if (p < 0) {
- continue;
- }
+ if (pixels_to_draw < 2) {
+ return; /* Not much to draw, exit before running job. */
+ }
- if (p >= waveform->length) {
- break;
- }
+ waveform_job_start_if_needed(C, seq);
- float value_min = waveform->data[p * 3];
- float value_max = waveform->data[p * 3 + 1];
- float rms = waveform->data[p * 3 + 2];
-
- if (p + 1 < waveform->length) {
- /* Use simple linear interpolation. */
- float f = sample_offset - p;
- value_min = (1.0f - f) * value_min + f * waveform->data[p * 3 + 3];
- value_max = (1.0f - f) * value_max + f * waveform->data[p * 3 + 4];
- rms = (1.0f - f) * rms + f * waveform->data[p * 3 + 5];
- if (samples_per_pix > 1.0f) {
- /* We need to sum up the values we skip over until the next step. */
- float next_pos = sample_offset + samples_per_pix;
- int end_idx = next_pos;
-
- for (int j = p + 1; (j < waveform->length) && (j < end_idx); j++) {
- value_min = min_ff(value_min, waveform->data[j * 3]);
- value_max = max_ff(value_max, waveform->data[j * 3 + 1]);
- rms = max_ff(rms, waveform->data[j * 3 + 2]);
- }
- }
- }
+ SoundWaveform *waveform = seq->sound->waveform;
+ if (waveform == NULL || waveform->length == 0) {
+ return; /* Waveform was not built. */
+ }
- if (fcu && !BKE_fcurve_is_empty(fcu)) {
- float evaltime = x1_offset + (i * frames_per_pixel);
- volume = evaluate_fcurve(fcu, evaltime);
- CLAMP_MIN(volume, 0.0f);
- }
+ /* F-Curve lookup is quite expensive, so do this after precondition. */
+ FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+ WaveVizData *waveform_data = MEM_callocN(sizeof(WaveVizData) * pixels_to_draw * 3, __func__);
+ size_t wave_data_len = 0;
- value_min *= volume;
- value_max *= volume;
- rms *= volume;
+ /* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
+ const float strip_offset = align_frame_with_pixel(seq->startofs + seq->anim_startofs,
+ frames_per_pixel);
+ float start_sample = strip_offset * samples_per_frame;
+ start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
+ /* Add off-screen part of strip to offset. */
+ start_sample += (frame_start - x1_aligned) * samples_per_frame;
- bool clipping = false;
+ for (int i = 0; i < pixels_to_draw; i++) {
+ float sample = start_sample + i * samples_per_pixel;
+ int sample_index = round_fl_to_int(sample);
- if (value_max > 1 || value_min < -1) {
- clipping = true;
+ if (sample_index < 0) {
+ continue;
+ }
- CLAMP_MAX(value_max, 1.0f);
- CLAMP_MIN(value_min, -1.0f);
- }
+ if (sample_index >= waveform->length) {
+ break;
+ }
- bool is_line_strip = (value_max - value_min < 0.05f);
-
- if (!ELEM(was_line_strip, -1, is_line_strip)) {
- /* If the previously added strip type isn't the same as the current one,
- * add transition areas so they transition smoothly between each other. */
- if (is_line_strip) {
- /* This will be a line strip, end the tri strip. */
- tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- tri_strip_iter->pos[1] = y_mid + value_min * y_scale;
- tri_strip_iter->clip = clipping;
- tri_strip_iter->rms_pos = tri_strip_iter->pos[1];
- tri_strip_iter->end = true;
-
- /* End of section. */
- tri_strip_iter++;
-
- /* Check if we are at the end.
- * If so, skip one point line. */
- if (i + 1 == pix_strip_len) {
- continue;
- }
- }
- else {
- /* This will be a tri strip. */
- line_strip_iter--;
- tri_strip_iter->pos[0] = line_strip_iter->pos[0];
- tri_strip_iter->pos[1] = line_strip_iter->pos[1];
- tri_strip_iter->clip = line_strip_iter->clip;
- tri_strip_iter->rms_pos = line_strip_iter->pos[1];
- tri_strip_iter++;
-
- /* Check if line had only one point. */
- line_strip_iter--;
- if (line_strip_iter < line_strip_arr || line_strip_iter->end) {
- /* Only one point, skip it. */
- line_strip_iter++;
- }
- else {
- /* End of section. */
- line_strip_iter++;
- line_strip_iter->end = true;
- line_strip_iter++;
- }
+ float value_min = waveform->data[sample_index * 3];
+ float value_max = waveform->data[sample_index * 3 + 1];
+ float rms = waveform->data[sample_index * 3 + 2];
+
+ if (sample_index + 1 < waveform->length) {
+ /* Use simple linear interpolation. */
+ float f = sample - sample_index;
+ value_min = (1.0f - f) * value_min + f * waveform->data[sample_index * 3 + 3];
+ value_max = (1.0f - f) * value_max + f * waveform->data[sample_index * 3 + 4];
+ rms = (1.0f - f) * rms + f * waveform->data[sample_index * 3 + 5];
+ if (samples_per_pixel > 1.0f) {
+ /* We need to sum up the values we skip over until the next step. */
+ float next_pos = sample + samples_per_pixel;
+ int end_idx = next_pos;
+
+ for (int j = sample_index + 1; (j < waveform->length) && (j < end_idx); j++) {
+ value_min = min_ff(value_min, waveform->data[j * 3]);
+ value_max = max_ff(value_max, waveform->data[j * 3 + 1]);
+ rms = max_ff(rms, waveform->data[j * 3 + 2]);
}
}
+ }
- was_line_strip = is_line_strip;
-
- if (is_line_strip) {
- line_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- line_strip_iter->pos[1] = y_mid + value_min * y_scale;
- line_strip_iter->clip = clipping;
- line_strip_iter++;
- }
- else {
- tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- tri_strip_iter->pos[1] = y_mid + value_min * y_scale;
- tri_strip_iter->clip = clipping;
- tri_strip_iter->rms_pos = y_mid + max_ff(-rms, value_min) * y_scale;
- tri_strip_iter++;
-
- tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- tri_strip_iter->pos[1] = y_mid + value_max * y_scale;
- tri_strip_iter->clip = clipping;
- tri_strip_iter->rms_pos = y_mid + min_ff(rms, value_max) * y_scale;
- tri_strip_iter++;
- }
+ float volume = seq->volume;
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
+ float evaltime = frame_start + (i * frames_per_pixel);
+ volume = evaluate_fcurve(fcu, evaltime);
+ CLAMP_MIN(volume, 0.0f);
}
- WaveVizData *tri_strip_end = tri_strip_iter;
- WaveVizData *line_strip_end = line_strip_iter;
+ value_min *= volume;
+ value_max *= volume;
+ rms *= volume;
- tri_strip_iter = tri_strip_arr;
- line_strip_iter = line_strip_arr;
+ bool is_clipping = false;
- draw_waveform(line_strip_iter, line_strip_end, GPU_PRIM_LINE_STRIP, false);
- draw_waveform(tri_strip_iter, tri_strip_end, GPU_PRIM_TRI_STRIP, false);
- draw_waveform(tri_strip_iter, tri_strip_end, GPU_PRIM_TRI_STRIP, true);
+ if (value_max > 1 || value_min < -1) {
+ is_clipping = true;
+
+ CLAMP_MAX(value_max, 1.0f);
+ CLAMP_MIN(value_min, -1.0f);
+ }
+
+ bool is_line_strip = (value_max - value_min < 0.05f);
+ /* The y coordinate for the middle of the strip. */
+ float y_mid = (y1 + y2) / 2.0f;
+ /* The length from the middle of the strip to the top/bottom. */
+ float y_scale = (y2 - y1) / 2.0f;
- MEM_freeN(tri_strip_arr);
- MEM_freeN(line_strip_arr);
+ vec2f pos = {frame_start + i * frames_per_pixel, y_mid + value_min * y_scale};
+ WaveVizData *new_data = &waveform_data[wave_data_len];
+ wave_data_len += waveform_append_sample(
+ new_data, pos, value_min, value_max, y_mid, y_scale, rms, is_clipping, is_line_strip);
}
+
+ /* Terminate array, so `get_segment_length()` can know when to stop. */
+ waveform_data[wave_data_len].final_sample = true;
+ draw_waveform(waveform_data, wave_data_len);
+ MEM_freeN(waveform_data);
}
static void drawmeta_contents(Scene *scene,
@@ -613,12 +568,12 @@ static void drawmeta_contents(Scene *scene,
col[3] = 196; /* Alpha, used for all meta children. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw only immediate children (1 level depth). */
for (seq = meta_seqbase->first; seq; seq = seq->next) {
- const int startdisp = SEQ_time_left_handle_frame_get(seq) + offset;
- const int enddisp = SEQ_time_right_handle_frame_get(seq) + offset;
+ const int startdisp = SEQ_time_left_handle_frame_get(scene, seq) + offset;
+ const int enddisp = SEQ_time_right_handle_frame_get(scene, seq) + offset;
if ((startdisp > x2 || enddisp < x1) == 0) {
float y_chan = (seq->machine - chan_min) / (float)(chan_range)*draw_range;
@@ -663,19 +618,20 @@ static void drawmeta_contents(Scene *scene,
GPU_blend(GPU_BLEND_NONE);
}
-float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
+float sequence_handle_size_get_clamped(const Scene *scene, Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
/* Ensure that handle is not wider, than quarter of strip. */
- return min_ff(
- maxhandle,
- ((float)(SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)) /
- 4.0f));
+ return min_ff(maxhandle,
+ ((float)(SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq)) /
+ 4.0f));
}
/* Draw a handle, on left or right side of strip. */
-static void draw_seq_handle(View2D *v2d,
+static void draw_seq_handle(const Scene *scene,
+ View2D *v2d,
Sequence *seq,
const float handsize_clamped,
const short direction,
@@ -689,8 +645,8 @@ static void draw_seq_handle(View2D *v2d,
uint whichsel = 0;
uchar col[4];
- x1 = SEQ_time_left_handle_frame_get(seq);
- x2 = SEQ_time_right_handle_frame_get(seq);
+ x1 = SEQ_time_left_handle_frame_get(scene, seq);
+ x2 = SEQ_time_right_handle_frame_get(scene, seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
@@ -745,8 +701,8 @@ static void draw_seq_handle(View2D *v2d,
numstr_len = BLI_snprintf_rlen(numstr,
sizeof(numstr),
"%d%d",
- SEQ_time_left_handle_frame_get(seq),
- SEQ_time_right_handle_frame_get(seq));
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq));
float tot_width = BLF_width(fontid, numstr, numstr_len);
if ((x2 - x1) / pixelx > 20 + tot_width) {
@@ -755,13 +711,13 @@ static void draw_seq_handle(View2D *v2d,
if (direction == SEQ_LEFTHANDLE) {
numstr_len = BLI_snprintf_rlen(
- numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(seq));
+ numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(scene, seq));
x1 += text_margin;
y1 += 0.09f;
}
else {
numstr_len = BLI_snprintf_rlen(
- numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(seq) - 1);
+ numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(scene, seq) - 1);
x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len));
y1 += 0.09f;
}
@@ -896,7 +852,8 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc
}
}
-static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
+static size_t draw_seq_text_get_overlay_string(const Scene *scene,
+ SpaceSeq *sseq,
Sequence *seq,
char *r_overlay_string,
size_t overlay_string_len)
@@ -922,8 +879,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
char strip_duration_text[16];
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) {
- const int strip_duration = SEQ_time_right_handle_frame_get(seq) -
- SEQ_time_left_handle_frame_get(seq);
+ const int strip_duration = SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq);
SNPRINTF(strip_duration_text, "%d", strip_duration);
if (i != 0) {
text_array[i++] = text_sep;
@@ -952,7 +909,7 @@ static void draw_seq_text_overlay(Scene *scene,
ListBase *channels = SEQ_channels_displayed_get(ed);
char overlay_string[FILE_MAX];
size_t overlay_string_len = draw_seq_text_get_overlay_string(
- sseq, seq, overlay_string, sizeof(overlay_string));
+ scene, sseq, seq, overlay_string, sizeof(overlay_string));
if (overlay_string_len == 0) {
return;
@@ -990,8 +947,8 @@ static void draw_sequence_extensions_overlay(
float x1, x2, y1, y2;
uchar col[4], blend_col[3];
- x1 = SEQ_time_left_handle_frame_get(seq);
- x2 = SEQ_time_right_handle_frame_get(seq);
+ x1 = SEQ_time_left_handle_frame_get(scene, seq);
+ x2 = SEQ_time_right_handle_frame_get(scene, seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
@@ -1005,28 +962,32 @@ static void draw_sequence_extensions_overlay(
col[3] = SEQ_render_is_muted(channels, seq) ? MUTE_ALPHA : 200;
UI_GetColorPtrShade3ubv(col, blend_col, 10);
- if (seq->startofs) {
+ const float strip_content_start = SEQ_time_start_frame_get(seq);
+ const float strip_content_end = SEQ_time_start_frame_get(seq) +
+ SEQ_time_strip_length_get(scene, seq);
+ float right_handle_frame = SEQ_time_right_handle_frame_get(scene, seq);
+ float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
+
+ if (left_handle_frame > strip_content_start) {
immUniformColor4ubv(col);
- immRectf(pos, (float)(seq->start), y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM);
+ immRectf(pos, strip_content_start, y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM);
/* Outline. */
immUniformColor3ubv(blend_col);
- imm_draw_box_wire_2d(pos, x1, y1 - pixely, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM);
+ imm_draw_box_wire_2d(pos, x1, y1 - pixely, strip_content_start, y1 - SEQ_STRIP_OFSBOTTOM);
}
- if (seq->endofs) {
+ if (right_handle_frame < strip_content_end) {
immUniformColor4ubv(col);
- immRectf(pos, x2, y2 + pixely, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+ immRectf(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM);
- /* Outline. */
- immUniformColor3ubv(blend_col);
- imm_draw_box_wire_2d(
- pos, x2, y2 + pixely, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+ /* Outline. */ immUniformColor3ubv(blend_col);
+ imm_draw_box_wire_2d(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM);
}
GPU_blend(GPU_BLEND_NONE);
}
static void draw_color_strip_band(
- ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1)
+ const Scene *scene, ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1)
{
uchar col[4];
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
@@ -1049,9 +1010,9 @@ static void draw_color_strip_band(
immUniformColor4ubv(col);
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_left_handle_frame_get(scene, seq),
y1,
- SEQ_time_right_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(scene, seq),
text_margin_y);
/* 1px line to better separate the color band. */
@@ -1059,8 +1020,8 @@ static void draw_color_strip_band(
immUniformColor4ubv(col);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, SEQ_time_left_handle_frame_get(seq), text_margin_y);
- immVertex2f(pos, SEQ_time_right_handle_frame_get(seq), text_margin_y);
+ immVertex2f(pos, SEQ_time_left_handle_frame_get(scene, seq), text_margin_y);
+ immVertex2f(pos, SEQ_time_right_handle_frame_get(scene, seq), text_margin_y);
immEnd();
GPU_blend(GPU_BLEND_NONE);
@@ -1112,25 +1073,31 @@ static void draw_seq_background(Scene *scene,
/* Draw the main strip body. */
if (is_single_image) {
- immRectf(
- pos, SEQ_time_left_handle_frame_get(seq), y1, SEQ_time_right_handle_frame_get(seq), y2);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ y1,
+ SEQ_time_right_handle_frame_get(scene, seq),
+ y2);
}
else {
immRectf(pos, x1, y1, x2, y2);
}
/* Draw background for hold still regions. */
- if (!is_single_image && SEQ_time_has_still_frames(seq)) {
+ if (!is_single_image) {
UI_GetColorPtrShade3ubv(col, col, -35);
immUniformColor4ubv(col);
- if (SEQ_time_has_left_still_frames(seq)) {
- const float content_start = min_ff(SEQ_time_right_handle_frame_get(seq), seq->start);
- immRectf(pos, SEQ_time_left_handle_frame_get(seq), y1, content_start, y2);
+ if (SEQ_time_has_left_still_frames(scene, seq)) {
+ float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ const float content_start = SEQ_time_start_frame_get(seq);
+ immRectf(pos, left_handle_frame, y1, content_start, y2);
}
- if (SEQ_time_has_right_still_frames(seq)) {
- const float content_end = max_ff(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len);
- immRectf(pos, content_end, y1, SEQ_time_right_handle_frame_get(seq), y2);
+ if (SEQ_time_has_right_still_frames(scene, seq)) {
+ float right_handle_frame = SEQ_time_right_handle_frame_get(scene, seq);
+ const float content_end = SEQ_time_start_frame_get(seq) +
+ SEQ_time_strip_length_get(scene, seq);
+ immRectf(pos, content_end, y1, right_handle_frame, y2);
}
}
@@ -1191,7 +1158,7 @@ static void draw_seq_invalid(float x1, float x2, float y2, float text_margin_y)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(1.0f, 0.0f, 0.0f, 0.9f);
immRectf(pos, x1, y2, x2, text_margin_y);
@@ -1200,9 +1167,9 @@ static void draw_seq_invalid(float x1, float x2, float y2, float text_margin_y)
}
static void calculate_seq_text_offsets(
- View2D *v2d, Sequence *seq, float *x1, float *x2, float pixelx)
+ const Scene *scene, View2D *v2d, Sequence *seq, float *x1, float *x2, float pixelx)
{
- const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx);
+ const float handsize_clamped = sequence_handle_size_get_clamped(scene, seq, pixelx);
float text_margin = 2.0f * handsize_clamped;
*x1 += text_margin;
@@ -1309,7 +1276,7 @@ static void draw_seq_fcurve_overlay(
GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
GPU_vertbuf_data_len_set(vbo, vert_count);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4f(batch, "color", 0.0f, 0.0f, 0.0f, 0.15f);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1336,7 +1303,7 @@ static void draw_seq_strip(const bContext *C,
View2D *v2d = &region->v2d;
float x1, x2, y1, y2;
- const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx);
+ const float handsize_clamped = sequence_handle_size_get_clamped(scene, seq, pixelx);
float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
/* Check if we are doing "solo preview". */
@@ -1347,15 +1314,17 @@ static void draw_seq_strip(const bContext *C,
SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG);
/* Draw strip body. */
- x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : SEQ_time_left_handle_frame_get(seq);
+ x1 = SEQ_time_has_left_still_frames(scene, seq) ? SEQ_time_start_frame_get(seq) :
+ SEQ_time_left_handle_frame_get(scene, seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
- x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) :
- SEQ_time_right_handle_frame_get(seq);
+ x2 = SEQ_time_has_right_still_frames(scene, seq) ?
+ SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq) :
+ SEQ_time_right_handle_frame_get(scene, seq);
y2 = seq->machine + SEQ_STRIP_OFSTOP;
/* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */
- x1 = min_ff(x1, SEQ_time_right_handle_frame_get(seq));
- x2 = max_ff(x2, SEQ_time_left_handle_frame_get(seq));
+ x1 = min_ff(x1, SEQ_time_right_handle_frame_get(scene, seq));
+ x2 = max_ff(x2, SEQ_time_left_handle_frame_get(scene, seq));
float text_margin_y;
bool y_threshold;
@@ -1375,18 +1344,18 @@ static void draw_seq_strip(const bContext *C,
}
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
draw_seq_background(scene, seq, pos, x1, x2, y1, y2, is_single_image, show_strip_color_tag);
/* Draw a color band inside color strip. */
if (seq->type == SEQ_TYPE_COLOR && y_threshold) {
- draw_color_strip_band(channels, seq, pos, text_margin_y, y1);
+ draw_color_strip_band(scene, channels, seq, pos, text_margin_y, y1);
}
/* Draw strip offsets when flag is enabled or during "solo preview". */
if (sseq->flag & SEQ_SHOW_OVERLAY) {
- if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) {
+ if (!is_single_image && pixely > 0) {
if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) ||
(seq == special_seq_update)) {
draw_sequence_extensions_overlay(scene, seq, pos, pixely, show_strip_color_tag);
@@ -1395,8 +1364,8 @@ static void draw_seq_strip(const bContext *C,
}
immUnbindProgram();
- x1 = SEQ_time_left_handle_frame_get(seq);
- x2 = SEQ_time_right_handle_frame_get(seq);
+ x1 = SEQ_time_left_handle_frame_get(scene, seq);
+ x2 = SEQ_time_right_handle_frame_get(scene, seq);
if ((seq->type == SEQ_TYPE_META) ||
((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) {
@@ -1416,18 +1385,9 @@ static void draw_seq_strip(const bContext *C,
}
/* Draw sound strip waveform. */
- if ((seq->type == SEQ_TYPE_SOUND_RAM) && ((sseq->flag & SEQ_SHOW_OVERLAY)) &&
- (sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) == 0) {
- draw_seq_waveform_overlay(v2d,
- C,
- sseq,
- scene,
- seq,
- x1,
- y_threshold ? y1 + 0.05f : y1,
- x2,
- y_threshold ? text_margin_y : y2,
- BLI_rctf_size_x(&region->v2d.cur) / region->winx);
+ if (seq_draw_waveforms_poll(C, sseq, seq)) {
+ draw_seq_waveform_overlay(
+ C, region, seq, x1, y_threshold ? y1 + 0.05f : y1, x2, y_threshold ? text_margin_y : y2);
}
/* Draw locked state. */
if (SEQ_transform_is_locked(channels, seq)) {
@@ -1440,20 +1400,20 @@ static void draw_seq_strip(const bContext *C,
}
pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (!SEQ_transform_is_locked(channels, seq)) {
draw_seq_handle(
- v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos, seq_active, pixelx, y_threshold);
+ scene, v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos, seq_active, pixelx, y_threshold);
draw_seq_handle(
- v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos, seq_active, pixelx, y_threshold);
+ scene, v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos, seq_active, pixelx, y_threshold);
}
draw_seq_outline(scene, seq, pos, x1, x2, y1, y2, pixelx, pixely, seq_active);
immUnbindProgram();
- calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx);
+ calculate_seq_text_offsets(scene, v2d, seq, &x1, &x2, pixelx);
/* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */
if (seq->type == SEQ_TYPE_SOUND_RAM) {
@@ -1474,7 +1434,7 @@ static void draw_seq_strip(const bContext *C,
}
}
-static void draw_effect_inputs_highlight(Sequence *seq)
+static void draw_effect_inputs_highlight(const Scene *scene, Sequence *seq)
{
Sequence *seq1 = seq->seq1;
Sequence *seq2 = seq->seq2;
@@ -1482,27 +1442,27 @@ static void draw_effect_inputs_highlight(Sequence *seq)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq1),
+ SEQ_time_left_handle_frame_get(scene, seq1),
seq1->machine + SEQ_STRIP_OFSBOTTOM,
- SEQ_time_right_handle_frame_get(seq1),
+ SEQ_time_right_handle_frame_get(scene, seq1),
seq1->machine + SEQ_STRIP_OFSTOP);
if (seq2 && seq2 != seq1) {
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq2),
+ SEQ_time_left_handle_frame_get(scene, seq2),
seq2->machine + SEQ_STRIP_OFSBOTTOM,
- SEQ_time_right_handle_frame_get(seq2),
+ SEQ_time_right_handle_frame_get(scene, seq2),
seq2->machine + SEQ_STRIP_OFSTOP);
}
if (seq3 && !ELEM(seq3, seq1, seq2)) {
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq3),
+ SEQ_time_left_handle_frame_get(scene, seq3),
seq3->machine + SEQ_STRIP_OFSBOTTOM,
- SEQ_time_right_handle_frame_get(seq3),
+ SEQ_time_right_handle_frame_get(scene, seq3),
seq3->machine + SEQ_STRIP_OFSTOP);
}
immUnbindProgram();
@@ -1591,7 +1551,8 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
}
if (viewport) {
- /* Follows same logic as wm_draw_window_offscreen to make sure to restore the same viewport. */
+ /* Follows same logic as wm_draw_window_offscreen to make sure to restore the same
+ * viewport. */
int view = (sseq->multiview_eye == STEREO_RIGHT_ID) ? 1 : 0;
GPU_viewport_bind(viewport, view, &region->winrct);
}
@@ -1688,7 +1649,7 @@ static void sequencer_draw_borders_overlay(const SpaceSeq *sseq,
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -1747,8 +1708,7 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, S
// ED_mask_get_size(C, &width, &height);
//Scene *scene = CTX_data_scene(C);
- width = (scene->r.size * scene->r.xsch) / 100;
- height = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &width, &height);
ED_mask_draw_region(mask,
region,
@@ -1960,7 +1920,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
GPU_texture_bind(texture, 0);
if (!glsl_used) {
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
}
@@ -2096,10 +2056,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
int preview_frame;
if (last_seq->flag & SEQ_RIGHTSEL) {
- preview_frame = SEQ_time_right_handle_frame_get(last_seq) - 1;
+ preview_frame = SEQ_time_right_handle_frame_get(scene, last_seq) - 1;
}
else {
- preview_frame = SEQ_time_left_handle_frame_get(last_seq);
+ preview_frame = SEQ_time_left_handle_frame_get(scene, last_seq);
}
return preview_frame;
@@ -2149,7 +2109,7 @@ static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq,
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_width(2);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float col[3];
if (is_active_seq) {
@@ -2253,7 +2213,7 @@ void sequencer_draw_preview(const bContext *C,
Editing *ed = SEQ_editing_get(scene);
ListBase *channels = SEQ_channels_displayed_get(ed);
SeqCollection *collection = SEQ_query_rendered_strips(
- channels, ed->seqbasep, timeline_frame, 0);
+ scene, channels, ed->seqbasep, timeline_frame, 0);
Sequence *seq;
Sequence *active_seq = SEQ_select_active_get(scene);
SEQ_ITERATOR_FOREACH (seq, collection) {
@@ -2287,7 +2247,7 @@ void sequencer_draw_preview(const bContext *C,
static void draw_seq_timeline_channels(View2D *v2d)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
immUniformThemeColor(TH_ROW_ALTERNATE);
@@ -2325,10 +2285,13 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
if (seq == last_seq && (last_seq->flag & SELECT)) {
continue;
}
- if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > v2d->cur.xmax) {
+ if (min_ii(SEQ_time_left_handle_frame_get(scene, seq), SEQ_time_start_frame_get(seq)) >
+ v2d->cur.xmax) {
continue;
}
- if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < v2d->cur.xmin) {
+ if (max_ii(SEQ_time_right_handle_frame_get(scene, seq),
+ SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq)) <
+ v2d->cur.xmin) {
continue;
}
if (seq->machine + 1.0f < v2d->cur.ymin) {
@@ -2353,7 +2316,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
/* When active strip is an effect, highlight its inputs. */
if (SEQ_effect_get_num_inputs(last_seq->type) > 0) {
- draw_effect_inputs_highlight(last_seq);
+ draw_effect_inputs_highlight(scene, last_seq);
}
/* When active is a Multi-cam strip, highlight its source channel. */
else if (last_seq->type == SEQ_TYPE_MULTICAM) {
@@ -2362,7 +2325,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos, v2d->cur.xmin, channel, v2d->cur.xmax, channel + 1);
@@ -2379,13 +2342,13 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_left_handle_frame_get(scene, seq),
seq->machine + SEQ_STRIP_OFSBOTTOM,
- SEQ_time_right_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(scene, seq),
seq->machine + SEQ_STRIP_OFSTOP);
immUnbindProgram();
@@ -2403,7 +2366,7 @@ static void seq_draw_sfra_efra(const Scene *scene, View2D *v2d)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw overlay outside of frame range. */
immUniformThemeColorShadeAlpha(TH_BACK, -10, -100);
@@ -2445,7 +2408,7 @@ static void seq_draw_sfra_efra(const Scene *scene, View2D *v2d)
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShade(TH_BACK, -40);
immBegin(GPU_PRIM_LINES, 4);
@@ -2569,7 +2532,7 @@ static void draw_cache_view_batch(
GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
if (vert_count > 0) {
GPU_vertbuf_data_len_set(vbo, vert_count);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4f(batch, "color", col_r, col_g, col_b, col_a);
GPU_batch_draw(batch);
}
@@ -2588,7 +2551,7 @@ static void draw_cache_view(const bContext *C)
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float stripe_bot, stripe_top;
float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
@@ -2612,8 +2575,8 @@ static void draw_cache_view(const bContext *C)
continue;
}
- if (SEQ_time_left_handle_frame_get(seq) > v2d->cur.xmax ||
- SEQ_time_right_handle_frame_get(seq) < v2d->cur.xmin) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) > v2d->cur.xmax ||
+ SEQ_time_right_handle_frame_get(scene, seq) < v2d->cur.xmin) {
continue;
}
@@ -2624,9 +2587,9 @@ static void draw_cache_view(const bContext *C)
const float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_left_handle_frame_get(scene, seq),
stripe_bot,
- SEQ_time_right_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(scene, seq),
stripe_top);
}
@@ -2637,9 +2600,9 @@ static void draw_cache_view(const bContext *C)
const float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_left_handle_frame_get(scene, seq),
stripe_bot,
- SEQ_time_right_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(scene, seq),
stripe_top);
}
@@ -2650,9 +2613,9 @@ static void draw_cache_view(const bContext *C)
const float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
immRectf(pos,
- SEQ_time_left_handle_frame_get(seq),
+ SEQ_time_left_handle_frame_get(scene, seq),
stripe_bot,
- SEQ_time_right_handle_frame_get(seq),
+ SEQ_time_right_handle_frame_get(scene, seq),
stripe_top);
}
}
@@ -2697,7 +2660,7 @@ static void draw_overlap_frame_indicator(const struct Scene *scene, const View2D
scene->r.cfra + scene->ed->overlay_frame_ofs;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 86c438c616e..415bb5898a9 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -54,6 +54,7 @@
#include "RNA_prototypes.h"
/* For menu, popup, icons, etc. */
+#include "ED_fileselect.h"
#include "ED_keyframing.h"
#include "ED_numinput.h"
#include "ED_outliner.h"
@@ -81,6 +82,7 @@ typedef struct TransSeq {
int anim_startofs, anim_endofs;
/* int final_left, final_right; */ /* UNUSED */
int len;
+ float content_start;
} TransSeq;
/** \} */
@@ -173,6 +175,11 @@ bool sequencer_edit_poll(bContext *C)
return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
}
+bool sequencer_editing_initialized_and_active(bContext *C)
+{
+ return ED_operator_sequencer_active(C) && sequencer_edit_poll(C);
+}
+
#if 0 /* UNUSED */
bool sequencer_strip_poll(bContext *C)
{
@@ -259,7 +266,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
const bool do_all = RNA_boolean_get(op->ptr, "all");
const Editing *ed = SEQ_editing_get(scene);
- SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all);
+ SEQ_edit_remove_gaps(scene, ed->seqbasep, scene->r.cfra, do_all);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -298,7 +305,7 @@ static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const int frames = RNA_int_get(op->ptr, "frames");
const Editing *ed = SEQ_editing_get(scene);
- SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, CFRA);
+ SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, scene->r.cfra);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -364,8 +371,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
else { /* SEQ_RIGHTSEL */
SEQ_time_right_handle_frame_set(scene, seq, snap_frame);
}
- SEQ_transform_handle_xlimits(
- scene, seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(scene, seq);
}
}
@@ -375,7 +380,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !SEQ_transform_is_locked(channels, seq)) {
seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
}
}
@@ -388,17 +393,20 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
if (seq->seq1 && (seq->seq1->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq)));
+ SEQ_offset_animdata(
+ scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(scene, seq)));
}
}
else if (seq->seq2 && (seq->seq2->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq)));
+ SEQ_offset_animdata(
+ scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(scene, seq)));
}
}
else if (seq->seq3 && (seq->seq3->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq)));
+ SEQ_offset_animdata(
+ scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(scene, seq)));
}
}
}
@@ -416,7 +424,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
int snap_frame;
- snap_frame = CFRA;
+ snap_frame = scene->r.cfra;
RNA_int_set(op->ptr, "frame", snap_frame);
return sequencer_snap_exec(C, op);
@@ -468,6 +476,7 @@ typedef struct SlipData {
static void transseq_backup(TransSeq *ts, Sequence *seq)
{
+ ts->content_start = SEQ_time_start_frame_get(seq);
ts->start = seq->start;
ts->machine = seq->machine;
ts->startofs = seq->startofs;
@@ -598,7 +607,7 @@ static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
}
/* Make sure, that each strip contains at least 1 frame of content. */
-static void sequencer_slip_apply_limits(SlipData *data, int *offset)
+static void sequencer_slip_apply_limits(const Scene *scene, SlipData *data, int *offset)
{
for (int i = 0; i < data->num_seq; i++) {
if (data->trim[i]) {
@@ -607,12 +616,12 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset)
int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
int diff = 0;
- if (seq_content_start >= SEQ_time_right_handle_frame_get(seq)) {
- diff = SEQ_time_right_handle_frame_get(seq) - seq_content_start - 1;
+ if (seq_content_start >= SEQ_time_right_handle_frame_get(scene, seq)) {
+ diff = SEQ_time_right_handle_frame_get(scene, seq) - seq_content_start - 1;
}
- if (seq_content_end <= SEQ_time_left_handle_frame_get(seq)) {
- diff = SEQ_time_left_handle_frame_get(seq) - seq_content_end + 1;
+ if (seq_content_end <= SEQ_time_left_handle_frame_get(scene, seq)) {
+ diff = SEQ_time_left_handle_frame_get(scene, seq) - seq_content_end + 1;
}
*offset += diff;
}
@@ -644,7 +653,7 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
transseq_backup(data->ts + i, data->seq_array[i]);
}
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_recursively(scene, data, offset);
MEM_freeN(data->seq_array);
@@ -690,7 +699,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
applyNumInput(&data->num_input, &offset_fl);
int offset = round_fl_to_int(offset_fl);
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -722,7 +731,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
offset = mouseloc[0] - data->init_mouseloc[0];
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -799,7 +808,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
applyNumInput(&data->num_input, &offset_fl);
int offset = round_fl_to_int(offset_fl);
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1047,7 +1056,7 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op)
SEQ_add_reload_new_file(bmain, scene, seq, !adjust_length);
if (adjust_length) {
- if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
}
}
@@ -1410,14 +1419,14 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
if (ignore_selection) {
if (use_cursor_position) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (SEQ_time_right_handle_frame_get(seq) == split_frame &&
+ if (SEQ_time_right_handle_frame_get(scene, seq) == split_frame &&
seq->machine == split_channel) {
seq_selected = seq->flag & SEQ_ALLSEL;
}
}
if (!seq_selected) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (SEQ_time_left_handle_frame_get(seq) == split_frame &&
+ if (SEQ_time_left_handle_frame_get(scene, seq) == split_frame &&
seq->machine == split_channel) {
seq->flag &= ~SEQ_ALLSEL;
}
@@ -1429,12 +1438,12 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
if (split_side != SEQ_SIDE_BOTH) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
if (split_side == SEQ_SIDE_LEFT) {
- if (SEQ_time_left_handle_frame_get(seq) >= split_frame) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) >= split_frame) {
seq->flag &= ~SEQ_ALLSEL;
}
}
else {
- if (SEQ_time_right_handle_frame_get(seq) <= split_frame) {
+ if (SEQ_time_right_handle_frame_get(scene, seq) <= split_frame) {
seq->flag &= ~SEQ_ALLSEL;
}
}
@@ -1457,7 +1466,7 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
View2D *v2d = UI_view2d_fromcontext(C);
int split_side = RNA_enum_get(op->ptr, "side");
- int split_frame = CFRA;
+ int split_frame = scene->r.cfra;
if (split_side == SEQ_SIDE_MOUSE) {
if (ED_operator_sequencer_active(C) && v2d) {
@@ -1695,8 +1704,10 @@ static int sequencer_delete_exec(bContext *C, wmOperator *op)
static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ ListBase *markers = &scene->markers;
- if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (region->regiontype == RGN_TYPE_WINDOW && !BLI_listbase_is_empty(markers)) {
/* Bounding box of 30 pixels is used for markers shortcuts,
* prevent conflict with markers shortcuts here.
*/
@@ -1761,7 +1772,7 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
- if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
}
}
@@ -1820,12 +1831,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* TODO: remove f-curve and assign to split image strips.
* The old animation system would remove the user of `seq->ipo`. */
- start_ofs = timeline_frame = SEQ_time_left_handle_frame_get(seq);
- frame_end = SEQ_time_right_handle_frame_get(seq);
+ start_ofs = timeline_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ frame_end = SEQ_time_right_handle_frame_get(scene, seq);
while (timeline_frame < frame_end) {
/* New seq. */
- se = SEQ_render_give_stripelem(seq, timeline_frame);
+ se = SEQ_render_give_stripelem(scene, seq, timeline_frame);
seq_new = SEQ_sequence_dupli_recursive(scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME);
@@ -1847,7 +1858,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
if (step > 1) {
seq_new->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(seqbase, seq_new)) {
+ if (SEQ_transform_test_overlap(scene, seqbase, seq_new)) {
SEQ_transform_seqbase_shuffle(seqbase, seq_new, scene);
}
}
@@ -1906,11 +1917,9 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
SEQ_prefetch_stop(scene);
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
- /* Enter meta-strip. */
- SEQ_meta_stack_alloc(ed, active_seq);
- SEQ_seqbase_active_set(ed, &active_seq->seqbase);
- SEQ_channels_displayed_set(ed, &active_seq->channels);
+ /* Deselect active meta seq. */
SEQ_select_active_set(scene, NULL);
+ SEQ_meta_stack_set(scene, active_seq);
}
else {
/* Exit meta-strip if possible. */
@@ -1918,11 +1927,9 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- MetaStack *ms = SEQ_meta_stack_active_get(ed);
- SEQ_seqbase_active_set(ed, ms->oldbasep);
- SEQ_channels_displayed_set(ed, ms->old_channels);
- SEQ_select_active_set(scene, ms->parseq);
- SEQ_meta_stack_free(ed, ms);
+ /* Display parent meta. */
+ Sequence *meta_parent = SEQ_meta_stack_pop(ed);
+ SEQ_select_active_set(scene, meta_parent);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -1977,8 +1984,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
BLI_addtail(&seqm->seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
channel_max = max_ii(seq->machine, channel_max);
- meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(seq), meta_start_frame);
- meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(seq), meta_end_frame);
+ meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(scene, seq), meta_start_frame);
+ meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(scene, seq), meta_end_frame);
}
}
@@ -1988,7 +1995,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
seqm->start = meta_start_frame;
seqm->len = meta_end_frame - meta_start_frame;
SEQ_select_active_set(scene, seqm);
- if (SEQ_transform_test_overlap(active_seqbase, seqm)) {
+ if (SEQ_transform_test_overlap(scene, active_seqbase, seqm)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene);
}
@@ -2048,7 +2055,7 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH (Sequence *, seq, active_seqbase) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(active_seqbase, seq)) {
+ if (SEQ_transform_test_overlap(scene, active_seqbase, seq)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seq, scene);
}
}
@@ -2087,12 +2094,12 @@ static bool strip_jump_internal(Scene *scene,
const bool do_center)
{
bool changed = false;
- int timeline_frame = CFRA;
+ int timeline_frame = scene->r.cfra;
int next_frame = SEQ_time_find_next_prev_edit(
scene, timeline_frame, side, do_skip_mute, do_center, false);
if (next_frame != timeline_frame) {
- CFRA = next_frame;
+ scene->r.cfra = next_frame;
changed = true;
}
@@ -2159,17 +2166,18 @@ static const EnumPropertyItem prop_side_lr_types[] = {
static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb)
{
- int gap = SEQ_time_left_handle_frame_get(seqb) - SEQ_time_right_handle_frame_get(seqa);
+ int gap = SEQ_time_left_handle_frame_get(scene, seqb) -
+ SEQ_time_right_handle_frame_get(scene, seqa);
int seq_a_start;
int seq_b_start;
- seq_b_start = (seqb->start - SEQ_time_left_handle_frame_get(seqb)) +
- SEQ_time_left_handle_frame_get(seqa);
+ seq_b_start = (seqb->start - SEQ_time_left_handle_frame_get(scene, seqb)) +
+ SEQ_time_left_handle_frame_get(scene, seqa);
SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start);
SEQ_relations_invalidate_cache_preprocessed(scene, seqb);
- seq_a_start = (seqa->start - SEQ_time_left_handle_frame_get(seqa)) +
- SEQ_time_right_handle_frame_get(seqb) + gap;
+ seq_a_start = (seqa->start - SEQ_time_left_handle_frame_get(scene, seqa)) +
+ SEQ_time_right_handle_frame_get(scene, seqb) + gap;
SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start);
SEQ_relations_invalidate_cache_preprocessed(scene, seqa);
}
@@ -2195,13 +2203,17 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
switch (lr) {
case SEQ_SIDE_LEFT:
- if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(test)) {
- dist = SEQ_time_right_handle_frame_get(test) - SEQ_time_left_handle_frame_get(seq);
+ if (SEQ_time_right_handle_frame_get(scene, seq) <=
+ SEQ_time_left_handle_frame_get(scene, test)) {
+ dist = SEQ_time_right_handle_frame_get(scene, test) -
+ SEQ_time_left_handle_frame_get(scene, seq);
}
break;
case SEQ_SIDE_RIGHT:
- if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(test)) {
- dist = SEQ_time_left_handle_frame_get(seq) - SEQ_time_right_handle_frame_get(test);
+ if (SEQ_time_left_handle_frame_get(scene, seq) >=
+ SEQ_time_right_handle_frame_get(scene, test)) {
+ dist = SEQ_time_left_handle_frame_get(scene, seq) -
+ SEQ_time_right_handle_frame_get(scene, test);
}
break;
}
@@ -2266,7 +2278,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
/* This may now overlap. */
- if (SEQ_transform_test_overlap(seqbase, iseq)) {
+ if (SEQ_transform_test_overlap(scene, seqbase, iseq)) {
SEQ_transform_seqbase_shuffle(seqbase, iseq, scene);
}
}
@@ -2316,7 +2328,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
switch (active_seq->type) {
case SEQ_TYPE_IMAGE:
- se = SEQ_render_give_stripelem(active_seq, scene->r.cfra);
+ se = SEQ_render_give_stripelem(scene, active_seq, scene->r.cfra);
break;
case SEQ_TYPE_MOVIE:
se = active_seq->strip->stripdata;
@@ -2527,8 +2539,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
else {
int min_seq_startdisp = INT_MAX;
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
- if (SEQ_time_left_handle_frame_get(seq) < min_seq_startdisp) {
- min_seq_startdisp = SEQ_time_left_handle_frame_get(seq);
+ if (SEQ_time_left_handle_frame_get(scene, seq) < min_seq_startdisp) {
+ min_seq_startdisp = SEQ_time_left_handle_frame_get(scene, seq);
}
}
/* Paste strips relative to the current-frame. */
@@ -2574,7 +2586,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
* strip. */
SEQ_transform_translate_sequence(scene, iseq, ofs);
/* Ensure, that pasted strips don't overlap. */
- if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, iseq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene);
}
}
@@ -2626,12 +2638,12 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
Sequence *seq_other;
const char *error_msg;
- if (SEQ_select_active_get_pair(scene, &seq_act, &seq_other) == 0) {
+ if (SEQ_select_active_get_pair(scene, &seq_act, &seq_other) == false) {
BKE_report(op->reports, RPT_ERROR, "Please select two strips");
return OPERATOR_CANCELLED;
}
- if (SEQ_edit_sequence_swap(seq_act, seq_other, &error_msg) == 0) {
+ if (SEQ_edit_sequence_swap(scene, seq_act, seq_other, &error_msg) == false) {
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
@@ -2858,7 +2870,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "directory", directory);
if (is_relative_path) {
- /* TODO(campbell): shouldn't this already be relative from the filesel?
+ /* TODO(@campbellbarton): shouldn't this already be relative from the filesel?
* (as the 'filepath' is) for now just make relative here,
* but look into changing after 2.60. */
BLI_path_rel(directory, BKE_main_blendfile_path(bmain));
@@ -3056,13 +3068,14 @@ void SEQUENCER_OT_change_scene(struct wmOperatorType *ot)
* \{ */
/** Comparison function suitable to be used with BLI_listbase_sort(). */
-static int seq_cmp_time_startdisp_channel(const void *a, const void *b)
+static int seq_cmp_time_startdisp_channel(void *thunk, const void *a, const void *b)
{
+ const Scene *scene = thunk;
Sequence *seq_a = (Sequence *)a;
Sequence *seq_b = (Sequence *)b;
- int seq_a_start = SEQ_time_left_handle_frame_get(seq_a);
- int seq_b_start = SEQ_time_left_handle_frame_get(seq_b);
+ int seq_a_start = SEQ_time_left_handle_frame_get(scene, seq_a);
+ int seq_b_start = SEQ_time_left_handle_frame_get(scene, seq_b);
/* If strips have the same start frame favor the one with a higher channel. */
if (seq_a_start == seq_b_start) {
@@ -3076,20 +3089,7 @@ static int sequencer_export_subtitles_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
- Main *bmain = CTX_data_main(C);
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
- char filepath[FILE_MAX];
-
- if (BKE_main_blendfile_path(bmain)[0] == '\0') {
- BLI_strncpy(filepath, "untitled", sizeof(filepath));
- }
- else {
- BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
- }
-
- BLI_path_extension_replace(filepath, sizeof(filepath), ".srt");
- RNA_string_set(op->ptr, "filepath", filepath);
- }
+ ED_fileselect_ensure_default_filepath(C, op, ".srt");
WM_event_add_fileselect(C, op);
@@ -3108,7 +3108,7 @@ static bool seq_get_text_strip_cb(Sequence *seq, void *user_data)
ListBase *channels = SEQ_channels_displayed_get(ed);
/* Only text strips that are not muted and don't end with negative frame. */
if ((seq->type == SEQ_TYPE_TEXT) && !SEQ_render_is_muted(channels, seq) &&
- (SEQ_time_right_handle_frame_get(seq) > cd->scene->r.sfra)) {
+ (SEQ_time_right_handle_frame_get(cd->scene, seq) > cd->scene->r.sfra)) {
BLI_addtail(cd->text_seq, MEM_dupallocN(seq));
}
return true;
@@ -3124,7 +3124,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
FILE *file;
char filepath[FILE_MAX];
- if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
@@ -3155,7 +3155,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BLI_listbase_sort(&text_seq, seq_cmp_time_startdisp_channel);
+ BLI_listbase_sort_r(&text_seq, seq_cmp_time_startdisp_channel, scene);
/* Open and write file. */
file = BLI_fopen(filepath, "w");
@@ -3170,15 +3170,16 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
timecode_str_start,
sizeof(timecode_str_start),
-2,
- FRA2TIME(max_ii(SEQ_time_left_handle_frame_get(seq) - scene->r.sfra, 0)),
+ FRA2TIME(max_ii(SEQ_time_left_handle_frame_get(scene, seq) - scene->r.sfra, 0)),
+ FPS,
+ USER_TIMECODE_SUBRIP);
+ BLI_timecode_string_from_time(
+ timecode_str_end,
+ sizeof(timecode_str_end),
+ -2,
+ FRA2TIME(SEQ_time_right_handle_frame_get(scene, seq) - scene->r.sfra),
FPS,
USER_TIMECODE_SUBRIP);
- BLI_timecode_string_from_time(timecode_str_end,
- sizeof(timecode_str_end),
- -2,
- FRA2TIME(SEQ_time_right_handle_frame_get(seq) - scene->r.sfra),
- FPS,
- USER_TIMECODE_SUBRIP);
fprintf(
file, "%d\n%s --> %s\n%s\n\n", iter++, timecode_str_start, timecode_str_end, data->text);
@@ -3244,8 +3245,8 @@ static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
selected = true;
- sfra = min_ii(sfra, SEQ_time_left_handle_frame_get(seq));
- efra = max_ii(efra, SEQ_time_right_handle_frame_get(seq) - 1);
+ sfra = min_ii(sfra, SEQ_time_left_handle_frame_get(scene, seq));
+ efra = max_ii(efra, SEQ_time_right_handle_frame_get(scene, seq) - 1);
}
}
@@ -3397,8 +3398,8 @@ static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) {
- const int timeline_frame = CFRA;
- StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame);
+ const int timeline_frame = scene->r.cfra;
+ StripElem *strip_elem = SEQ_render_give_stripelem(scene, seq, timeline_frame);
if (strip_elem == NULL) {
continue;
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 3307c3fde2f..644e897f631 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -70,7 +70,9 @@ void color3ubv_from_seq(const struct Scene *curscene,
void sequencer_special_update_set(Sequence *seq);
/* Get handle width in 2d-View space. */
-float sequence_handle_size_get_clamped(struct Sequence *seq, float pixelx);
+float sequence_handle_size_get_clamped(const struct Scene *scene,
+ struct Sequence *seq,
+ float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
@@ -113,7 +115,7 @@ void channel_draw_context_init(const struct bContext *C,
/* sequencer_edit.c */
struct View2D;
-void seq_rectf(struct Sequence *seq, struct rctf *rectf);
+void seq_rectf(const struct Scene *scene, struct Sequence *seq, struct rctf *rectf);
struct Sequence *find_nearest_seq(struct Scene *scene,
struct View2D *v2d,
int *hand,
@@ -133,6 +135,7 @@ int seq_effect_find_selected(struct Scene *scene,
/* Operator helpers. */
bool sequencer_edit_poll(struct bContext *C);
+bool sequencer_editing_initialized_and_active(struct bContext *C);
/* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 6ba1dcc5eb8..af0aa093e40 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -17,7 +17,7 @@
#include "sequencer_intern.h"
-/* XXX(campbell): why is this function better than BLI_math version?
+/* XXX(@campbellbarton): why is this function better than BLI_math version?
* only difference is it does some normalize after, need to double check on this. */
static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
{
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index f237fbc0a12..4aaa3aeb2ff 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -59,7 +59,7 @@ SeqCollection *all_strips_from_context(bContext *C)
const bool is_preview = sequencer_view_has_preview_poll(C);
if (is_preview) {
- return SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ return SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
}
return SEQ_query_all_strips(seqbase);
@@ -74,7 +74,7 @@ SeqCollection *selected_strips_from_context(bContext *C)
const bool is_preview = sequencer_view_has_preview_poll(C);
if (is_preview) {
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
return strips;
}
@@ -108,7 +108,8 @@ static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRIN
}
/* Used for mouse selection in SEQUENCER_OT_select. */
-static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
+static void select_active_side(
+ const Scene *scene, ListBase *seqbase, int sel_side, int channel, int frame)
{
Sequence *seq;
@@ -116,13 +117,13 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
if (channel == seq->machine) {
switch (sel_side) {
case SEQ_SIDE_LEFT:
- if (frame > (SEQ_time_left_handle_frame_get(seq))) {
+ if (frame > (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
break;
case SEQ_SIDE_RIGHT:
- if (frame < (SEQ_time_left_handle_frame_get(seq))) {
+ if (frame < (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
@@ -137,7 +138,8 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
}
/* Used for mouse selection in SEQUENCER_OT_select_side. */
-static void select_active_side_range(ListBase *seqbase,
+static void select_active_side_range(const Scene *scene,
+ ListBase *seqbase,
const int sel_side,
const int frame_ranges[MAXSEQ],
const int frame_ignore)
@@ -152,13 +154,13 @@ static void select_active_side_range(ListBase *seqbase,
}
switch (sel_side) {
case SEQ_SIDE_LEFT:
- if (frame > (SEQ_time_left_handle_frame_get(seq))) {
+ if (frame > (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
break;
case SEQ_SIDE_RIGHT:
- if (frame < (SEQ_time_left_handle_frame_get(seq))) {
+ if (frame < (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
@@ -173,14 +175,14 @@ static void select_active_side_range(ListBase *seqbase,
}
/* Used for mouse selection in SEQUENCER_OT_select */
-static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
+static void select_linked_time(const Scene *scene, ListBase *seqbase, Sequence *seq_link)
{
Sequence *seq;
for (seq = seqbase->first; seq; seq = seq->next) {
if (seq_link->machine != seq->machine) {
- int left_match = (SEQ_time_left_handle_frame_get(seq) == seq_link->startdisp) ? 1 : 0;
- int right_match = (SEQ_time_right_handle_frame_get(seq) == seq_link->enddisp) ? 1 : 0;
+ int left_match = (SEQ_time_left_handle_frame_get(scene, seq) == seq_link->startdisp) ? 1 : 0;
+ int right_match = (SEQ_time_right_handle_frame_get(scene, seq) == seq_link->enddisp) ? 1 : 0;
if (left_match && right_match) {
/* Direct match, copy the selection settings. */
@@ -245,10 +247,10 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel
recurs_sel_seq(seq);
}
-void seq_rectf(Sequence *seq, rctf *rect)
+void seq_rectf(const Scene *scene, Sequence *seq, rctf *rect)
{
- rect->xmin = SEQ_time_left_handle_frame_get(seq);
- rect->xmax = SEQ_time_right_handle_frame_get(seq);
+ rect->xmin = SEQ_time_left_handle_frame_get(scene, seq);
+ rect->xmax = SEQ_time_right_handle_frame_get(scene, seq);
rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
rect->ymax = seq->machine + SEQ_STRIP_OFSTOP;
}
@@ -273,12 +275,14 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
(sel == 0 && (seq->flag & SELECT) == 0))) {
switch (lr) {
case SEQ_SIDE_LEFT:
- if (SEQ_time_left_handle_frame_get(test) == (SEQ_time_right_handle_frame_get(seq))) {
+ if (SEQ_time_left_handle_frame_get(scene, test) ==
+ (SEQ_time_right_handle_frame_get(scene, seq))) {
return seq;
}
break;
case SEQ_SIDE_RIGHT:
- if (SEQ_time_right_handle_frame_get(test) == (SEQ_time_left_handle_frame_get(seq))) {
+ if (SEQ_time_right_handle_frame_get(scene, test) ==
+ (SEQ_time_left_handle_frame_get(scene, seq))) {
return seq;
}
break;
@@ -311,18 +315,20 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
while (seq) {
if (seq->machine == (int)y) {
/* Check for both normal strips, and strips that have been flipped horizontally. */
- if (((SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(seq)) &&
- (SEQ_time_left_handle_frame_get(seq) <= x &&
- SEQ_time_right_handle_frame_get(seq) >= x)) ||
- ((SEQ_time_left_handle_frame_get(seq) > SEQ_time_right_handle_frame_get(seq)) &&
- (SEQ_time_left_handle_frame_get(seq) >= x &&
- SEQ_time_right_handle_frame_get(seq) <= x))) {
+ if (((SEQ_time_left_handle_frame_get(scene, seq) <
+ SEQ_time_right_handle_frame_get(scene, seq)) &&
+ (SEQ_time_left_handle_frame_get(scene, seq) <= x &&
+ SEQ_time_right_handle_frame_get(scene, seq) >= x)) ||
+ ((SEQ_time_left_handle_frame_get(scene, seq) >
+ SEQ_time_right_handle_frame_get(scene, seq)) &&
+ (SEQ_time_left_handle_frame_get(scene, seq) >= x &&
+ SEQ_time_right_handle_frame_get(scene, seq) <= x))) {
if (SEQ_transform_sequence_can_be_translated(seq)) {
/* Clamp handles to defined size in pixel space. */
- handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
- displen = (float)abs(SEQ_time_left_handle_frame_get(seq) -
- SEQ_time_right_handle_frame_get(seq));
+ handsize = 2.0f * sequence_handle_size_get_clamped(scene, seq, pixelx);
+ displen = (float)abs(SEQ_time_left_handle_frame_get(scene, seq) -
+ SEQ_time_right_handle_frame_get(scene, seq));
/* Don't even try to grab the handles of small strips. */
if (displen / pixelx > 16) {
@@ -337,10 +343,10 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
CLAMP(handsize, 7 * pixelx, 30 * pixelx);
}
- if (handsize + SEQ_time_left_handle_frame_get(seq) >= x) {
+ if (handsize + SEQ_time_left_handle_frame_get(scene, seq) >= x) {
*hand = SEQ_SIDE_LEFT;
}
- else if (-handsize + SEQ_time_right_handle_frame_get(seq) <= x) {
+ else if (-handsize + SEQ_time_right_handle_frame_get(scene, seq) <= x) {
*hand = SEQ_SIDE_RIGHT;
}
}
@@ -583,8 +589,10 @@ static void sequencer_select_side_of_frame(const bContext *C,
const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
- if (((x < CFRA) && (SEQ_time_right_handle_frame_get(seq_iter) <= CFRA)) ||
- ((x >= CFRA) && (SEQ_time_left_handle_frame_get(seq_iter) >= CFRA))) {
+ if (((x < scene->r.cfra) &&
+ (SEQ_time_right_handle_frame_get(scene, seq_iter) <= scene->r.cfra)) ||
+ ((x >= scene->r.cfra) &&
+ (SEQ_time_left_handle_frame_get(scene, seq_iter) >= scene->r.cfra))) {
/* Select left or right. */
seq_iter->flag |= SELECT;
recurs_sel_seq(seq_iter);
@@ -597,8 +605,8 @@ static void sequencer_select_side_of_frame(const bContext *C,
TimeMarker *tmarker;
for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
- if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
- ((x >= CFRA) && (tmarker->frame >= CFRA))) {
+ if (((x < scene->r.cfra) && (tmarker->frame <= scene->r.cfra)) ||
+ ((x >= scene->r.cfra) && (tmarker->frame >= scene->r.cfra))) {
tmarker->flag |= SELECT;
}
else {
@@ -639,8 +647,11 @@ static void sequencer_select_linked_handle(const bContext *C,
case SEQ_SIDE_LEFT:
if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
seq->flag |= SELECT;
- select_active_side(
- ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, SEQ_time_left_handle_frame_get(seq));
+ select_active_side(scene,
+ ed->seqbasep,
+ SEQ_SIDE_LEFT,
+ seq->machine,
+ SEQ_time_left_handle_frame_get(scene, seq));
}
else {
seq->flag |= SELECT;
@@ -653,8 +664,11 @@ static void sequencer_select_linked_handle(const bContext *C,
case SEQ_SIDE_RIGHT:
if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
seq->flag |= SELECT;
- select_active_side(
- ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, SEQ_time_left_handle_frame_get(seq));
+ select_active_side(scene,
+ ed->seqbasep,
+ SEQ_SIDE_RIGHT,
+ seq->machine,
+ SEQ_time_left_handle_frame_get(scene, seq));
}
else {
seq->flag |= SELECT;
@@ -669,7 +683,7 @@ static void sequencer_select_linked_handle(const bContext *C,
else {
select_active_side(
- ed->seqbasep, sel_side, seq->machine, SEQ_time_left_handle_frame_get(seq));
+ scene, ed->seqbasep, sel_side, seq->machine, SEQ_time_left_handle_frame_get(scene, seq));
}
}
}
@@ -734,7 +748,7 @@ static Sequence *seq_select_seq_from_preview(
const bool use_cycle = (!WM_cursor_test_motion_and_update(mval) || extend || toggle);
SeqCollection *strips = SEQ_query_rendered_strips(
- channels, seqbase, scene->r.cfra, sseq->chanshown);
+ scene, channels, seqbase, scene->r.cfra, sseq->chanshown);
/* Allow strips this far from the closest center to be included.
* This allows cycling over center points which are near enough
@@ -921,7 +935,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
sequencer_select_strip_impl(ed, seq, handle_clicked, extend, deselect, toggle);
- select_linked_time(ed->seqbasep, seq);
+ select_linked_time(scene, ed->seqbasep, seq);
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
return OPERATOR_FINISHED;
@@ -1431,18 +1445,18 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op)
if (extend == false) {
ED_sequencer_deselect_all(scene);
}
- const int timeline_frame = CFRA;
+ const int timeline_frame = scene->r.cfra;
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
bool test = false;
switch (side) {
case -1:
- test = (timeline_frame >= SEQ_time_right_handle_frame_get(seq));
+ test = (timeline_frame >= SEQ_time_right_handle_frame_get(scene, seq));
break;
case 1:
- test = (timeline_frame <= SEQ_time_left_handle_frame_get(seq));
+ test = (timeline_frame <= SEQ_time_left_handle_frame_get(scene, seq));
break;
case 2:
- test = SEQ_time_strip_intersects_frame(seq, timeline_frame);
+ test = SEQ_time_strip_intersects_frame(scene, seq, timeline_frame);
break;
}
@@ -1513,10 +1527,10 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
if (seq->flag & SELECT) {
selected = true;
if (sel_side == SEQ_SIDE_LEFT) {
- *frame_limit_p = max_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq));
+ *frame_limit_p = max_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(scene, seq));
}
else {
- *frame_limit_p = min_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq));
+ *frame_limit_p = min_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(scene, seq));
}
}
}
@@ -1525,7 +1539,7 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- select_active_side_range(ed->seqbasep, sel_side, frame_ranges, frame_init);
+ select_active_side_range(scene, ed->seqbasep, sel_side, frame_ranges, frame_init);
ED_outliner_select_sync_from_sequence_tag(C);
@@ -1595,7 +1609,7 @@ static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect, const
SpaceSeq *sseq = CTX_wm_space_seq(C);
SeqCollection *strips = SEQ_query_rendered_strips(
- channels, seqbase, scene->r.cfra, sseq->chanshown);
+ scene, channels, seqbase, scene->r.cfra, sseq->chanshown);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
if (!seq_box_select_rect_image_isect(scene, seq, rect)) {
@@ -1648,15 +1662,15 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
rctf rq;
- seq_rectf(seq, &rq);
+ seq_rectf(scene, seq, &rq);
if (BLI_rctf_isect(&rq, &rectf, NULL)) {
if (handles) {
/* Get the handles draw size. */
float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- float handsize = sequence_handle_size_get_clamped(seq, pixelx);
+ float handsize = sequence_handle_size_get_clamped(scene, seq, pixelx);
/* Right handle. */
- if (rectf.xmax > (SEQ_time_right_handle_frame_get(seq) - handsize)) {
+ if (rectf.xmax > (SEQ_time_right_handle_frame_get(scene, seq) - handsize)) {
if (select) {
seq->flag |= SELECT | SEQ_RIGHTSEL;
}
@@ -1669,7 +1683,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
}
}
/* Left handle. */
- if (rectf.xmin < (SEQ_time_left_handle_frame_get(seq) + handsize)) {
+ if (rectf.xmin < (SEQ_time_left_handle_frame_get(scene, seq) + handsize)) {
if (select) {
seq->flag |= SELECT | SEQ_LEFTSEL;
}
@@ -1953,7 +1967,8 @@ static bool select_grouped_effect(SeqCollection *strips,
return changed;
}
-static bool select_grouped_time_overlap(SeqCollection *strips,
+static bool select_grouped_time_overlap(const Scene *scene,
+ SeqCollection *strips,
ListBase *UNUSED(seqbase),
Sequence *actseq)
{
@@ -1961,8 +1976,10 @@ static bool select_grouped_time_overlap(SeqCollection *strips,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
- if (SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(actseq) &&
- SEQ_time_right_handle_frame_get(seq) > SEQ_time_left_handle_frame_get(actseq)) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) <
+ SEQ_time_right_handle_frame_get(scene, actseq) &&
+ SEQ_time_right_handle_frame_get(scene, seq) >
+ SEQ_time_left_handle_frame_get(scene, actseq)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1972,7 +1989,8 @@ static bool select_grouped_time_overlap(SeqCollection *strips,
}
/* Query strips that are in lower channel and intersect in time with seq_reference. */
-static void query_lower_channel_strips(Sequence *seq_reference,
+static void query_lower_channel_strips(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
@@ -1980,10 +1998,10 @@ static void query_lower_channel_strips(Sequence *seq_reference,
if (seq_test->machine > seq_reference->machine) {
continue; /* Not lower channel. */
}
- if (SEQ_time_right_handle_frame_get(seq_test) <=
- SEQ_time_left_handle_frame_get(seq_reference) ||
- SEQ_time_left_handle_frame_get(seq_test) >=
- SEQ_time_right_handle_frame_get(seq_reference)) {
+ if (SEQ_time_right_handle_frame_get(scene, seq_test) <=
+ SEQ_time_left_handle_frame_get(scene, seq_reference) ||
+ SEQ_time_left_handle_frame_get(scene, seq_test) >=
+ SEQ_time_right_handle_frame_get(scene, seq_reference)) {
continue; /* Not intersecting in time. */
}
SEQ_collection_append_strip(seq_test, collection);
@@ -1992,7 +2010,8 @@ static void query_lower_channel_strips(Sequence *seq_reference,
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
-static bool select_grouped_effect_link(SeqCollection *strips,
+static bool select_grouped_effect_link(const Scene *scene,
+ SeqCollection *strips,
ListBase *seqbase,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
@@ -2000,8 +2019,10 @@ static bool select_grouped_effect_link(SeqCollection *strips,
/* Get collection of strips. */
SEQ_filter_selected_strips(strips);
const int selected_strip_count = SEQ_collection_len(strips);
- SEQ_collection_expand(seqbase, strips, query_lower_channel_strips);
- SEQ_collection_expand(seqbase, strips, SEQ_query_strip_effect_chain);
+ // XXX this uses scene as arg, so it does not work with iterator :( I had thought about this, but
+ // expand function is just so useful... I can just add scene and inject it I guess.....
+ SEQ_collection_expand(scene, seqbase, strips, query_lower_channel_strips);
+ SEQ_collection_expand(scene, seqbase, strips, SEQ_query_strip_effect_chain);
/* Check if other strips will be affected. */
const bool changed = SEQ_collection_len(strips) > selected_strip_count;
@@ -2067,10 +2088,10 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
changed |= select_grouped_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(strips, seqbase, actseq, channel);
+ changed |= select_grouped_effect_link(scene, strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(strips, seqbase, actseq);
+ changed |= select_grouped_time_overlap(scene, strips, seqbase, actseq);
break;
default:
BLI_assert(0);
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index 984d3b1f374..a11b5663620 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -69,15 +69,16 @@ static void thumbnail_endjob(void *data)
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene);
}
-static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area)
+static bool check_seq_need_thumbnails(const Scene *scene, Sequence *seq, rctf *view_area)
{
if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) {
return false;
}
- if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > view_area->xmax) {
+ if (min_ii(SEQ_time_left_handle_frame_get(scene, seq), seq->start) > view_area->xmax) {
return false;
}
- if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < view_area->xmin) {
+ if (max_ii(SEQ_time_right_handle_frame_get(scene, seq), seq->start + seq->len) <
+ view_area->xmin) {
return false;
}
if (seq->machine + 1.0f < view_area->ymin) {
@@ -135,6 +136,7 @@ static void thumbnail_start_job(void *data,
float *UNUSED(progress))
{
ThumbnailDrawJob *tj = data;
+ const Scene *scene = tj->scene;
float frame_step;
GHashIterator gh_iter;
@@ -145,7 +147,7 @@ static void thumbnail_start_job(void *data,
Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter);
ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig);
- if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
+ if (check_seq_need_thumbnails(scene, seq_orig, tj->view_area)) {
seq_get_thumb_image_dimensions(
val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
SEQ_render_thumbnails(
@@ -161,7 +163,7 @@ static void thumbnail_start_job(void *data,
Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter);
ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig);
- if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
+ if (check_seq_need_thumbnails(scene, seq_orig, tj->view_area)) {
seq_get_thumb_image_dimensions(
val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop);
@@ -197,7 +199,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
ThumbDataItem *val_need_update = BLI_ghash_lookup(thumb_data_hash, seq);
- if (val_need_update == NULL && check_seq_need_thumbnails(seq, &v2d->cur)) {
+ if (val_need_update == NULL && check_seq_need_thumbnails(scene, seq, &v2d->cur)) {
ThumbDataItem *val = MEM_callocN(sizeof(ThumbDataItem), "Thumbnail Hash Values");
val->seq_dupli = SEQ_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
val->scene = scene;
@@ -206,7 +208,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi
else {
if (val_need_update != NULL) {
val_need_update->seq_dupli->start = seq->start;
- val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(seq);
+ val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(scene, seq);
}
}
}
@@ -361,18 +363,20 @@ static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame,
return best_frame;
}
-static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame)
+static int sequencer_thumbnail_closest_guaranteed_frame_get(struct Scene *scene,
+ Sequence *seq,
+ int timeline_frame)
{
- if (timeline_frame <= SEQ_time_left_handle_frame_get(seq)) {
- return SEQ_time_left_handle_frame_get(seq);
+ if (timeline_frame <= SEQ_time_left_handle_frame_get(scene, seq)) {
+ return SEQ_time_left_handle_frame_get(scene, seq);
}
/* Set of "guaranteed" thumbnails. */
- const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(seq);
- const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq);
+ const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(scene, seq);
+ const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(scene, seq);
const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step;
const int nearest_guaranted_absolute_frame = relative_base_frame +
- SEQ_time_left_handle_frame_get(seq);
+ SEQ_time_left_handle_frame_get(scene, seq);
return nearest_guaranted_absolute_frame;
}
@@ -387,7 +391,8 @@ static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *conte
previously_displayed);
ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped);
- int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(seq, timeline_frame);
+ int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(
+ context->scene, seq, timeline_frame);
ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped);
ImBuf *closest_in_memory = NULL;
@@ -427,6 +432,11 @@ void draw_seq_strip_thumbnail(View2D *v2d,
float image_height, image_width, thumb_width;
rcti crop;
+ StripElem *se = seq->strip->stripdata;
+ if (se->orig_height == 0 || se->orig_width == 0) {
+ return;
+ }
+
/* If width of the strip too small ignore drawing thumbnails. */
if ((y2 - y1) / pixely <= 20 * U.dpi_fac) {
return;
@@ -445,14 +455,14 @@ void draw_seq_strip_thumbnail(View2D *v2d,
float thumb_y_end = y1 + thumb_height;
float cut_off = 0;
- float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ?
+ float upper_thumb_bound = SEQ_time_has_right_still_frames(scene, seq) ?
(seq->start + seq->len) :
- SEQ_time_right_handle_frame_get(seq);
+ SEQ_time_right_handle_frame_get(scene, seq);
if (seq->type == SEQ_TYPE_IMAGE) {
- upper_thumb_bound = SEQ_time_right_handle_frame_get(seq);
+ upper_thumb_bound = SEQ_time_right_handle_frame_get(scene, seq);
}
- float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, thumb_width, &v2d->cur);
+ float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, thumb_width, &v2d->cur);
float thumb_x_end;
GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq);
@@ -475,8 +485,8 @@ void draw_seq_strip_thumbnail(View2D *v2d,
}
/* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
- if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(seq), timeline_frame, thumb_x_end)) {
- cut_off = SEQ_time_left_handle_frame_get(seq) - timeline_frame;
+ if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(scene, seq), timeline_frame, thumb_x_end)) {
+ cut_off = SEQ_time_left_handle_frame_get(scene, seq) - timeline_frame;
clipped = true;
}
@@ -553,7 +563,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
IMB_freeImBuf(ibuf);
GPU_blend(GPU_BLEND_NONE);
cut_off = 0;
- timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, thumb_width);
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(scene, seq, timeline_frame, thumb_width);
}
last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, timeline_frame, FLT_MAX);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 857ca6d989b..78fa8c379d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -12,6 +12,7 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_scene.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -84,7 +85,7 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
box.xmin = ms->disp_range[0] - 1;
box.xmax = ms->disp_range[1] + 1;
}
- SEQ_timeline_expand_boundbox(SEQ_active_seqbase_get(ed), &box);
+ SEQ_timeline_expand_boundbox(scene, SEQ_active_seqbase_get(ed), &box);
View2D *v2d = &region->v2d;
rcti scrub_rect;
@@ -174,8 +175,7 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
seq_reset_imageofs(sseq);
- imgwidth = (scene->r.size * scene->r.xsch) / 100;
- imgheight = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &imgwidth, &imgheight);
/* Apply aspect, doesn't need to be that accurate. */
imgwidth = (int)(imgwidth * (scene->r.xasp / scene->r.yasp));
@@ -227,11 +227,11 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
float ratio = RNA_float_get(op->ptr, "ratio");
- float winx = (int)(rd->size * rd->xsch) / 100;
- float winy = (int)(rd->size * rd->ysch) / 100;
+ int winx, winy;
+ BKE_render_resolution(rd, false, &winx, &winy);
- float facx = BLI_rcti_size_x(&v2d->mask) / winx;
- float facy = BLI_rcti_size_y(&v2d->mask) / winy;
+ float facx = BLI_rcti_size_x(&v2d->mask) / (float)winx;
+ float facy = BLI_rcti_size_y(&v2d->mask) / (float)winy;
BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f));
@@ -306,8 +306,8 @@ static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strip
int xmargin = FPS;
SEQ_ITERATOR_FOREACH (seq, strips) {
- xmin = min_ii(xmin, SEQ_time_left_handle_frame_get(seq));
- xmax = max_ii(xmax, SEQ_time_right_handle_frame_get(seq));
+ xmin = min_ii(xmin, SEQ_time_left_handle_frame_get(scene, seq));
+ xmax = max_ii(xmax, SEQ_time_right_handle_frame_get(scene, seq));
ymin = min_ii(ymin, seq->machine);
ymax = max_ii(ymax, seq->machine);
@@ -373,7 +373,7 @@ void SEQUENCER_OT_view_selected(wmOperatorType *ot)
/* Api callbacks. */
ot->exec = sequencer_view_selected_exec;
- ot->poll = ED_operator_sequencer_active;
+ ot->poll = sequencer_editing_initialized_and_active;
/* Flags. */
ot->flag = OPTYPE_REGISTER;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index f95c5f196b6..201f132052d 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -374,7 +374,7 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
static void sequencer_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* Context changes. */
switch (wmn->category) {
@@ -548,7 +548,8 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region)
}
View2D *v2d = &region->v2d;
- Editing *ed = SEQ_editing_get(CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return;
@@ -563,7 +564,7 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region)
/* Initialize default view with 7 channels, that are visible even if empty. */
rctf strip_boundbox;
BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, 7.0f);
- SEQ_timeline_expand_boundbox(ed->seqbasep, &strip_boundbox);
+ SEQ_timeline_expand_boundbox(scene, ed->seqbasep, &strip_boundbox);
/* Clamp Y max. Scrubbing area height must be added, so strips aren't occluded. */
rcti scrub_rect;
@@ -629,7 +630,7 @@ static void sequencer_main_region_view2d_changed(const bContext *C, ARegion *reg
static void sequencer_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* Context changes. */
switch (wmn->category) {
@@ -861,7 +862,7 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
static void sequencer_preview_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
WM_gizmomap_tag_refresh(region->gizmo_map);
@@ -932,7 +933,7 @@ static void sequencer_buttons_region_draw(const bContext *C, ARegion *region)
static void sequencer_buttons_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* Context changes. */
switch (wmn->category) {
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index f134cdb95c2..173d976c124 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -14,7 +14,6 @@ set(INC
../../makesrna
../../nodes
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index dd3aac1eae9..5c0f69905fa 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -298,7 +298,6 @@ static float get_default_column_width(const ColumnValues &values)
return values.default_width;
}
static const float float_width = 3;
- static const float int_width = 2;
switch (values.type()) {
case SPREADSHEET_VALUE_TYPE_BOOL:
return 2.0f;
@@ -312,13 +311,12 @@ static float get_default_column_width(const ColumnValues &values)
case SPREADSHEET_VALUE_TYPE_FLOAT3:
return 3.0f * float_width;
case SPREADSHEET_VALUE_TYPE_COLOR:
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
return 4.0f * float_width;
case SPREADSHEET_VALUE_TYPE_INSTANCES:
return 8.0f;
case SPREADSHEET_VALUE_TYPE_STRING:
return 5.0f;
- case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
- return 4.0f * int_width;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return 2.0f;
}
@@ -438,7 +436,7 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
switch (wmn->category) {
case NC_SCENE: {
@@ -488,7 +486,7 @@ static void spreadsheet_header_region_free(ARegion *UNUSED(region))
static void spreadsheet_header_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
switch (wmn->category) {
case NC_SCENE: {
@@ -572,7 +570,7 @@ static void spreadsheet_footer_region_listener(const wmRegionListenerParams *UNU
static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
switch (wmn->category) {
case NC_SCENE: {
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
index 76c7131e268..6a09d3f84c6 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
@@ -27,9 +27,8 @@ class DataSource {
* column. (This can be made a bit more generic in the future when necessary.)
*/
virtual void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> /*fn*/) const
{
- UNUSED_VARS(fn);
}
/**
@@ -37,9 +36,8 @@ class DataSource {
* returned.
*/
virtual std::unique_ptr<ColumnValues> get_column_values(
- const SpreadsheetColumnID &column_id) const
+ const SpreadsheetColumnID & /*column_id*/) const
{
- UNUSED_VARS(column_id);
return {};
}
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 f5315b616d0..3290c0ddd87 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -1,8 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_index_mask_ops.hh"
#include "BLI_virtual_array.hh"
+#include "BKE_attribute.hh"
#include "BKE_context.h"
+#include "BKE_curves.hh"
#include "BKE_editmesh.h"
#include "BKE_geometry_fields.hh"
#include "BKE_global.h"
@@ -20,6 +23,7 @@
#include "DEG_depsgraph_query.h"
+#include "ED_curves_sculpt.h"
#include "ED_spreadsheet.h"
#include "NOD_geometry_nodes_eval_log.hh"
@@ -64,7 +68,12 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
- if (component_->attribute_domain_num(domain_) == 0) {
+ if (!component_->attributes().has_value()) {
+ return;
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+
+ if (attributes.domain_size(domain_) == 0) {
return;
}
@@ -73,8 +82,9 @@ void GeometryDataSource::foreach_default_column_ids(
}
extra_columns_.foreach_default_column_ids(fn);
- component_->attribute_foreach(
- [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+
+ attributes.for_all(
+ [&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
if (meta_data.domain != domain_) {
return true;
}
@@ -113,7 +123,11 @@ void GeometryDataSource::foreach_default_column_ids(
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- const int domain_num = component_->attribute_domain_num(domain_);
+ if (!component_->attributes().has_value()) {
+ return {};
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+ const int domain_num = attributes.domain_size(domain_);
if (domain_num == 0) {
return {};
}
@@ -154,52 +168,56 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
if (const Mesh *mesh = component.get_for_read()) {
+ const Span<MEdge> edges = mesh->edges();
+ const Span<MPoly> polys = mesh->polys();
+ const Span<MLoop> loops = mesh->loops();
+
if (domain_ == ATTR_DOMAIN_EDGE) {
if (STREQ(column_id.name, "Vertex 1")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
- return mesh->medge[index].v1;
+ column_id.name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
+ return edges[index].v1;
}));
}
if (STREQ(column_id.name, "Vertex 2")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
- return mesh->medge[index].v2;
+ column_id.name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
+ return edges[index].v2;
}));
}
}
else if (domain_ == ATTR_DOMAIN_FACE) {
if (STREQ(column_id.name, "Corner Start")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
- return mesh->mpoly[index].loopstart;
+ column_id.name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
+ return polys[index].loopstart;
}));
}
if (STREQ(column_id.name, "Corner Size")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
- return mesh->mpoly[index].totloop;
+ column_id.name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
+ return polys[index].totloop;
}));
}
}
else if (domain_ == ATTR_DOMAIN_CORNER) {
if (STREQ(column_id.name, "Vertex")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
- return mesh->mloop[index].v;
+ column_id.name, VArray<int>::ForFunc(loops.size(), [loops](int64_t index) {
+ return loops[index].v;
}));
}
if (STREQ(column_id.name, "Edge")) {
return std::make_unique<ColumnValues>(
- column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
- return mesh->mloop[index].e;
+ column_id.name, VArray<int>::ForFunc(loops.size(), [loops](int64_t index) {
+ return loops[index].e;
}));
}
}
}
}
- bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
+ bke::GAttributeReader attribute = attributes.lookup(column_id.name);
if (!attribute) {
return {};
}
@@ -213,87 +231,112 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
int GeometryDataSource::tot_rows() const
{
- return component_->attribute_domain_num(domain_);
+ if (!component_->attributes().has_value()) {
+ return {};
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+ return attributes.domain_size(domain_);
}
-/**
- * Only data sets corresponding to mesh objects in edit mode currently support selection filtering.
- */
bool GeometryDataSource::has_selection_filter() const
{
Object *object_orig = DEG_get_original_object(object_eval_);
- if (object_orig->type != OB_MESH) {
- return false;
- }
- if (object_orig->mode != OB_MODE_EDIT) {
- return false;
- }
- if (component_->type() != GEO_COMPONENT_TYPE_MESH) {
- return false;
- }
-
- return true;
-}
-
-static IndexMask index_mask_from_bool_array(const VArray<bool> &selection,
- Vector<int64_t> &indices)
-{
- for (const int i : selection.index_range()) {
- if (selection[i]) {
- indices.append(i);
+ switch (component_->type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ if (object_orig->type != OB_MESH) {
+ return false;
+ }
+ if (object_orig->mode != OB_MODE_EDIT) {
+ return false;
+ }
+ return true;
}
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (object_orig->type != OB_CURVES) {
+ return false;
+ }
+ if (object_orig->mode != OB_MODE_SCULPT_CURVES) {
+ return false;
+ }
+ return true;
+ }
+ default:
+ return false;
}
- return IndexMask(indices);
}
IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const
{
std::lock_guard lock{mutex_};
+ const IndexMask full_range(this->tot_rows());
+
+ switch (component_->type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ BLI_assert(object_eval_->type == OB_MESH);
+ BLI_assert(object_eval_->mode == OB_MODE_EDIT);
+ Object *object_orig = DEG_get_original_object(object_eval_);
+ const Mesh *mesh_eval = geometry_set_.get_mesh_for_read();
+ const bke::AttributeAccessor attributes_eval = mesh_eval->attributes();
+ Mesh *mesh_orig = (Mesh *)object_orig->data;
+ BMesh *bm = mesh_orig->edit_mesh->bm;
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
+ if (orig_indices != nullptr) {
+ /* Use CD_ORIGINDEX layer if it exists. */
+ VArray<bool> selection = attributes_eval.adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm, orig_indices](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ const BMVert *vert = BM_vert_at_index(bm, i_orig);
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_ops::find_indices_from_virtual_array(
+ full_range, selection, 1024, indices);
+ }
- BLI_assert(object_eval_->mode == OB_MODE_EDIT);
- BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
- Object *object_orig = DEG_get_original_object(object_eval_);
- const MeshComponent *mesh_component = static_cast<const MeshComponent *>(component_);
- const Mesh *mesh_eval = mesh_component->get_for_read();
- Mesh *mesh_orig = (Mesh *)object_orig->data;
- BMesh *bm = mesh_orig->edit_mesh->bm;
- BM_mesh_elem_table_ensure(bm, BM_VERT);
-
- const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
- if (orig_indices != nullptr) {
- /* Use CD_ORIGINDEX layer if it exists. */
- VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
- VArray<bool>::ForFunc(mesh_eval->totvert,
- [bm, orig_indices](int vertex_index) -> bool {
- const int i_orig = orig_indices[vertex_index];
- if (i_orig < 0) {
- return false;
- }
- if (i_orig >= bm->totvert) {
- return false;
- }
- BMVert *vert = bm->vtable[i_orig];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- }),
- ATTR_DOMAIN_POINT,
- domain_);
- return index_mask_from_bool_array(selection, indices);
- }
-
- if (mesh_eval->totvert == bm->totvert) {
- /* Use a simple heuristic to match original vertices to evaluated ones. */
- VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
- VArray<bool>::ForFunc(mesh_eval->totvert,
- [bm](int vertex_index) -> bool {
- BMVert *vert = bm->vtable[vertex_index];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- }),
- ATTR_DOMAIN_POINT,
- domain_);
- return index_mask_from_bool_array(selection, indices);
- }
-
- return IndexMask(mesh_eval->totvert);
+ if (mesh_eval->totvert == bm->totvert) {
+ /* Use a simple heuristic to match original vertices to evaluated ones. */
+ VArray<bool> selection = attributes_eval.adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm](int vertex_index) -> bool {
+ const BMVert *vert = BM_vert_at_index(bm, vertex_index);
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_ops::find_indices_from_virtual_array(
+ full_range, selection, 2048, indices);
+ }
+
+ return full_range;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ BLI_assert(object_eval_->type == OB_CURVES);
+ BLI_assert(object_eval_->mode == OB_MODE_SCULPT_CURVES);
+ const CurveComponent &component = static_cast<const CurveComponent &>(*component_);
+ const Curves &curves_id = *component.get_for_read();
+ switch (domain_) {
+ case ATTR_DOMAIN_POINT:
+ return sculpt_paint::retrieve_selected_points(curves_id, indices);
+ case ATTR_DOMAIN_CURVE:
+ return sculpt_paint::retrieve_selected_curves(curves_id, indices);
+ default:
+ BLI_assert_unreachable();
+ }
+ return full_range;
+ }
+ default:
+ return full_range;
+ }
}
void VolumeDataSource::foreach_default_column_ids(
@@ -398,10 +441,15 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
geometry_set.get_component_for_write<PointCloudComponent>();
pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
}
+ else if (object_orig->type == OB_CURVES) {
+ const Curves &curves_id = *(const Curves *)object_orig->data;
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ curve_component.replace(&const_cast<Curves &>(curves_id), GeometryOwnershipType::ReadOnly);
+ }
}
else {
if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
- Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
+ Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval);
if (mesh == nullptr) {
return geometry_set;
}
@@ -472,18 +520,6 @@ static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
}
}
-static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
-{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
- return (GeometryComponentType)sspreadsheet->geometry_component_type;
- }
- if (object_eval->type == OB_POINTCLOUD) {
- return GEO_COMPONENT_TYPE_POINT_CLOUD;
- }
- return GEO_COMPONENT_TYPE_MESH;
-}
-
class GeometryComponentCacheKey : public SpreadsheetCache::Key {
public:
/* Use the pointer to the geometry component as a key to detect when the geometry changed. */
@@ -527,23 +563,23 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
std::make_unique<GeometryComponentCacheKey>(component));
const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
- const int domain_num = component.attribute_domain_num(domain);
+ const int domain_num = component.attribute_domain_size(domain);
for (const auto item : fields_to_show.items()) {
- StringRef name = item.key;
+ const StringRef name = item.key;
const GField &field = item.value;
/* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
GArray<> evaluated_array(field.cpp_type(), domain_num);
- bke::GeometryComponentFieldContext field_context{component, domain};
+ bke::GeometryFieldContext field_context{component, domain};
fn::FieldEvaluator field_evaluator{field_context, domain_num};
field_evaluator.add_with_destination(field, evaluated_array);
field_evaluator.evaluate();
return evaluated_array;
});
- r_extra_columns.add(std::move(name), evaluated_array.as_span());
+ r_extra_columns.add(name, evaluated_array.as_span());
}
}
@@ -551,9 +587,9 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
- const GeometryComponentType component_type = get_display_component_type(C, object_eval);
+ const GeometryComponentType component_type = GeometryComponentType(
+ sspreadsheet->geometry_component_type);
GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
-
if (!geometry_set.has(component_type)) {
return {};
}
@@ -563,10 +599,10 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
if (component_type == GEO_COMPONENT_TYPE_VOLUME) {
- return std::make_unique<VolumeDataSource>(geometry_set);
+ return std::make_unique<VolumeDataSource>(std::move(geometry_set));
}
return std::make_unique<GeometryDataSource>(
- object_eval, geometry_set, component_type, domain, std::move(extra_columns));
+ object_eval, std::move(geometry_set), component_type, domain, std::move(extra_columns));
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index 04b4f6d8d06..71bc4768949 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -68,10 +68,6 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
- /**
- * Only data sets corresponding to mesh objects in edit mode currently support selection
- * filtering.
- */
bool has_selection_filter() const override;
IndexMask apply_selection_filter(Vector<int64_t> &indices) const;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index ee22f4173ab..146b6091bde 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -145,7 +145,7 @@ void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
* to the right side of the number, which it didn't have with the button. */
char element_count[7];
BLI_str_format_decimal_unit(element_count, *count);
- UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
+ UI_but_hint_drawstr_set((uiBut *)this->view_item_button(), element_count);
}
}
@@ -194,7 +194,7 @@ std::optional<int> GeometryDataSetTreeViewItem::count() const
}
if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
- return component->attribute_domain_num(*domain_);
+ return component->attribute_domain_size(*domain_);
}
return 0;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
index c7170cd1da3..e1f13f05715 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
@@ -273,7 +273,7 @@ void draw_spreadsheet_in_region(const bContext *C,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
draw_index_column_background(pos, region, drawer);
draw_alternating_row_overlay(pos, scroll_offset_y, region, drawer);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index e19a343335a..3fe4c7c8ee0 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -19,6 +19,8 @@
#include "BLF_api.h"
+#include "BLT_translation.h"
+
namespace blender::ed::spreadsheet {
class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
@@ -193,7 +195,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
else if (data.type().is<ColorGeometry4b>()) {
const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
- this->draw_int_vector(params, {value.r, value.g, value.b, value.a});
+ this->draw_byte_color(params, value);
}
else if (data.type().is<InstanceReference>()) {
const InstanceReference value = data.get<InstanceReference>(real_index);
@@ -285,7 +287,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
for (const int i : values.index_range()) {
std::stringstream ss;
const float value = values[i];
- ss << std::fixed << std::setprecision(3) << value;
+ ss << " " << std::fixed << std::setprecision(3) << value;
const std::string value_str = ss.str();
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -308,13 +310,16 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
}
- void draw_int_vector(const CellDrawParams &params, const Span<int> values) const
+ void draw_byte_color(const CellDrawParams &params, const ColorGeometry4b color) const
{
- BLI_assert(!values.is_empty());
+ const ColorGeometry4f float_color = color.decode();
+ Span<float> values(&float_color.r, 4);
const float segment_width = (float)params.width / values.size();
for (const int i : values.index_range()) {
- const int value = values[i];
- const std::string value_str = std::to_string(value);
+ std::stringstream ss;
+ const float value = values[i];
+ ss << " " << std::fixed << std::setprecision(3) << value;
+ const std::string value_str = ss.str();
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
@@ -330,9 +335,24 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
0,
0,
nullptr);
- /* Right-align Ints. */
+ /* Right-align Floats. */
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
+
+ /* Tooltip showing raw byte values. Encode values in pointer to avoid memory allocation. */
+ UI_but_func_tooltip_set(
+ but,
+ [](bContext * /*C*/, void *argN, const char *UNUSED(tip)) {
+ const uint32_t uint_color = POINTER_AS_UINT(argN);
+ ColorGeometry4b color = *(ColorGeometry4b *)&uint_color;
+ return BLI_sprintfN(TIP_("Byte Color (sRGB encoded):\n%3d %3d %3d %3d"),
+ color.r,
+ color.g,
+ color.b,
+ color.a);
+ },
+ POINTER_FROM_UINT(*(uint32_t *)&color),
+ nullptr);
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index e1ff4b59b14..6806e185cfe 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -195,25 +195,82 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
else if (column_data.type().is<ColorGeometry4f>()) {
const ColorGeometry4f value = row_filter.value_color;
- const float threshold_sq = pow2f(row_filter.threshold);
- apply_filter_operation(
- column_data.typed<ColorGeometry4f>(),
- [&](const ColorGeometry4f cell) { return len_squared_v4v4(cell, value) <= threshold_sq; },
- prev_mask,
- new_indices);
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = pow2f(row_filter.threshold);
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return len_squared_v4v4(cell, value) <= threshold_sq;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
}
else if (column_data.type().is<ColorGeometry4b>()) {
- const ColorGeometry4b value = row_filter.value_byte_color;
- const float4 value_floats = {(float)value.r, (float)value.g, (float)value.b, (float)value.a};
- const float threshold_sq = pow2f(row_filter.threshold);
- apply_filter_operation(
- column_data.typed<ColorGeometry4b>(),
- [&](const ColorGeometry4b cell) {
- const float4 cell_floats = {(float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a};
- return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq;
- },
- prev_mask,
- new_indices);
+ const ColorGeometry4f value = row_filter.value_color;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float4 value_floats = {
+ (float)value.r, (float)value.g, (float)value.b, (float)value.a};
+ const float threshold_sq = pow2f(row_filter.threshold);
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell_bytes) {
+ const ColorGeometry4f cell = cell_bytes.decode();
+ const float4 cell_floats = {
+ (float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a};
+ return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell_bytes) {
+ const ColorGeometry4f cell = cell_bytes.decode();
+ return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell_bytes) {
+ const ColorGeometry4f cell = cell_bytes.decode();
+ return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
}
else if (column_data.type().is<InstanceReference>()) {
const StringRef value = row_filter.value_string;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index d42a371c666..548e6cf29e4 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -39,11 +39,7 @@ static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name)
static std::string operation_string(const eSpreadsheetColumnValueType data_type,
const eSpreadsheetFilterOperation operation)
{
- if (ELEM(data_type,
- SPREADSHEET_VALUE_TYPE_BOOL,
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- SPREADSHEET_VALUE_TYPE_COLOR,
- SPREADSHEET_VALUE_TYPE_BYTE_COLOR)) {
+ if (ELEM(data_type, SPREADSHEET_VALUE_TYPE_BOOL, SPREADSHEET_VALUE_TYPE_INSTANCES)) {
return "=";
}
@@ -94,7 +90,8 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
return row_filter.value_string;
}
return "";
- case SPREADSHEET_VALUE_TYPE_COLOR: {
+ case SPREADSHEET_VALUE_TYPE_COLOR:
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR: {
std::ostringstream result;
result.precision(3);
result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1]
@@ -103,14 +100,6 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
- case SPREADSHEET_VALUE_TYPE_BYTE_COLOR: {
- std::ostringstream result;
- result.precision(3);
- result << std::fixed << "(" << (int)row_filter.value_byte_color[0] << ", "
- << (int)row_filter.value_byte_color[1] << ", " << (int)row_filter.value_byte_color[2]
- << ", " << (int)row_filter.value_byte_color[3] << ")";
- return result.str();
- }
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return "";
}
@@ -237,16 +226,16 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_COLOR:
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE);
- uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
+ uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ }
break;
case SPREADSHEET_VALUE_TYPE_STRING:
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
break;
- case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
- uiItemR(layout, filter_ptr, "value_byte_color", 0, IFACE_("Value"), ICON_NONE);
- uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
- break;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR);
break;
diff --git a/source/blender/editors/space_statusbar/CMakeLists.txt b/source/blender/editors/space_statusbar/CMakeLists.txt
index fba40c1ec26..cf0ccd4e552 100644
--- a/source/blender/editors/space_statusbar/CMakeLists.txt
+++ b/source/blender/editors/space_statusbar/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index 273c0375fb0..9c64235870c 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -83,7 +83,7 @@ static void statusbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
static void statusbar_header_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index 6410e971a66..38787a84fce 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index ea35a8c0fa7..45cf557c4b4 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -30,6 +30,7 @@
#include "UI_view2d.h"
#include "RNA_access.h"
+#include "RNA_path.h"
#include "text_format.h"
#include "text_intern.h" /* own include */
@@ -108,7 +109,7 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
static void text_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
SpaceText *st = area->spacedata.first;
/* context changes */
@@ -325,7 +326,7 @@ static void text_drop_paste(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_get_local_ID(drag, 0);
/* copy drag path to properties */
- text = RNA_path_full_ID_py(G_MAIN, id);
+ text = RNA_path_full_ID_py(id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 54735a4d481..461606f63aa 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -314,7 +314,7 @@ static int doc_scroll = 0;
static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- /* NOTE(campbell): this code could be refactored or rewritten. */
+ /* NOTE(@campbellbarton): this code could be refactored or rewritten. */
SpaceText *st = CTX_wm_space_text(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index c93ffccd477..0f0ecb0e4bf 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -997,7 +997,7 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
/* background so highlights don't go behind the scrollbar */
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_BACK);
immRecti(pos, back->xmin, back->ymin, back->xmax, back->ymax);
immUnbindProgram();
@@ -1076,7 +1076,7 @@ static void draw_documentation(const SpaceText *st, ARegion *region)
/* Draw panel */
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_BACK);
immRecti(pos, x, y, x + boxw, y - boxh);
@@ -1206,7 +1206,7 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_SHADE1);
immRecti(pos, x - 1, y + 1, x + boxw + 1, y - boxh - 1);
@@ -1232,7 +1232,7 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
if (item == sel) {
uint posi = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_SHADE2);
immRecti(posi, x + margin_x, y - 3, x + margin_x + w, y + lheight - 3);
@@ -1280,7 +1280,7 @@ static void draw_text_decoration(SpaceText *st, ARegion *region)
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Draw the selection */
if (text->curl != text->sell || text->curc != text->selc) {
@@ -1663,7 +1663,7 @@ void draw_text_main(SpaceText *st, ARegion *region)
if (st->showlinenrs) {
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_GRID);
immRecti(pos, 0, 0, TXT_NUMCOL_WIDTH(st), region->winy);
immUnbindProgram();
@@ -1726,7 +1726,7 @@ void draw_text_main(SpaceText *st, ARegion *region)
if (margin_column_x >= x) {
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float margin_color[4];
UI_GetThemeColor4fv(TH_TEXT, margin_color);
margin_color[3] = 0.2f;
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index f7d7f9c6238..4b3ee1c15c7 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -264,7 +264,7 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -287,18 +287,19 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_
else if ((*str != '#') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
- /* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_osl_format_identifier()' */
+ /* Special `vars(v)` or built-in `keywords(b)` */
+ /* keep in sync with `txtfmt_osl_format_identifier()`. */
if ((i = txtfmt_lua_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_lua_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
}
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index 27dc1174c49..575eadeee66 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -285,7 +285,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -298,18 +298,19 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
else if ((*str != '#') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space or delimiters. so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_osl_format_identifier()' */
+ /* keep in sync with `txtfmt_osl_format_identifier()`. */
if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
index 7c2f098f0fa..7c2c4829ad3 100644
--- a/source/blender/editors/space_text/text_format_pov.c
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -857,7 +857,7 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -880,18 +880,19 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_
else if (text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_pov_format_identifier()' */
+ /* keep in sync with `txtfmt_pov_format_identifier()`. */
if ((i = txtfmt_pov_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_pov_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) { prev = FMT_TYPE_RESERVED;
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
index 6844f08cca6..dda3b7089fe 100644
--- a/source/blender/editors/space_text/text_format_pov_ini.c
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -435,7 +435,7 @@ static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -458,18 +458,19 @@ static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool
else if ((*str != '#') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_ini_format_identifier()' */
+ /* keep in sync with `txtfmt_ini_format_identifier()`. */
if ((i = txtfmt_ini_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_ini_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
}
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 47d0168195b..28f536ffa98 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -59,9 +59,9 @@ static int txtfmt_py_find_builtinfunc(const char *string)
/* clang-format off */
if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
@@ -425,7 +425,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
}
*fmt = FMT_TYPE_STRING;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -447,18 +447,19 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
else if ((*str != '@') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_py_format_identifier()' */
+ /* keep in sync with `txtfmt_py_format_identifier()`. */
if ((i = txtfmt_py_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_py_find_decorator(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 05d51cf6362..f0196bf8e00 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -273,7 +273,7 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op))
PointerRNA ptr, idptr;
PropertyRNA *prop;
- text = BKE_text_add(bmain, "Text");
+ text = BKE_text_add(bmain, DATA_("Text"));
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
@@ -3396,7 +3396,8 @@ static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wm
return OPERATOR_PASS_THROUGH;
}
- if (!(event->ascii >= '0' && event->ascii <= '9')) {
+ const char event_ascii = WM_event_utf8_to_ascii(event);
+ if (!(event_ascii >= '0' && event_ascii <= '9')) {
return OPERATOR_PASS_THROUGH;
}
@@ -3406,7 +3407,7 @@ static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wm
}
jump_to *= 10;
- jump_to += (int)(event->ascii - '0');
+ jump_to += (int)(event_ascii - '0');
txt_move_toline(text, jump_to - 1, 0);
last_jump = time;
@@ -3495,16 +3496,8 @@ static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
char str[BLI_UTF8_MAX + 1];
- size_t len;
-
- if (event->utf8_buf[0]) {
- len = BLI_str_utf8_size_safe(event->utf8_buf);
- memcpy(str, event->utf8_buf, len);
- }
- else {
- /* in theory, ghost can set value to extended ascii here */
- len = BLI_str_utf8_from_unicode(event->ascii, str, sizeof(str) - 1);
- }
+ const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
+ memcpy(str, event->utf8_buf, len);
str[len] = '\0';
RNA_string_set(op->ptr, "text", str);
diff --git a/source/blender/editors/space_topbar/CMakeLists.txt b/source/blender/editors/space_topbar/CMakeLists.txt
index 26c6b796df5..f529c855e6d 100644
--- a/source/blender/editors/space_topbar/CMakeLists.txt
+++ b/source/blender/editors/space_topbar/CMakeLists.txt
@@ -10,7 +10,6 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index e9a9e690e60..ee0e0c3ef46 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -116,7 +116,7 @@ static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *regi
static void topbar_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -146,7 +146,7 @@ static void topbar_main_region_listener(const wmRegionListenerParams *params)
static void topbar_header_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -155,6 +155,9 @@ static void topbar_header_listener(const wmRegionListenerParams *params)
ED_region_tag_redraw(region);
}
break;
+ case NC_WORKSPACE:
+ ED_region_tag_redraw(region);
+ break;
case NC_SPACE:
if (wmn->data == ND_SPACE_INFO) {
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index a76cd3377bc..100266f4433 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -15,7 +15,6 @@ set(INC
../../makesrna
../../render
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/mantaflow/extern
@@ -61,7 +60,7 @@ set(SRC
view3d_ops.c
view3d_placement.c
view3d_project.c
- view3d_select.c
+ view3d_select.cc
view3d_snap.c
view3d_utils.c
view3d_view.c
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 8add6886584..36ced74a8b7 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -16,6 +16,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -67,9 +68,9 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
if (facemap_data) {
GPU_blend(GPU_BLEND_ALPHA);
- const MVert *mvert = me->mvert;
- const MPoly *mpoly = me->mpoly;
- const MLoop *mloop = me->mloop;
+ const MVert *verts = BKE_mesh_verts(me);
+ const MPoly *polys = BKE_mesh_polys(me);
+ const MLoop *loops = BKE_mesh_loops(me);
int mpoly_len = me->totpoly;
int mloop_len = me->totloop;
@@ -95,12 +96,12 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
int i;
if (me->runtime.looptris.array) {
const MLoopTri *mlt = me->runtime.looptris.array;
- for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) {
+ for (mp = polys, i = 0; i < mpoly_len; i++, mp++) {
if (facemap_data[i] == facemap) {
for (int j = 2; j < mp->totloop; j++) {
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[0]].v].co);
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[1]].v].co);
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[2]].v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), verts[loops[mlt->tri[0]].v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), verts[loops[mlt->tri[1]].v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), verts[loops[mlt->tri[2]].v].co);
vbo_len_used += 3;
mlt++;
}
@@ -112,15 +113,15 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
}
else {
/* No tessellation data, fan-fill. */
- for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) {
+ for (mp = polys, i = 0; i < mpoly_len; i++, mp++) {
if (facemap_data[i] == facemap) {
- const MLoop *ml_start = &mloop[mp->loopstart];
+ const MLoop *ml_start = &loops[mp->loopstart];
const MLoop *ml_a = ml_start + 1;
const MLoop *ml_b = ml_start + 2;
for (int j = 2; j < mp->totloop; j++) {
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_start->v].co);
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_a->v].co);
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_b->v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), verts[ml_start->v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), verts[ml_a->v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), verts[ml_b->v].co);
vbo_len_used += 3;
ml_a++;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 9ed2fec96db..86c796e6be4 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -960,7 +960,7 @@ static void view3d_widgets(void)
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera);
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera_view);
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_empty_image);
- /* TODO(campbell): Not working well enough, disable for now. */
+ /* TODO(@campbellbarton): Not working well enough, disable for now. */
#if 0
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_armature_spline);
#endif
@@ -1037,7 +1037,7 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
wmWindow *window = params->window;
ScrArea *area = params->area;
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
const Scene *scene = params->scene;
View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
@@ -1210,6 +1210,9 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
break;
}
break;
+ case NC_NODE:
+ ED_region_tag_redraw(region);
+ break;
case NC_WORLD:
switch (wmn->data) {
case ND_WORLD_DRAW:
@@ -1300,6 +1303,10 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
ED_region_tag_redraw(region);
}
break;
+ case NC_WORKSPACE:
+ /* In case the region displays workspace settings. */
+ ED_region_tag_redraw(region);
+ break;
}
}
@@ -1398,7 +1405,7 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
WM_msg_subscribe_rna_anon_type(mbus, ObjectDisplay, &msg_sub_value_region_tag_redraw);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
if (obact != NULL) {
switch (obact->mode) {
case OB_MODE_PARTICLE_EDIT:
@@ -1433,7 +1440,7 @@ static void view3d_main_region_cursor(wmWindow *win, ScrArea *area, ARegion *reg
}
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit) {
WM_cursor_set(win, WM_CURSOR_EDIT);
}
@@ -1460,7 +1467,7 @@ static void view3d_header_region_draw(const bContext *C, ARegion *region)
static void view3d_header_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -1677,7 +1684,7 @@ static void view3d_buttons_region_layout(const bContext *C, ARegion *region)
static void view3d_buttons_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
/* context changes */
switch (wmn->category) {
@@ -1800,7 +1807,7 @@ static void view3d_tools_region_draw(const bContext *C, ARegion *region)
static void space_view3d_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
- wmNotifier *wmn = params->notifier;
+ const wmNotifier *wmn = params->notifier;
View3D *v3d = area->spacedata.first;
/* context changes */
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 6786bf8404e..5a5747bdf84 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -36,6 +36,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -1283,7 +1284,7 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob && (BKE_object_is_in_editmode_vgroup(ob) || BKE_object_is_in_wpaint_select_vert(ob))) {
MDeformVert *dvert_act = ED_mesh_active_dvert_get_only(ob);
if (dvert_act) {
@@ -1683,7 +1684,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
{
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
switch (event) {
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index 395df42b2cb..195806fbecc 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -16,6 +16,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -495,6 +496,16 @@ static void v3d_cursor_eventstate_save_xy(SnapCursorDataIntern *cursor_snap,
}
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+static void v3d_cursor_eventstate_save_modifier(SnapCursorDataIntern *data_intern,
+ const wmWindowManager *wm)
+{
+ if (!wm || !wm->winactive) {
+ return;
+ }
+ const wmEvent *event = wm->winactive->eventstate;
+ data_intern->last_eventstate.modifier = event->modifier;
+}
+
static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const wmWindowManager *wm)
{
if (!wm || !wm->winactive) {
@@ -582,10 +593,14 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
{
SnapCursorDataIntern *data_intern = &g_data_intern;
V3DSnapCursorData *snap_data = &data_intern->snap_data;
- v3d_cursor_snap_context_ensure(scene);
+
+ const bool use_surface_nor = state->plane_orient == V3D_PLACE_ORIENT_SURFACE;
+ const bool use_surface_co = state->plane_depth == V3D_PLACE_DEPTH_SURFACE;
+ const bool calc_plane_omat = v3d_cursor_snap_calc_plane();
float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3];
eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
+ eSnapMode snap_elements = v3d_cursor_snap_elements(state, scene);
int snap_elem_index[3] = {-1, -1, -1};
int index = -1;
@@ -594,86 +609,90 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
zero_v3(face_nor);
unit_m3(omat);
- eSnapMode snap_elements = v3d_cursor_snap_elements(state, scene);
- data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE;
- const bool calc_plane_omat = v3d_cursor_snap_calc_plane();
- if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE)) {
- data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
- snap_elements |= SCE_SNAP_MODE_FACE;
- }
+ if (use_surface_nor || use_surface_co) {
+ v3d_cursor_snap_context_ensure(scene);
+
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE;
+ if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE_RAYCAST;
+ snap_elements |= SCE_SNAP_MODE_FACE_RAYCAST;
+ }
- snap_data->is_enabled = true;
+ snap_data->is_enabled = true;
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- if (!(state->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE)) {
- snap_data->is_snap_invert = v3d_cursor_is_snap_invert(data_intern, wm);
-
- const ToolSettings *ts = scene->toolsettings;
- if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) {
- snap_data->is_enabled = false;
- if (!calc_plane_omat) {
- snap_data->snap_elem = SCE_SNAP_MODE_NONE;
- return;
+ if (!(state->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE)) {
+ snap_data->is_snap_invert = v3d_cursor_is_snap_invert(data_intern, wm);
+
+ const ToolSettings *ts = scene->toolsettings;
+ if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) {
+ snap_data->is_enabled = false;
+ if (!calc_plane_omat) {
+ snap_data->snap_elem = SCE_SNAP_MODE_NONE;
+ return;
+ }
+ snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE_RAYCAST;
}
- snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
}
- }
#endif
- if (snap_elements & SCE_SNAP_MODE_GEOM) {
- float prev_co[3] = {0.0f};
- if (state->prevpoint) {
- copy_v3_v3(prev_co, state->prevpoint);
- }
- else {
- snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
- }
+ if (snap_elements & SCE_SNAP_MODE_GEOM) {
+ float prev_co[3] = {0.0f};
+ if (state->prevpoint) {
+ copy_v3_v3(prev_co, state->prevpoint);
+ }
+ else {
+ snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
- eSnapEditType edit_mode_type = (state->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL) ?
- SNAP_GEOM_FINAL :
- (state->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE) ?
- SNAP_GEOM_CAGE :
- SNAP_GEOM_EDIT;
-
- bool use_occlusion_test = (state->flag & V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE) ? false : true;
-
- float dist_px = 12.0f * U.pixelsize;
-
- snap_elem = ED_transform_snap_object_project_view3d_ex(
- data_intern->snap_context_v3d,
- depsgraph,
- region,
- v3d,
- snap_elements,
- &(const struct SnapObjectParams){
- .snap_target_select = SCE_SNAP_TARGET_ALL,
- .edit_mode_type = edit_mode_type,
- .use_occlusion_test = use_occlusion_test,
- },
- mval_fl,
- prev_co,
- &dist_px,
- co,
- no,
- &index,
- NULL,
- obmat,
- face_nor);
- }
-
- if (is_zero_v3(face_nor)) {
- face_nor[state->plane_axis] = 1.0f;
+ eSnapEditType edit_mode_type = (state->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL) ?
+ SNAP_GEOM_FINAL :
+ (state->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE) ?
+ SNAP_GEOM_CAGE :
+ SNAP_GEOM_EDIT;
+
+ bool use_occlusion_test = (state->flag & V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE) ? false :
+ true;
+
+ float dist_px = 12.0f * U.pixelsize;
+
+ snap_elem = ED_transform_snap_object_project_view3d_ex(
+ data_intern->snap_context_v3d,
+ depsgraph,
+ region,
+ v3d,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
+ .edit_mode_type = edit_mode_type,
+ .use_occlusion_test = use_occlusion_test,
+ },
+ NULL,
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ obmat,
+ face_nor);
+ }
}
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ else {
+ v3d_cursor_eventstate_save_modifier(data_intern, wm);
+ }
+#endif
if (calc_plane_omat) {
RegionView3D *rv3d = region->regiondata;
- bool orient_surface = (snap_elem != SCE_SNAP_MODE_NONE) &&
- (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
+ bool orient_surface = use_surface_nor && (snap_elem != SCE_SNAP_MODE_NONE);
if (orient_surface) {
copy_m3_m4(omat, obmat);
}
else {
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
const int orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
const int pivot_point = scene->toolsettings->transform_pivot_point;
ED_transform_calc_orientation_from_type_ex(
@@ -691,16 +710,40 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
orthogonalize_m3(omat, state->plane_axis);
if (orient_surface) {
- if (dot_v3v3(rv3d->viewinv[2], face_nor) < 0.0f) {
- negate_v3(face_nor);
+ if (!is_zero_v3(face_nor)) {
+ /* Negate the face normal according to the view. */
+ float ray_dir[3];
+ if (rv3d->is_persp) {
+ BLI_assert_msg(snap_elem != SCE_SNAP_MODE_NONE,
+ "Use of variable `co` without it being computed");
+
+ sub_v3_v3v3(ray_dir, co, rv3d->viewinv[3]); /* No need to normalize. */
+ }
+ else {
+ negate_v3_v3(ray_dir, rv3d->viewinv[2]);
+ }
+
+ if (dot_v3v3(ray_dir, face_nor) >= 0.0f) {
+ negate_v3(face_nor);
+ }
+ }
+ else if (!is_zero_v3(no)) {
+ copy_v3_v3(face_nor, no);
+ }
+ else {
+ face_nor[state->plane_axis] = 1.0f;
}
v3d_cursor_poject_surface_normal(face_nor, obmat, omat);
}
}
+ if (!use_surface_co) {
+ snap_elem = SCE_SNAP_MODE_NONE;
+ }
+
float *co_depth = (snap_elem != SCE_SNAP_MODE_NONE) ? co : scene->cursor.location;
snap_elem &= ~data_intern->snap_elem_hidden;
- if (snap_elem == 0) {
+ if (snap_elem == SCE_SNAP_MODE_NONE) {
RegionView3D *rv3d = region->regiondata;
const float *plane_normal = omat[state->plane_axis];
bool do_plane_isect = (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) &&
@@ -728,7 +771,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
(SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
snap_elem_index[1] = index;
}
- else if (snap_elem == SCE_SNAP_MODE_FACE) {
+ else if (snap_elem == SCE_SNAP_MODE_FACE_RAYCAST) {
snap_elem_index[2] = index;
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index b9e4c19295d..7ae1b86806a 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -567,7 +567,7 @@ static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region,
/* First, solid lines. */
{
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* passepartout, specified in camera edit buttons */
if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
@@ -618,7 +618,7 @@ static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region,
}
/* And now, the dashed lines! */
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
{
float viewport_size[4];
@@ -800,7 +800,7 @@ static void drawrenderborder(ARegion *region, View3D *v3d)
GPU_line_width(1.0f);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -982,7 +982,7 @@ static void draw_view_axis(RegionView3D *rv3d, const rcti *rect)
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
immBegin(GPU_PRIM_LINES, 6);
for (int axis_i = 0; axis_i < 3; axis_i++) {
@@ -1294,7 +1294,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
static void draw_selected_name(
Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
{
- const int cfra = CFRA;
+ const int cfra = scene->r.cfra;
const char *msg_pin = " (Pinned)";
const char *msg_sep = " : ";
@@ -1497,7 +1497,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
if (U.uiflag & USER_DRAWVIEWINFO) {
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
}
@@ -2247,16 +2247,16 @@ void view3d_depths_rect_create(ARegion *region, rcti *rect, ViewDepths *r_d)
static ViewDepths *view3d_depths_create(ARegion *region)
{
ViewDepths *d = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
- d->w = region->winx;
- d->h = region->winy;
{
GPUViewport *viewport = WM_draw_region_get_viewport(region);
GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
uint32_t *int_depths = GPU_texture_read(depth_tx, GPU_DATA_UINT_24_8, 0);
+ d->w = GPU_texture_width(depth_tx);
+ d->h = GPU_texture_height(depth_tx);
d->depths = (float *)int_depths;
/* Convert in-place. */
- int pixel_count = GPU_texture_width(depth_tx) * GPU_texture_height(depth_tx);
+ int pixel_count = d->w * d->h;
for (int i = 0; i < pixel_count; i++) {
d->depths[i] = (int_depths[i] >> 8u) / (float)0xFFFFFF;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 5fbdbef676c..6001f701c00 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -413,7 +413,9 @@ static void view3d_set_1_to_1_viewborder(Scene *scene,
{
RegionView3D *rv3d = region->regiondata;
float size[2];
- int im_width = (scene->r.size * scene->r.xsch) / 100;
+
+ int im_width, im_height;
+ BKE_render_resolution(&scene->r, false, &im_width, &im_height);
ED_view3d_calc_camera_border_size(scene, depsgraph, region, v3d, rv3d, size);
@@ -695,7 +697,7 @@ static int drop_world_exec(bContext *C, wmOperator *op)
id_us_plus(&world->id);
scene->world = world;
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, scene);
@@ -908,12 +910,13 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
CTX_data_ensure_evaluated_depsgraph(C),
region,
v3d,
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
.snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
+ NULL,
mval_fl,
NULL,
&dist_px,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 3f6167d92ca..89b46069df1 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -37,7 +37,7 @@
* \{ */
/*
- * TODO(campbell): Current conversion is a approximation (usable not correct),
+ * TODO(@campbellbarton): Current conversion is a approximation (usable not correct),
* we'll need to take the next/previous bones into account to get the tangent directions.
* First last matrices from 'BKE_pchan_bbone_spline_setup' are close but also not quite accurate
* since they're not at either end-points on the curve.
@@ -114,7 +114,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = BKE_object_pose_armature_get(base->object);
if (ob) {
@@ -133,7 +133,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType
static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
+ Object *ob = BKE_object_pose_armature_get(BKE_view_layer_active_object_get(view_layer));
bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
@@ -166,7 +166,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g
static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
+ Object *ob = BKE_object_pose_armature_get(BKE_view_layer_active_object_get(view_layer));
if (!gzgroup->customdata) {
return;
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
index 83f589a64c9..d4720d01d70 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
@@ -56,7 +56,7 @@ static bool WIDGETGROUP_camera_poll(const bContext *C, wmGizmoGroupType *UNUSED(
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = base->object;
if (ob->type == OB_CAMERA) {
@@ -73,7 +73,7 @@ static bool WIDGETGROUP_camera_poll(const bContext *C, wmGizmoGroupType *UNUSED(
static void WIDGETGROUP_camera_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
float dir[3];
const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
@@ -125,7 +125,7 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup)
struct CameraWidgetGroup *cagzgroup = gzgroup->customdata;
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Camera *ca = ob->data;
PointerRNA camera_ptr;
float dir[3];
@@ -242,7 +242,7 @@ static void WIDGETGROUP_camera_message_subscribe(const bContext *C,
{
ARegion *region = CTX_wm_region(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Camera *ca = ob->data;
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
@@ -370,7 +370,7 @@ static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmGizmoGroupType *UN
* We could change the rules for when to show. */
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (scene->camera != OBACT(view_layer)) {
+ if (scene->camera != BKE_view_layer_active_object_get(view_layer)) {
return false;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
index f113cc60224..a7febe11672 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
@@ -100,7 +100,7 @@ static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmGizmoGroupType *UN
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = base->object;
if (ob->type == OB_EMPTY) {
@@ -133,7 +133,7 @@ static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmGizmoGroup *gzg
struct EmptyImageWidgetGroup *igzgroup = gzgroup->customdata;
wmGizmo *gz = igzgroup->gizmo;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
copy_m4_m4(gz->matrix_basis, ob->obmat);
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
index 456e939eba7..f2f9e9092fa 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
@@ -43,7 +43,7 @@ static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmGizmoGroupType *UNU
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = base->object;
if (ob->pd && ob->pd->forcefield) {
@@ -74,7 +74,7 @@ static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmGizmoGroup *gzgr
wmGizmoWrapper *wwrapper = gzgroup->customdata;
wmGizmo *gz = wwrapper->gizmo;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
PartDeflect *pd = ob->pd;
if (pd->forcefield == PFIELD_WIND) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c
index b3bc0bc70cb..d0f58f43c2b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_light.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c
@@ -46,7 +46,7 @@ static bool WIDGETGROUP_light_spot_poll(const bContext *C, wmGizmoGroupType *UNU
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = base->object;
if (ob->type == OB_LAMP) {
@@ -77,7 +77,7 @@ static void WIDGETGROUP_light_spot_refresh(const bContext *C, wmGizmoGroup *gzgr
wmGizmoWrapper *wwrapper = gzgroup->customdata;
wmGizmo *gz = wwrapper->gizmo;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Light *la = ob->data;
float dir[3];
@@ -157,7 +157,7 @@ static bool WIDGETGROUP_light_area_poll(const bContext *C, wmGizmoGroupType *UNU
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = base->object;
if (ob->type == OB_LAMP) {
@@ -187,7 +187,7 @@ static void WIDGETGROUP_light_area_refresh(const bContext *C, wmGizmoGroup *gzgr
{
wmGizmoWrapper *wwrapper = gzgroup->customdata;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Light *la = ob->data;
wmGizmo *gz = wwrapper->gizmo;
@@ -240,7 +240,7 @@ static bool WIDGETGROUP_light_target_poll(const bContext *C, wmGizmoGroupType *U
}
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base && BASE_SELECTABLE(v3d, base)) {
Object *ob = base->object;
if (ob->type == OB_LAMP) {
@@ -281,7 +281,7 @@ static void WIDGETGROUP_light_target_draw_prepare(const bContext *C, wmGizmoGrou
{
wmGizmoWrapper *wwrapper = gzgroup->customdata;
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
wmGizmo *gz = wwrapper->gizmo;
normalize_m4_m4(gz->matrix_basis, ob->obmat);
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 9aae30c4a7e..41a0e137b03 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -17,6 +17,7 @@
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
#include "BKE_material.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -357,11 +358,12 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
depsgraph,
ruler_info->region,
v3d,
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
.snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
+ NULL,
mval_fl,
NULL,
&dist_px,
@@ -419,7 +421,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
RegionView3D *rv3d = ruler_info->region->regiondata;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
@@ -522,7 +524,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER;
}
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
@@ -576,7 +578,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
gpl = view3d_ruler_layer_get(scene->gpd);
if (gpl) {
bGPDframe *gpf;
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
if (gpf) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -782,7 +784,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* capping */
{
float rot_90_vec_a[2];
@@ -884,7 +886,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
}
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 6e8d9e96abd..90d108c23cc 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -20,6 +20,7 @@
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -125,7 +126,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
static void uiTemplatePaintModeSelection(uiLayout *layout, struct bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
/* Gizmos aren't used in paint modes */
if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
@@ -147,7 +148,7 @@ static void uiTemplatePaintModeSelection(uiLayout *layout, struct bContext *C)
void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *obedit = CTX_data_edit_object(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 53fc450107a..4c9e2595023 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -9,6 +9,10 @@
#include "ED_view3d.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* internal exports only */
struct ARegion;
@@ -83,7 +87,7 @@ void view3d_depths_rect_create(struct ARegion *region, struct rcti *rect, struct
*/
float view3d_depth_near(struct ViewDepths *d);
-/* view3d_select.c */
+/* view3d_select.cc */
void VIEW3D_OT_select(struct wmOperatorType *ot);
void VIEW3D_OT_select_circle(struct wmOperatorType *ot);
@@ -241,3 +245,7 @@ void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt);
extern uchar view3d_camera_border_hack_col[3];
extern bool view3d_camera_border_hack_test;
#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 4606908b91f..60141fd00cd 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -23,6 +23,7 @@
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
@@ -205,6 +206,8 @@ typedef struct foreachScreenObjectVert_userData {
void (*func)(void *userData, MVert *mv, const float screen_co[2], int index);
void *userData;
ViewContext vc;
+ MVert *verts;
+ const bool *hide_vert;
eV3DProjTest clip_flag;
} foreachScreenObjectVert_userData;
@@ -262,18 +265,19 @@ static void meshobject_foreachScreenVert__mapFunc(void *userData,
const float UNUSED(no[3]))
{
foreachScreenObjectVert_userData *data = userData;
- struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
-
- if (!(mv->flag & ME_HIDE)) {
- float screen_co[2];
+ if (data->hide_vert && data->hide_vert[index]) {
+ return;
+ }
+ MVert *mv = &data->verts[index];
- if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
- V3D_PROJ_RET_OK) {
- return;
- }
+ float screen_co[2];
- data->func(data->userData, mv, screen_co, index);
+ if (ED_view3d_project_float_object(data->vc.region, co, screen_co, data->clip_flag) !=
+ V3D_PROJ_RET_OK) {
+ return;
}
+
+ data->func(data->userData, mv, screen_co, index);
}
void meshobject_foreachScreenVert(
@@ -297,6 +301,9 @@ void meshobject_foreachScreenVert(
data.func = func;
data.userData = userData;
data.clip_flag = clip_flag;
+ data.verts = BKE_mesh_verts_for_write((Mesh *)vc->obact->data);
+ data.hide_vert = (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".hide_vert");
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
@@ -335,7 +342,7 @@ void mesh_foreachScreenVert(
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -398,7 +405,7 @@ void mesh_foreachScreenEdge(ViewContext *vc,
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -486,7 +493,7 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -558,7 +565,7 @@ void mesh_foreachScreenFace(
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
data.vc = *vc;
diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c
index 50d7626a57d..684b3539943 100644
--- a/source/blender/editors/space_view3d/view3d_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_navigate.c
@@ -166,7 +166,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
View3D *v3d = CTX_wm_view3d(C);
- Object *ob_act_eval = OBACT(view_layer_eval);
+ Object *ob_act_eval = BKE_view_layer_active_object_get(view_layer_eval);
Object *ob_act = DEG_get_original_object(ob_act_eval);
if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
@@ -203,12 +203,11 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
}
else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) {
/* object mode use boundbox centers */
- Base *base_eval;
uint tot = 0;
float select_center[3];
zero_v3(select_center);
- for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) {
+ LISTBASE_FOREACH (Base *, base_eval, &view_layer_eval->object_bases) {
if (BASE_SELECTED(v3d, base_eval)) {
/* use the boundbox if we can */
Object *ob_eval = base_eval->object;
@@ -495,6 +494,8 @@ static void axis_set_view(bContext *C,
.camera_old = v3d->camera,
.ofs = rv3d->ofs,
.quat = quat,
+ /* No undo because this switches to/from camera. */
+ .undo_str = NULL,
});
}
else if (orig_persp == RV3D_CAMOB && v3d->camera) {
@@ -518,6 +519,8 @@ static void axis_set_view(bContext *C,
.ofs = ofs,
.quat = quat,
.dist = &dist,
+ /* No undo because this switches to/from camera. */
+ .undo_str = NULL,
});
}
else {
@@ -540,6 +543,8 @@ static void axis_set_view(bContext *C,
&(const V3D_SmoothParams){
.quat = quat,
.dyn_ofs = dyn_ofs_pt,
+ /* No undo because this isn't a camera view. */
+ .undo_str = NULL,
});
}
}
@@ -694,6 +699,8 @@ static void view3d_from_minmax(bContext *C,
.camera_old = v3d->camera,
.ofs = new_ofs,
.dist = ok_dist ? &new_dist : NULL,
+ /* The caller needs to use undo begin/end calls. */
+ .undo_str = NULL,
});
}
else {
@@ -704,6 +711,8 @@ static void view3d_from_minmax(bContext *C,
&(const V3D_SmoothParams){
.ofs = new_ofs,
.dist = ok_dist ? &new_dist : NULL,
+ /* The caller needs to use undo begin/end calls. */
+ .undo_str = NULL,
});
}
@@ -736,6 +745,7 @@ static void view3d_from_minmax_multi(bContext *C,
static int view3d_all_exec(bContext *C, wmOperator *op)
{
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -802,6 +812,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
/* This is an approximation, see function documentation for details. */
ED_view3d_clipping_clamp_minmax(rv3d, min, max);
}
+ ED_view3d_smooth_view_undo_begin(C, area);
if (use_all_regions) {
view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx);
@@ -810,6 +821,8 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx);
}
+ ED_view3d_smooth_view_undo_end(C, area, op->type->name, false);
+
return OPERATOR_FINISHED;
}
@@ -842,13 +855,14 @@ void VIEW3D_OT_view_all(wmOperatorType *ot)
static int viewselected_exec(bContext *C, wmOperator *op)
{
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
- Object *ob_eval = OBACT(view_layer_eval);
+ Object *ob_eval = BKE_view_layer_active_object_get(view_layer_eval);
Object *obedit = CTX_data_edit_object(C);
const bGPdata *gpd_eval = ob_eval && (ob_eval->type == OB_GPENCIL) ? ob_eval->data : NULL;
const bool is_gp_edit = gpd_eval ? GPENCIL_ANY_MODE(gpd_eval) : false;
@@ -948,8 +962,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok_dist = 0; /* don't zoom */
}
else {
- Base *base_eval;
- for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) {
+ LISTBASE_FOREACH (Base *, base_eval, &view_layer_eval->object_bases) {
if (BASE_SELECTED(v3d, base_eval)) {
bool only_center = false;
Object *ob = DEG_get_original_object(base_eval->object);
@@ -971,6 +984,8 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ED_view3d_clipping_clamp_minmax(rv3d, min, max);
}
+ ED_view3d_smooth_view_undo_begin(C, area);
+
if (use_all_regions) {
view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx);
}
@@ -978,6 +993,8 @@ static int viewselected_exec(bContext *C, wmOperator *op)
view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
}
+ ED_view3d_smooth_view_undo_end(C, area, op->type->name, false);
+
return OPERATOR_FINISHED;
}
@@ -1020,8 +1037,14 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
/* non camera center */
float new_ofs[3];
negate_v3_v3(new_ofs, scene->cursor.location);
- ED_view3d_smooth_view(
- C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs});
+ ED_view3d_smooth_view(C,
+ v3d,
+ region,
+ smooth_viewtx,
+ &(const V3D_SmoothParams){
+ .ofs = new_ofs,
+ .undo_str = op->type->name,
+ });
/* Smooth view does view-lock #RV3D_BOXVIEW copy. */
}
@@ -1074,8 +1097,14 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_view3d_win_to_3d_int(v3d, region, new_ofs, event->mval, new_ofs);
}
negate_v3(new_ofs);
- ED_view3d_smooth_view(
- C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs});
+ ED_view3d_smooth_view(C,
+ v3d,
+ region,
+ smooth_viewtx,
+ &(const V3D_SmoothParams){
+ .ofs = new_ofs,
+ .undo_str = op->type->name,
+ });
}
return OPERATOR_FINISHED;
@@ -1275,7 +1304,7 @@ static int view_camera_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
if (rv3d->persp != RV3D_CAMOB) {
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (!rv3d->smooth_timer) {
/* store settings of current view before allowing overwriting with camera view
@@ -1318,17 +1347,20 @@ static int view_camera_exec(bContext *C, wmOperator *op)
/* finally do snazzy view zooming */
rv3d->persp = RV3D_CAMOB;
- ED_view3d_smooth_view(C,
- v3d,
- region,
- smooth_viewtx,
- &(const V3D_SmoothParams){
- .camera = v3d->camera,
- .ofs = rv3d->ofs,
- .quat = rv3d->viewquat,
- .dist = &rv3d->dist,
- .lens = &v3d->lens,
- });
+ ED_view3d_smooth_view(
+ C,
+ v3d,
+ region,
+ smooth_viewtx,
+ &(const V3D_SmoothParams){
+ .camera = v3d->camera,
+ .ofs = rv3d->ofs,
+ .quat = rv3d->viewquat,
+ .dist = &rv3d->dist,
+ .lens = &v3d->lens,
+ /* No undo because this changes cameras (and wont move the camera). */
+ .undo_str = NULL,
+ });
}
else {
/* return to settings of last view */
@@ -1417,7 +1449,12 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
ED_view3d_smooth_view_force_finish(C, v3d, region);
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0 || (view_opposite != RV3D_VIEW_USER)) {
- if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
+ const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d);
+ if ((rv3d->persp != RV3D_CAMOB) || is_camera_lock) {
+ if (is_camera_lock) {
+ const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_camera_lock_init(depsgraph, v3d, rv3d);
+ }
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
float quat_mul[4];
float quat_new[4];
@@ -1475,6 +1512,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams){
.quat = quat_new,
.dyn_ofs = dyn_ofs_pt,
+ /* Group as successive orbit may run by holding a key. */
+ .undo_str = op->type->name,
+ .undo_grouped = true,
});
return OPERATOR_FINISHED;
@@ -1554,6 +1594,7 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y);
+ ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
viewops_data_free(C, vod);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_navigate.h b/source/blender/editors/space_view3d/view3d_navigate.h
index fc7bc11295a..925acd90573 100644
--- a/source/blender/editors/space_view3d/view3d_navigate.h
+++ b/source/blender/editors/space_view3d/view3d_navigate.h
@@ -231,6 +231,14 @@ typedef struct V3D_SmoothParams {
/** Alternate rotation center, when set `ofs` must be NULL. */
const float *dyn_ofs;
+
+ /** When non-NULL, perform undo pushes when transforming the camera. */
+ const char *undo_str;
+ /**
+ * When true use grouped undo pushes, use for incremental viewport manipulation
+ * which are likely to be activated by holding a key or from the mouse-wheel.
+ */
+ bool undo_grouped;
} V3D_SmoothParams;
/**
@@ -252,6 +260,22 @@ void ED_view3d_smooth_view(struct bContext *C,
const V3D_SmoothParams *sview);
/**
+ * Call before multiple smooth-view operations begin to properly handle undo.
+ *
+ * \note Only use explicit undo calls when multiple calls to smooth-view are necessary
+ * or when calling #ED_view3d_smooth_view_ex.
+ * Otherwise pass in #V3D_SmoothParams.undo_str so an undo step is pushed as needed.
+ */
+void ED_view3d_smooth_view_undo_begin(struct bContext *C, const struct ScrArea *area);
+/**
+ * Run after multiple smooth-view operations have run to push undo as needed.
+ */
+void ED_view3d_smooth_view_undo_end(struct bContext *C,
+ const struct ScrArea *area,
+ const char *undo_str,
+ bool undo_grouped);
+
+/**
* Apply the smooth-view immediately, use when we need to start a new view operation.
* (so we don't end up half-applying a view operation when pressing keys quickly).
*/
diff --git a/source/blender/editors/space_view3d/view3d_navigate_dolly.c b/source/blender/editors/space_view3d/view3d_navigate_dolly.c
index d45b0c436ac..376e8ba190b 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_dolly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_dolly.c
@@ -181,6 +181,7 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret & OPERATOR_FINISHED) {
+ ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
viewops_data_free(C, vod);
op->customdata = NULL;
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index 399f422f411..b607abe8226 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -247,7 +247,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(regio
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor3(TH_VIEW_OVERLAY);
@@ -1079,6 +1079,7 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
int exit_code;
bool do_draw = false;
FlyInfo *fly = op->customdata;
+ View3D *v3d = fly->v3d;
RegionView3D *rv3d = fly->rv3d;
Object *fly_object = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control);
@@ -1102,6 +1103,9 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
exit_code = flyEnd(C, fly);
+ if (exit_code == OPERATOR_FINISHED) {
+ ED_view3d_camera_lock_undo_push(op->type->name, v3d, rv3d, C);
+ }
if (exit_code != OPERATOR_RUNNING_MODAL) {
do_draw = true;
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_move.c b/source/blender/editors/space_view3d/view3d_navigate_move.c
index e653b349a2f..e236b702fb8 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_move.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_move.c
@@ -140,6 +140,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret & OPERATOR_FINISHED) {
+ ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_ndof.c b/source/blender/editors/space_view3d/view3d_navigate_ndof.c
index 1ce9bdcb211..88abf602c26 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_ndof.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_ndof.c
@@ -373,6 +373,9 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event)
const bool has_translate = !is_zero_v2(ndof->tvec);
const bool has_zoom = ndof->tvec[2] != 0.0f;
+ float pan_vec[3];
+ WM_event_ndof_pan_get(ndof, pan_vec, true);
+
/* NOTE(@campbellbarton): In principle rotating could pass through to regular
* non-camera NDOF behavior (exiting the camera-view and rotating).
* Disabled this block since in practice it's difficult to control NDOF devices
@@ -388,14 +391,14 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event)
if (has_translate) {
const float speed = ndof->dt * NDOF_PIXELS_PER_SECOND;
- float event_ofs[2] = {ndof->tvec[0] * speed, ndof->tvec[1] * speed};
+ float event_ofs[2] = {pan_vec[0] * speed, pan_vec[1] * speed};
if (ED_view3d_camera_view_pan(region, event_ofs)) {
changed = true;
}
}
if (has_zoom) {
- const float scale = 1.0f + (ndof->dt * ndof->tvec[2]);
+ const float scale = 1.0f + (ndof->dt * pan_vec[2]);
if (ED_view3d_camera_view_zoom_scale(rv3d, scale)) {
changed = true;
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_roll.c b/source/blender/editors/space_view3d/view3d_navigate_roll.c
index 087ca72211e..af93aa50238 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_roll.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_roll.c
@@ -15,6 +15,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_screen.h"
#include "view3d_intern.h"
@@ -167,7 +169,13 @@ static int viewroll_exec(bContext *C, wmOperator *op)
}
rv3d = region->regiondata;
- if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
+
+ const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d);
+ if ((rv3d->persp != RV3D_CAMOB) || is_camera_lock) {
+ if (is_camera_lock) {
+ const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_camera_lock_init(depsgraph, v3d, rv3d);
+ }
ED_view3d_smooth_view_force_finish(C, v3d, region);
@@ -202,6 +210,9 @@ static int viewroll_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams){
.quat = quat_new,
.dyn_ofs = dyn_ofs_pt,
+ /* Group as successive roll may run by holding a key. */
+ .undo_str = op->type->name,
+ .undo_grouped = true,
});
viewops_data_free(C, op->customdata);
diff --git a/source/blender/editors/space_view3d/view3d_navigate_rotate.c b/source/blender/editors/space_view3d/view3d_navigate_rotate.c
index 989fa152acc..20385e15c48 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_rotate.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_rotate.c
@@ -375,6 +375,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret & OPERATOR_FINISHED) {
+ ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
}
diff --git a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c
index 48af126d8a9..6b150d1e771 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c
@@ -8,6 +8,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -21,6 +22,115 @@
#include "view3d_intern.h"
#include "view3d_navigate.h" /* own include */
+static void view3d_smoothview_apply_with_interp(
+ bContext *C, View3D *v3d, RegionView3D *rv3d, const bool use_autokey, const float factor);
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth View Undo Handling
+ *
+ * When the camera is locked to the viewport smooth-view operations
+ * may need to perform an undo push.
+ *
+ * In this case the smooth-view camera transformation is temporarily completed,
+ * undo is pushed then the change is rewound, and smooth-view completes from it's timer.
+ * In the case smooth-view executed the change immediately - an undo push is called.
+ *
+ * NOTE(@campbellbarton): While this is not ideal it's necessary as making the undo-push
+ * once smooth-view is complete because smooth-view is non-blocking and it's possible other
+ * operations are executed once smooth-view has started.
+ * \{ */
+
+void ED_view3d_smooth_view_undo_begin(bContext *C, const ScrArea *area)
+{
+ const View3D *v3d = area->spacedata.first;
+ Object *camera = v3d->camera;
+ if (!camera) {
+ return;
+ }
+
+ /* Tag the camera object so it's known smooth-view is applied to the view-ports camera
+ * (needed to detect when a locked camera is being manipulated).
+ * NOTE: It doesn't matter if the actual object being manipulated is the camera or not. */
+ camera->id.tag &= ~LIB_TAG_DOIT;
+
+ LISTBASE_FOREACH (const ARegion *, region, &area->regionbase) {
+ if (region->regiontype != RGN_TYPE_WINDOW) {
+ continue;
+ }
+ const RegionView3D *rv3d = region->regiondata;
+ if (ED_view3d_camera_lock_undo_test(v3d, rv3d, C)) {
+ camera->id.tag |= LIB_TAG_DOIT;
+ break;
+ }
+ }
+}
+
+void ED_view3d_smooth_view_undo_end(bContext *C,
+ const ScrArea *area,
+ const char *undo_str,
+ const bool undo_grouped)
+{
+ View3D *v3d = area->spacedata.first;
+ Object *camera = v3d->camera;
+ if (!camera) {
+ return;
+ }
+ if (camera->id.tag & LIB_TAG_DOIT) {
+ /* Smooth view didn't touch the camera. */
+ camera->id.tag &= ~LIB_TAG_DOIT;
+ return;
+ }
+
+ if ((U.uiflag & USER_GLOBALUNDO) == 0) {
+ return;
+ }
+
+ /* NOTE(@campbellbarton): It is not possible that a single viewport references different cameras
+ * so even in the case there is a quad-view with multiple camera views set, these will all
+ * reference the same camera. In this case it doesn't matter which region is used.
+ * If in the future multiple cameras are supported, this logic can be extended. */
+ const ARegion *region_camera = NULL;
+
+ /* An undo push should be performed. */
+ bool is_interactive = false;
+ LISTBASE_FOREACH (const ARegion *, region, &area->regionbase) {
+ if (region->regiontype != RGN_TYPE_WINDOW) {
+ continue;
+ }
+ const RegionView3D *rv3d = region->regiondata;
+ if (ED_view3d_camera_lock_undo_test(v3d, rv3d, C)) {
+ region_camera = region;
+ if (rv3d->sms) {
+ is_interactive = true;
+ }
+ }
+ }
+
+ if (region_camera == NULL) {
+ return;
+ }
+
+ RegionView3D *rv3d = region_camera->regiondata;
+
+ /* Fast forward, undo push, then rewind. */
+ if (is_interactive) {
+ view3d_smoothview_apply_with_interp(C, v3d, rv3d, false, 1.0f);
+ }
+
+ if (undo_grouped) {
+ ED_view3d_camera_lock_undo_grouped_push(undo_str, v3d, rv3d, C);
+ }
+ else {
+ ED_view3d_camera_lock_undo_push(undo_str, v3d, rv3d, C);
+ }
+
+ if (is_interactive) {
+ view3d_smoothview_apply_with_interp(C, v3d, rv3d, false, 0.0f);
+ }
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Smooth View Operator & Utilities
*
@@ -86,6 +196,11 @@ void ED_view3d_smooth_view_ex(
const int smooth_viewtx,
const V3D_SmoothParams *sview)
{
+ /* In this case use #ED_view3d_smooth_view_undo_begin & end functions
+ * instead of passing in undo. */
+ BLI_assert_msg(sview->undo_str == NULL,
+ "Only the 'ED_view3d_smooth_view' version of this function handles undo!");
+
RegionView3D *rv3d = region->regiondata;
struct SmoothView3DStore sms = {{0}};
@@ -236,6 +351,13 @@ void ED_view3d_smooth_view_ex(
WM_event_add_mousemove(win);
}
+
+ if (sms.to_camera == false) {
+ /* See comments in #ED_view3d_smooth_view_undo_begin for why this is needed. */
+ if (v3d->camera) {
+ v3d->camera->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
}
void ED_view3d_smooth_view(bContext *C,
@@ -249,97 +371,129 @@ void ED_view3d_smooth_view(bContext *C,
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
- ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview);
+ /* #ED_view3d_smooth_view_ex asserts this is not set as it doesn't support undo. */
+ struct V3D_SmoothParams sview_no_undo = *sview;
+ sview_no_undo.undo_str = NULL;
+ sview_no_undo.undo_grouped = false;
+
+ const bool do_undo = (sview->undo_str != NULL);
+ if (do_undo) {
+ ED_view3d_smooth_view_undo_begin(C, area);
+ }
+
+ ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, &sview_no_undo);
+
+ if (do_undo) {
+ ED_view3d_smooth_view_undo_end(C, area, sview->undo_str, sview->undo_grouped);
+ }
}
-/* only meant for timer usage */
-static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview)
+/**
+ * Apply with interpolation, on completion run #view3d_smoothview_apply_and_finish.
+ */
+static void view3d_smoothview_apply_with_interp(
+ bContext *C, View3D *v3d, RegionView3D *rv3d, const bool use_autokey, const float factor)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- RegionView3D *rv3d = region->regiondata;
struct SmoothView3DStore *sms = rv3d->sms;
- float step, step_inv;
- if (sms->time_allowed != 0.0) {
- step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed);
+ interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, factor);
+
+ if (sms->use_dyn_ofs) {
+ view3d_orbit_apply_dyn_ofs(
+ rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs);
}
else {
- step = 1.0f;
+ interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, factor);
}
- /* end timer */
- if (step >= 1.0f) {
- wmWindow *win = CTX_wm_window(C);
+ rv3d->dist = interpf(sms->dst.dist, sms->src.dist, factor);
+ v3d->lens = interpf(sms->dst.lens, sms->src.lens, factor);
- /* if we went to camera, store the original */
- if (sms->to_camera) {
- rv3d->persp = RV3D_CAMOB;
- view3d_smooth_view_state_restore(&sms->org, v3d, rv3d);
- }
- else {
- const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
-
- view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d);
-
- ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
+ const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ if (ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d)) {
+ if (use_autokey) {
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
+ }
+}
- if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
- rv3d->view = sms->org_view;
- }
-
- MEM_freeN(rv3d->sms);
- rv3d->sms = NULL;
+/**
+ * Apply the view-port transformation & free smooth-view related data.
+ */
+static void view3d_smoothview_apply_and_finish(bContext *C, View3D *v3d, RegionView3D *rv3d)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ struct SmoothView3DStore *sms = rv3d->sms;
- WM_event_remove_timer(wm, win, rv3d->smooth_timer);
- rv3d->smooth_timer = NULL;
- rv3d->rflag &= ~RV3D_NAVIGATING;
+ wmWindow *win = CTX_wm_window(C);
- /* Event handling won't know if a UI item has been moved under the pointer. */
- WM_event_add_mousemove(win);
+ /* if we went to camera, store the original */
+ if (sms->to_camera) {
+ rv3d->persp = RV3D_CAMOB;
+ view3d_smooth_view_state_restore(&sms->org, v3d, rv3d);
}
else {
- /* ease in/out */
- step = (3.0f * step * step - 2.0f * step * step * step);
-
- step_inv = 1.0f - step;
-
- interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step);
-
- if (sms->use_dyn_ofs) {
- view3d_orbit_apply_dyn_ofs(
- rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs);
- }
- else {
- interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step);
- }
+ const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv;
- v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv;
+ view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d);
- const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
- if (ED_screen_animation_playing(wm)) {
+ if (ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d)) {
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
}
- if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) {
- view3d_boxview_copy(CTX_wm_area(C), region);
+ if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
+ rv3d->view = sms->org_view;
}
+ MEM_freeN(rv3d->sms);
+ rv3d->sms = NULL;
+
+ WM_event_remove_timer(wm, win, rv3d->smooth_timer);
+ rv3d->smooth_timer = NULL;
+ rv3d->rflag &= ~RV3D_NAVIGATING;
+
+ /* Event handling won't know if a UI item has been moved under the pointer. */
+ WM_event_add_mousemove(win);
+
/* NOTE: this doesn't work right because the v3d->lens is now used in ortho mode r51636,
* when switching camera in quad-view the other ortho views would zoom & reset.
*
* For now only redraw all regions when smooth-view finishes.
*/
- if (step >= 1.0f) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+}
+
+/* only meant for timer usage */
+
+static void view3d_smoothview_apply_from_timer(bContext *C, View3D *v3d, ARegion *region)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ RegionView3D *rv3d = region->regiondata;
+ struct SmoothView3DStore *sms = rv3d->sms;
+ float factor;
+
+ if (sms->time_allowed != 0.0) {
+ factor = (float)((rv3d->smooth_timer->duration) / sms->time_allowed);
}
else {
- ED_region_tag_redraw(region);
+ factor = 1.0f;
+ }
+ if (factor >= 1.0f) {
+ view3d_smoothview_apply_and_finish(C, v3d, rv3d);
}
+ else {
+ /* Ease in/out smoothing. */
+ factor = (3.0f * factor * factor - 2.0f * factor * factor * factor);
+ const bool use_autokey = ED_screen_animation_playing(wm);
+ view3d_smoothview_apply_with_interp(C, v3d, rv3d, use_autokey, factor);
+ }
+
+ if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
+ view3d_boxview_copy(CTX_wm_area(C), region);
+ }
+
+ ED_region_tag_redraw(region);
}
static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -353,7 +507,7 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
return OPERATOR_PASS_THROUGH;
}
- view3d_smoothview_apply(C, v3d, region, true);
+ view3d_smoothview_apply_from_timer(C, v3d, region);
return OPERATOR_FINISHED;
}
@@ -361,12 +515,10 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
-
if (rv3d && rv3d->sms) {
- rv3d->sms->time_allowed = 0.0; /* force finishing */
- view3d_smoothview_apply(C, v3d, region, false);
+ view3d_smoothview_apply_and_finish(C, v3d, rv3d);
- /* force update of view matrix so tools that run immediately after
+ /* Force update of view matrix so tools that run immediately after
* can use them without redrawing first */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index c4eff01375b..7e537d0c141 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -55,9 +55,6 @@
#define USE_TABLET_SUPPORT
-/* ensure the target position is one we can reach, see: T45771 */
-#define USE_PIXELSIZE_NATIVE_SUPPORT
-
/* -------------------------------------------------------------------- */
/** \name Modal Key-map
* \{ */
@@ -226,8 +223,8 @@ typedef struct WalkInfo {
/** Previous 2D mouse values. */
int prev_mval[2];
- /** Center mouse values. */
- int center_mval[2];
+ /** Initial mouse location. */
+ int init_mval[2];
int moffset[2];
@@ -271,9 +268,6 @@ typedef struct WalkInfo {
bool is_reversed;
#ifdef USE_TABLET_SUPPORT
- /** Check if we had a cursor event before. */
- bool is_cursor_first;
-
/** Tablet devices (we can't relocate the cursor). */
bool is_cursor_absolute;
#endif
@@ -341,7 +335,7 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *region, voi
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorAlpha(TH_VIEW_OVERLAY, 1.0f);
@@ -484,7 +478,7 @@ enum {
static float base_speed = -1.0f;
static float userdef_speed = -1.0f;
-static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
+static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int mval[2])
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -565,8 +559,6 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
#ifdef USE_TABLET_SUPPORT
- walk->is_cursor_first = true;
-
walk->is_cursor_absolute = false;
#endif
@@ -599,28 +591,10 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->depsgraph, walk->scene, walk->v3d, walk->rv3d);
- /* center the mouse */
- walk->center_mval[0] = walk->region->winx * 0.5f;
- walk->center_mval[1] = walk->region->winy * 0.5f;
-
-#ifdef USE_PIXELSIZE_NATIVE_SUPPORT
- walk->center_mval[0] += walk->region->winrct.xmin;
- walk->center_mval[1] += walk->region->winrct.ymin;
-
- WM_cursor_compatible_xy(win, &walk->center_mval[0], &walk->center_mval[1]);
-
- walk->center_mval[0] -= walk->region->winrct.xmin;
- walk->center_mval[1] -= walk->region->winrct.ymin;
-#endif
-
- copy_v2_v2_int(walk->prev_mval, walk->center_mval);
-
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
+ copy_v2_v2_int(walk->init_mval, mval);
+ copy_v2_v2_int(walk->prev_mval, mval);
- /* remove the mouse cursor temporarily */
- WM_cursor_modal_set(win, WM_CURSOR_NONE);
+ WM_cursor_grab_enable(win, 0, true, NULL);
return 1;
}
@@ -669,18 +643,7 @@ static int walkEnd(bContext *C, WalkInfo *walk)
}
#endif
- /* restore the cursor */
- WM_cursor_modal_restore(win);
-
-#ifdef USE_TABLET_SUPPORT
- if (walk->is_cursor_absolute == false)
-#endif
- {
- /* center the mouse */
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
- }
+ WM_cursor_grab_enable(win, 0, true, NULL);
if (walk->state == WALK_CONFIRM) {
MEM_freeN(walk);
@@ -691,34 +654,16 @@ static int walkEnd(bContext *C, WalkInfo *walk)
return OPERATOR_CANCELLED;
}
-static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
+static void walkEvent(WalkInfo *walk, const wmEvent *event)
{
if (event->type == TIMER && event->customdata == walk->timer) {
walk->redraw = true;
}
- else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ else if (ISMOUSE_MOTION(event->type)) {
#ifdef USE_TABLET_SUPPORT
- if (walk->is_cursor_first) {
- /* wait until we get the 'warp' event */
- if ((walk->center_mval[0] == event->mval[0]) && (walk->center_mval[1] == event->mval[1])) {
- walk->is_cursor_first = false;
- }
- else {
- /* NOTE: its possible the system isn't giving us the warp event
- * ideally we shouldn't have to worry about this, see: T45361 */
- wmWindow *win = CTX_wm_window(C);
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
- }
- return;
- }
-
if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) {
walk->is_cursor_absolute = true;
- copy_v2_v2_int(walk->prev_mval, event->mval);
- copy_v2_v2_int(walk->center_mval, event->mval);
}
#endif /* USE_TABLET_SUPPORT */
@@ -727,29 +672,8 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
copy_v2_v2_int(walk->prev_mval, event->mval);
- if ((walk->center_mval[0] != event->mval[0]) || (walk->center_mval[1] != event->mval[1])) {
+ if (walk->moffset[0] || walk->moffset[1]) {
walk->redraw = true;
-
-#ifdef USE_TABLET_SUPPORT
- if (walk->is_cursor_absolute) {
- /* pass */
- }
- else
-#endif
- if (WM_event_is_last_mousemove(event)) {
- wmWindow *win = CTX_wm_window(C);
-
-#ifdef __APPLE__
- if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) ||
- (abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2))
-#endif
- {
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
- copy_v2_v2_int(walk->prev_mval, walk->center_mval);
- }
- }
}
}
#ifdef WITH_INPUT_NDOF
@@ -1436,12 +1360,12 @@ static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->customdata = walk;
- if (initWalkInfo(C, walk, op) == false) {
+ if (initWalkInfo(C, walk, op, event->mval) == false) {
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
- walkEvent(C, walk, event);
+ walkEvent(walk, event);
WM_event_add_modal_handler(C, op);
@@ -1462,12 +1386,13 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
int exit_code;
bool do_draw = false;
WalkInfo *walk = op->customdata;
+ View3D *v3d = walk->v3d;
RegionView3D *rv3d = walk->rv3d;
Object *walk_object = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
walk->redraw = false;
- walkEvent(C, walk, event);
+ walkEvent(walk, event);
#ifdef WITH_INPUT_NDOF
if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer] */
@@ -1488,6 +1413,9 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (exit_code != OPERATOR_RUNNING_MODAL) {
do_draw = true;
}
+ if (exit_code == OPERATOR_FINISHED) {
+ ED_view3d_camera_lock_undo_push(op->type->name, v3d, rv3d, C);
+ }
if (do_draw) {
if (rv3d->persp == RV3D_CAMOB) {
@@ -1515,7 +1443,9 @@ void VIEW3D_OT_walk(wmOperatorType *ot)
ot->poll = ED_operator_region_view3d_active;
/* flags */
- ot->flag = OPTYPE_BLOCKING;
+ /* NOTE: #OPTYPE_BLOCKING isn't used because this needs to grab & hide the cursor.
+ * where as blocking confines the cursor to the window bounds, even when hidden. */
+ ot->flag = 0;
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom.c b/source/blender/editors/space_view3d/view3d_navigate_zoom.c
index a67c0850ad9..9230aa09b1a 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_zoom.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_zoom.c
@@ -425,6 +425,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret & OPERATOR_FINISHED) {
+ ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
}
@@ -507,6 +508,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_region_tag_redraw(region);
+ ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c b/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c
index f834efe4a7b..7cafc3dfd42 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c
@@ -159,11 +159,15 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* clamp after because we may have been zooming out */
CLAMP(new_dist, dist_range[0], dist_range[1]);
- /* TODO(campbell): 'is_camera_lock' not currently working well. */
const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d);
- if ((rv3d->persp == RV3D_CAMOB) && (is_camera_lock == false)) {
+ if (rv3d->persp == RV3D_CAMOB) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP);
+ if (is_camera_lock) {
+ ED_view3d_camera_lock_init(depsgraph, v3d, rv3d);
+ }
+ else {
+ ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP);
+ }
}
ED_view3d_smooth_view(C,
@@ -173,6 +177,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
&(const V3D_SmoothParams){
.ofs = new_ofs,
.dist = &new_dist,
+ .undo_str = op->type->name,
});
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.cc
index 01f94bcab55..f00bee54ed6 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.cc
@@ -5,10 +5,10 @@
* \ingroup spview3d
*/
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
+#include <cfloat>
+#include <cmath>
+#include <cstdio>
+#include <cstring>
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
@@ -23,7 +23,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_lasso_2d.h"
#include "BLI_linklist.h"
@@ -32,6 +31,7 @@
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#ifdef __BIG_ENDIAN__
# include "BLI_endian_switch.h"
@@ -204,14 +204,14 @@ static void editselect_buf_cache_init(ViewContext *vc, short select_mode)
}
}
-static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel)
+static void editselect_buf_cache_free(EditSelectBuf_Cache *esel)
{
MEM_SAFE_FREE(esel->select_bitmap);
}
static void editselect_buf_cache_free_voidp(void *esel_voidp)
{
- editselect_buf_cache_free(esel_voidp);
+ editselect_buf_cache_free(static_cast<EditSelectBuf_Cache *>(esel_voidp));
MEM_freeN(esel_voidp);
}
@@ -219,7 +219,7 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w
ViewContext *vc,
short select_mode)
{
- struct EditSelectBuf_Cache *esel = MEM_callocN(sizeof(*esel), __func__);
+ EditSelectBuf_Cache *esel = MEM_cnew<EditSelectBuf_Cache>(__func__);
wm_userdata->data = esel;
wm_userdata->free_fn = editselect_buf_cache_free_voidp;
wm_userdata->use_free = true;
@@ -232,7 +232,7 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w
/** \name Internal Edit-Mesh Utilities
* \{ */
-static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel,
+static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
@@ -264,7 +264,7 @@ static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel
return changed;
}
-static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel,
+static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
@@ -296,7 +296,7 @@ static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel
return changed;
}
-static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel,
+static bool edbm_backbuf_check_and_select_faces(EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
@@ -330,18 +330,21 @@ static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel
/* object mode, edbm_ prefix is confusing here, rename? */
static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me,
- struct EditSelectBuf_Cache *esel,
+ EditSelectBuf_Cache *esel,
const eSelectOp sel_op)
{
- MVert *mv = me->mvert;
- uint index;
+ MVert *verts = BKE_mesh_verts_for_write(me);
+ MVert *mv = verts;
bool changed = false;
const BLI_bitmap *select_bitmap = esel->select_bitmap;
if (mv) {
- for (index = 0; index < me->totvert; index++, mv++) {
- if (!(mv->flag & ME_HIDE)) {
+ const bool *hide_vert = (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".hide_vert");
+
+ for (int index = 0; index < me->totvert; index++, mv++) {
+ if (!(hide_vert && hide_vert[index])) {
const bool is_select = mv->flag & SELECT;
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
@@ -357,23 +360,25 @@ static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me,
/* object mode, edbm_ prefix is confusing here, rename? */
static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me,
- struct EditSelectBuf_Cache *esel,
+ EditSelectBuf_Cache *esel,
const eSelectOp sel_op)
{
- MPoly *mpoly = me->mpoly;
- uint index;
+ MPoly *polys = BKE_mesh_polys_for_write(me);
bool changed = false;
const BLI_bitmap *select_bitmap = esel->select_bitmap;
- if (mpoly) {
- for (index = 0; index < me->totpoly; index++, mpoly++) {
- if (!(mpoly->flag & ME_HIDE)) {
- const bool is_select = mpoly->flag & ME_FACE_SEL;
+ if (polys) {
+ const bool *hide_poly = (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".hide_poly");
+
+ for (int index = 0; index < me->totpoly; index++) {
+ if (!(hide_poly && hide_poly[index])) {
+ const bool is_select = polys[index].flag & ME_FACE_SEL;
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL);
+ SET_FLAG_FROM_TEST(polys[index].flag, sel_op_result, ME_FACE_SEL);
changed = true;
}
}
@@ -388,7 +393,7 @@ static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me,
/** \name Lasso Select
* \{ */
-typedef struct LassoSelectUserData {
+struct LassoSelectUserData {
ViewContext *vc;
const rcti *rect;
const rctf *rect_fl;
@@ -402,7 +407,7 @@ typedef struct LassoSelectUserData {
int pass;
bool is_done;
bool is_changed;
-} LassoSelectUserData;
+};
static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
ViewContext *vc,
@@ -421,7 +426,7 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
r_data->mcoords_len = mcoords_len;
r_data->sel_op = sel_op;
/* SELECT by default, but can be changed if needed (only few cases use and respect this). */
- r_data->select_flag = SELECT;
+ r_data->select_flag = (eBezTriple_Flag)SELECT;
/* runtime */
r_data->pass = 0;
@@ -434,24 +439,24 @@ static bool view3d_selectable_data(bContext *C)
Object *ob = CTX_data_active_object(C);
if (!ED_operator_region_view3d_active(C)) {
- return 0;
+ return false;
}
if (ob) {
if (ob->mode & OB_MODE_EDIT) {
if (ob->type == OB_FONT) {
- return 0;
+ return false;
}
}
else {
if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) &&
!BKE_paint_select_elem_test(ob)) {
- return 0;
+ return false;
}
}
}
- return 1;
+ return true;
}
/* helper also for box_select */
@@ -466,21 +471,21 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2
/* check points in rect */
if (edge_fully_inside_rect(rect, v1, v2)) {
- return 1;
+ return true;
}
/* check points completely out rect */
if (v1[0] < rect->xmin && v2[0] < rect->xmin) {
- return 0;
+ return false;
}
if (v1[0] > rect->xmax && v2[0] > rect->xmax) {
- return 0;
+ return false;
}
if (v1[1] < rect->ymin && v2[1] < rect->ymin) {
- return 0;
+ return false;
}
if (v1[1] > rect->ymax && v2[1] > rect->ymax) {
- return 0;
+ return false;
}
/* simple check lines intersecting. */
@@ -490,22 +495,22 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2
d4 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
if (d1 < 0 && d2 < 0 && d3 < 0 && d4 < 0) {
- return 0;
+ return false;
}
if (d1 > 0 && d2 > 0 && d3 > 0 && d4 > 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void do_lasso_select_pose__do_tag(void *userData,
- struct bPoseChannel *pchan,
+ bPoseChannel *pchan,
const float screen_co_a[2],
const float screen_co_b[2])
{
- LassoSelectUserData *data = userData;
- const bArmature *arm = data->vc->obact->data;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
+ const bArmature *arm = static_cast<bArmature *>(data->vc->obact->data);
if (!PBONE_SELECTABLE(arm, pchan->bone)) {
return;
}
@@ -526,7 +531,7 @@ static void do_lasso_tag_pose(ViewContext *vc,
LassoSelectUserData data;
rcti rect;
- if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) {
+ if ((ob->type != OB_ARMATURE) || (ob->pose == nullptr)) {
return;
}
@@ -535,7 +540,8 @@ static void do_lasso_tag_pose(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0);
+ view3d_userdata_lassoselect_init(
+ &data, vc, &rect, mcoords, mcoords_len, static_cast<eSelectOp>(0));
ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
@@ -559,7 +565,7 @@ static bool do_lasso_select_objects(ViewContext *vc,
changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
}
- for (base = vc->view_layer->object_bases.first; base; base = base->next) {
+ for (base = static_cast<Base *>(vc->view_layer->object_bases.first); base; base = base->next) {
if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */
const bool is_select = base->flag & BASE_SELECTED;
const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) &&
@@ -583,32 +589,31 @@ static bool do_lasso_select_objects(ViewContext *vc,
/**
* Use for lasso & box select.
*/
-static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len)
+static blender::Vector<Base *> do_pose_tag_select_op_prepare(ViewContext *vc)
{
- Base **bases = NULL;
- BLI_array_declare(bases);
+ blender::Vector<Base *> bases;
+
FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_ARMATURE, OB_MODE_POSE, base_iter) {
Object *ob_iter = base_iter->object;
- bArmature *arm = ob_iter->data;
+ bArmature *arm = static_cast<bArmature *>(ob_iter->data);
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
Bone *bone = pchan->bone;
bone->flag &= ~BONE_DONE;
}
arm->id.tag |= LIB_TAG_DOIT;
ob_iter->id.tag &= ~LIB_TAG_DOIT;
- BLI_array_append(bases, base_iter);
+ bases.append(base_iter);
}
FOREACH_BASE_IN_MODE_END;
- *r_bases_len = BLI_array_len(bases);
return bases;
}
-static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op)
+static bool do_pose_tag_select_op_exec(blender::MutableSpan<Base *> bases, const eSelectOp sel_op)
{
bool changed_multi = false;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- for (int i = 0; i < bases_len; i++) {
+ for (const int i : bases.index_range()) {
Base *base_iter = bases[i];
Object *ob_iter = base_iter->object;
if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, false)) {
@@ -618,10 +623,10 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
}
}
- for (int i = 0; i < bases_len; i++) {
+ for (const int i : bases.index_range()) {
Base *base_iter = bases[i];
Object *ob_iter = base_iter->object;
- bArmature *arm = ob_iter->data;
+ bArmature *arm = static_cast<bArmature *>(ob_iter->data);
/* Don't handle twice. */
if (arm->id.tag & LIB_TAG_DOIT) {
@@ -642,7 +647,7 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
SET_FLAG_FROM_TEST(bone->flag, sel_op_result, BONE_SELECTED);
if (sel_op_result == 0) {
if (arm->act_bone == bone) {
- arm->act_bone = NULL;
+ arm->act_bone = nullptr;
}
}
changed = true;
@@ -662,22 +667,20 @@ static bool do_lasso_select_pose(ViewContext *vc,
const int mcoords_len,
const eSelectOp sel_op)
{
- uint bases_len;
- Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
+ blender::Vector<Base *> bases = do_pose_tag_select_op_prepare(vc);
- for (int i = 0; i < bases_len; i++) {
+ for (const int i : bases.index_range()) {
Base *base_iter = bases[i];
Object *ob_iter = base_iter->object;
do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len);
}
- const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
+ const bool changed_multi = do_pose_tag_select_op_exec(bases, sel_op);
if (changed_multi) {
DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene);
}
- MEM_freeN(bases);
return changed_multi;
}
@@ -686,7 +689,7 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- LassoSelectUserData *data = userData;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
const bool is_inside =
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
@@ -700,7 +703,7 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
}
struct LassoSelectUserData_ForMeshEdge {
LassoSelectUserData *data;
- struct EditSelectBuf_Cache *esel;
+ EditSelectBuf_Cache *esel;
uint backbuf_offset;
};
static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
@@ -709,7 +712,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
const float screen_co_b[2],
int index)
{
- struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
+ LassoSelectUserData_ForMeshEdge *data_for_edge = static_cast<LassoSelectUserData_ForMeshEdge *>(
+ user_data);
LassoSelectUserData *data = data_for_edge->data;
bool is_visible = true;
if (data_for_edge->backbuf_offset) {
@@ -737,7 +741,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
const float screen_co_b[2],
int index)
{
- struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
+ LassoSelectUserData_ForMeshEdge *data_for_edge = static_cast<LassoSelectUserData_ForMeshEdge *>(
+ user_data);
LassoSelectUserData *data = data_for_edge->data;
bool is_visible = true;
if (data_for_edge->backbuf_offset) {
@@ -763,7 +768,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- LassoSelectUserData *data = userData;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
const bool is_inside =
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
@@ -807,13 +812,13 @@ static bool do_lasso_select_mesh(ViewContext *vc,
const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
if (use_zbuf) {
- if (wm_userdata->data == NULL) {
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
- esel = wm_userdata->data;
+ esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr);
}
}
@@ -829,16 +834,15 @@ static bool do_lasso_select_mesh(ViewContext *vc,
}
if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
- struct LassoSelectUserData_ForMeshEdge data_for_edge = {
- .data = &data,
- .esel = use_zbuf ? esel : NULL,
- .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
- vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
- 0,
- };
+ LassoSelectUserData_ForMeshEdge data_for_edge{};
+ data_for_edge.data = &data;
+ data_for_edge.esel = use_zbuf ? esel : nullptr;
+ data_for_edge.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
+ vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
+ 0;
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
- (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
+ (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB);
/* Fully inside. */
mesh_foreachScreenEdge_clip_bb_segment(
vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
@@ -877,7 +881,7 @@ static void do_lasso_select_curve__doSelect(void *userData,
bool handles_visible,
const float screen_co[2])
{
- LassoSelectUserData *data = userData;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
const bool is_inside = BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED);
@@ -943,14 +947,14 @@ static bool do_lasso_select_curve(ViewContext *vc,
}
if (data.is_changed) {
- BKE_curve_nurb_vert_active_validate(vc->obedit->data);
+ BKE_curve_nurb_vert_active_validate(static_cast<Curve *>(vc->obedit->data));
}
return data.is_changed;
}
static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
{
- LassoSelectUserData *data = userData;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
const bool is_select = bp->f1 & SELECT;
const bool is_inside =
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
@@ -989,8 +993,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
const float screen_co_a[2],
const float screen_co_b[2])
{
- LassoSelectUserData *data = userData;
- const bArmature *arm = data->vc->obedit->data;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
+ const bArmature *arm = static_cast<const bArmature *>(data->vc->obedit->data);
if (!EBONE_VISIBLE(arm, ebone)) {
return;
}
@@ -1038,8 +1042,8 @@ static void do_lasso_select_armature__doSelectBone_clip_content(void *userData,
const float screen_co_a[2],
const float screen_co_b[2])
{
- LassoSelectUserData *data = userData;
- bArmature *arm = data->vc->obedit->data;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
+ bArmature *arm = static_cast<bArmature *>(data->vc->obedit->data);
if (!EBONE_VISIBLE(arm, ebone)) {
return;
}
@@ -1078,7 +1082,7 @@ static bool do_lasso_select_armature(ViewContext *vc,
data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit);
}
- bArmature *arm = vc->obedit->data;
+ bArmature *arm = static_cast<bArmature *>(vc->obedit->data);
ED_armature_ebone_listbase_temp_clear(arm->edbo);
@@ -1096,7 +1100,7 @@ static bool do_lasso_select_armature(ViewContext *vc,
&data,
V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
- data.is_changed |= ED_armature_edit_select_op_from_tagged(vc->obedit->data, sel_op);
+ data.is_changed |= ED_armature_edit_select_op_from_tagged(arm, sel_op);
if (data.is_changed) {
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit);
@@ -1105,10 +1109,10 @@ static bool do_lasso_select_armature(ViewContext *vc,
}
static void do_lasso_select_mball__doSelectElem(void *userData,
- struct MetaElem *ml,
+ MetaElem *ml,
const float screen_co[2])
{
- LassoSelectUserData *data = userData;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
const bool is_select = ml->flag & SELECT;
const bool is_inside =
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
@@ -1151,7 +1155,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- LassoSelectUserData *data = userData;
+ LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData);
const bool is_select = mv->flag & SELECT;
const bool is_inside =
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
@@ -1171,10 +1175,10 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
{
const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
Object *ob = vc->obact;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
rcti rect;
- if (me == NULL || me->totvert == 0) {
+ if (me == nullptr || me->totvert == 0) {
return false;
}
@@ -1186,18 +1190,18 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
if (use_zbuf) {
- if (wm_userdata->data == NULL) {
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
- esel = wm_userdata->data;
+ esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr);
}
}
if (use_zbuf) {
- if (esel->select_bitmap != NULL) {
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
}
}
@@ -1231,10 +1235,10 @@ static bool do_lasso_select_paintface(ViewContext *vc,
const eSelectOp sel_op)
{
Object *ob = vc->obact;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
rcti rect;
- if (me == NULL || me->totpoly == 0) {
+ if (me == nullptr || me->totpoly == 0) {
return false;
}
@@ -1246,12 +1250,12 @@ static bool do_lasso_select_paintface(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
- if (esel == NULL) {
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
+ if (esel == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
- esel = wm_userdata->data;
+ esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr);
}
if (esel->select_bitmap) {
@@ -1259,7 +1263,7 @@ static bool do_lasso_select_paintface(ViewContext *vc,
}
if (changed) {
- paintface_flush_flags(vc->C, ob, SELECT);
+ paintface_flush_flags(vc->C, ob, true, false);
}
return changed;
}
@@ -1273,10 +1277,10 @@ static bool view3d_lasso_select(bContext *C,
Object *ob = CTX_data_active_object(C);
bool changed_multi = false;
- wmGenericUserData wm_userdata_buf = {0};
+ wmGenericUserData wm_userdata_buf = {nullptr, nullptr, false};
wmGenericUserData *wm_userdata = &wm_userdata_buf;
- if (vc->obedit == NULL) { /* Object Mode */
+ if (vc->obedit == nullptr) { /* Object Mode */
if (BKE_paint_select_face_test(ob)) {
changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
@@ -1288,7 +1292,7 @@ static bool view3d_lasso_select(bContext *C,
/* pass */
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op);
+ changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op) != OPERATOR_CANCELLED;
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op);
@@ -1334,7 +1338,7 @@ static bool view3d_lasso_select(bContext *C,
}
if (changed) {
- DEG_id_tag_update(vc->obedit->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(vc->obedit->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
changed_multi = true;
}
@@ -1363,7 +1367,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ eSelectOp sel_op = static_cast<eSelectOp>(RNA_enum_get(op->ptr, "mode"));
bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
MEM_freeN((void *)mcoords);
@@ -1403,12 +1407,12 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
* \{ */
/* The max number of menu items in an object select menu */
-typedef struct SelMenuItemF {
+struct SelMenuItemF {
char idname[MAX_ID_NAME - 2];
int icon;
Base *base_ptr;
void *item_ptr;
-} SelMenuItemF;
+};
#define SEL_MENU_SIZE 22
static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE];
@@ -1419,12 +1423,12 @@ static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- EnumPropertyItem *item = NULL, item_tmp = {0};
+ EnumPropertyItem *item = nullptr, item_tmp = {0};
int totitem = 0;
int i = 0;
/* Don't need context but avoid API doc-generation using this. */
- if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') {
+ if (C == nullptr || object_mouse_select_menu_data[i].idname[0] == '\0') {
return DummyRNA_NULL_items;
}
@@ -1453,9 +1457,9 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *oldbasact = BASACT(view_layer);
+ const Base *oldbasact = view_layer->basact;
- Base *basact = NULL;
+ Base *basact = nullptr;
CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
/* This is a bit dodgy, there should only be ONE object with this name,
* but library objects can mess this up. */
@@ -1466,7 +1470,7 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- if (basact == NULL) {
+ if (basact == nullptr) {
return OPERATOR_CANCELLED;
}
UNUSED_VARS_NDEBUG(v3d);
@@ -1537,14 +1541,14 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
/* #Object.id.name to select (dynamic enum). */
prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE));
ot->prop = prop;
- prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
+ prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1556,12 +1560,12 @@ static bool object_mouse_select_menu(bContext *C,
const GPUSelectResult *buffer,
const int hits,
const int mval[2],
- const struct SelectPick_Params *params,
+ const SelectPick_Params *params,
Base **r_basact)
{
int base_count = 0;
bool ok;
- LinkNodePair linklist = {NULL, NULL};
+ LinkNodePair linklist = {nullptr, nullptr};
/* handle base->object->select_id */
CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
@@ -1598,14 +1602,14 @@ static bool object_mouse_select_menu(bContext *C,
}
CTX_DATA_END;
- *r_basact = NULL;
+ *r_basact = nullptr;
if (base_count == 0) {
return false;
}
if (base_count == 1) {
Base *base = (Base *)linklist.list->link;
- BLI_linklist_free(linklist.list, NULL);
+ BLI_linklist_free(linklist.list, nullptr);
*r_basact = base;
return false;
}
@@ -1617,7 +1621,7 @@ static bool object_mouse_select_menu(bContext *C,
memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
for (node = linklist.list, i = 0; node; node = node->next, i++) {
- Base *base = node->link;
+ Base *base = static_cast<Base *>(node->link);
Object *ob = base->object;
const char *name = ob->id.name + 2;
@@ -1632,10 +1636,10 @@ static bool object_mouse_select_menu(bContext *C,
RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD);
RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB);
RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr);
WM_operator_properties_free(&ptr);
- BLI_linklist_free(linklist.list, NULL);
+ BLI_linklist_free(linklist.list, nullptr);
return true;
}
@@ -1643,17 +1647,16 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op)
{
const int name_index = RNA_enum_get(op->ptr, "name");
- const struct SelectPick_Params params = {
- .sel_op = ED_select_op_from_operator(op->ptr),
- };
+ SelectPick_Params params{};
+ params.sel_op = ED_select_op_from_operator(op->ptr);
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *oldbasact = BASACT(view_layer);
+ const Base *oldbasact = view_layer->basact;
Base *basact = object_mouse_select_menu_data[name_index].base_ptr;
- if (basact == NULL) {
+ if (basact == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1728,14 +1731,14 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
/* #Object.id.name to select (dynamic enum). */
prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Bone Name", "");
RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE));
ot->prop = prop;
- prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
+ prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1746,19 +1749,19 @@ static bool bone_mouse_select_menu(bContext *C,
const GPUSelectResult *buffer,
const int hits,
const bool is_editmode,
- const struct SelectPick_Params *params)
+ const SelectPick_Params *params)
{
BLI_assert(buffer);
int bone_count = 0;
- LinkNodePair base_list = {NULL, NULL};
- LinkNodePair bone_list = {NULL, NULL};
+ LinkNodePair base_list = {nullptr, nullptr};
+ LinkNodePair bone_list = {nullptr, nullptr};
GSet *added_bones = BLI_gset_ptr_new("Bone mouse select menu");
/* Select logic taken from ed_armature_pick_bone_from_selectbuffer_impl in armature_select.c */
for (int a = 0; a < hits; a++) {
- void *bone_ptr = NULL;
- Base *bone_base = NULL;
+ void *bone_ptr = nullptr;
+ Base *bone_base = nullptr;
uint hitresult = buffer[a].id;
if (!(hitresult & BONESEL_ANY)) {
@@ -1786,8 +1789,8 @@ static bool bone_mouse_select_menu(bContext *C,
if (is_editmode) {
EditBone *ebone;
const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
- bArmature *arm = bone_base->object->data;
- ebone = BLI_findlink(arm->edbo, hit_bone);
+ bArmature *arm = static_cast<bArmature *>(bone_base->object->data);
+ ebone = static_cast<EditBone *>(BLI_findlink(arm->edbo, hit_bone));
if (ebone && !(ebone->flag & BONE_UNSELECTABLE)) {
bone_ptr = ebone;
}
@@ -1795,7 +1798,8 @@ static bool bone_mouse_select_menu(bContext *C,
else {
bPoseChannel *pchan;
const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
- pchan = BLI_findlink(&bone_base->object->pose->chanbase, hit_bone);
+ pchan = static_cast<bPoseChannel *>(
+ BLI_findlink(&bone_base->object->pose->chanbase, hit_bone));
if (pchan && !(pchan->bone->flag & BONE_UNSELECTABLE)) {
bone_ptr = pchan;
}
@@ -1820,14 +1824,14 @@ static bool bone_mouse_select_menu(bContext *C,
}
}
- BLI_gset_free(added_bones, NULL);
+ BLI_gset_free(added_bones, nullptr);
if (bone_count == 0) {
return false;
}
if (bone_count == 1) {
- BLI_linklist_free(base_list.list, NULL);
- BLI_linklist_free(bone_list.list, NULL);
+ BLI_linklist_free(base_list.list, nullptr);
+ BLI_linklist_free(bone_list.list, nullptr);
return false;
}
@@ -1841,15 +1845,15 @@ static bool bone_mouse_select_menu(bContext *C,
base_node = base_node->next, bone_node = bone_node->next, i++) {
char *name;
- object_mouse_select_menu_data[i].base_ptr = base_node->link;
+ object_mouse_select_menu_data[i].base_ptr = static_cast<Base *>(base_node->link);
if (is_editmode) {
- EditBone *ebone = bone_node->link;
+ EditBone *ebone = static_cast<EditBone *>(bone_node->link);
object_mouse_select_menu_data[i].item_ptr = ebone;
name = ebone->name;
}
else {
- bPoseChannel *pchan = bone_node->link;
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(bone_node->link);
object_mouse_select_menu_data[i].item_ptr = pchan;
name = pchan->name;
}
@@ -1865,11 +1869,11 @@ static bool bone_mouse_select_menu(bContext *C,
RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD);
RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB);
RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr);
WM_operator_properties_free(&ptr);
- BLI_linklist_free(base_list.list, NULL);
- BLI_linklist_free(bone_list.list, NULL);
+ BLI_linklist_free(base_list.list, nullptr);
+ BLI_linklist_free(bone_list.list, nullptr);
return true;
}
@@ -1927,7 +1931,7 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
int hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
- int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ eV3DSelectMode select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
int hits = 0;
if (do_nearest_xray_if_supported) {
@@ -2083,7 +2087,7 @@ static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b
* that are visible but not select-able,
* since you may be in pose mode with an un-selectable object.
*
- * \return the active base or NULL.
+ * \return the active base or nullptr.
*/
static Base *mouse_select_eval_buffer(ViewContext *vc,
const GPUSelectResult *buffer,
@@ -2135,7 +2139,8 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
else {
{
- GPUSelectResult *buffer_sorted = MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__);
+ GPUSelectResult *buffer_sorted = static_cast<GPUSelectResult *>(
+ MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__));
memcpy(buffer_sorted, buffer, sizeof(*buffer_sorted) * hits);
/* Remove non-bone objects. */
if (has_bones && do_bones_get_priotity) {
@@ -2155,8 +2160,8 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
/* It's possible there are no hits (all objects contained bones). */
if (hits > 0) {
/* Only exclude active object when it is selected. */
- if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED)) {
- const int select_id_active = BASACT(view_layer)->object->runtime.select_id;
+ if (view_layer->basact && (view_layer->basact->flag & BASE_SELECTED)) {
+ const int select_id_active = view_layer->basact->object->runtime.select_id;
for (int i_next = 0, i_prev = hits - 1; i_next < hits; i_prev = i_next++) {
if ((select_id_active == (buffer[i_prev].id & 0xFFFF)) &&
(select_id_active != (buffer[i_next].id & 0xFFFF))) {
@@ -2181,9 +2186,9 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
MEM_freeN((void *)buffer);
}
- Base *basact = NULL;
+ Base *basact = nullptr;
if (found) {
- for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
if (base->object->runtime.select_id == select_id) {
basact = base;
@@ -2206,11 +2211,11 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const
ViewLayer *view_layer = vc->view_layer;
View3D *v3d = vc->v3d;
- Base *oldbasact = BASACT(view_layer);
+ Base *oldbasact = view_layer->basact;
const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
float dist = ED_view3d_select_dist_px() * 1.3333f;
- Base *basact = NULL;
+ Base *basact = nullptr;
/* Put the active object at a disadvantage to cycle through other objects. */
const float penalty_dist = 10.0f * UI_DPI_FAC;
@@ -2233,8 +2238,8 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const
}
base = base->next;
- if (base == NULL) {
- base = FIRSTBASE(view_layer);
+ if (base == nullptr) {
+ base = static_cast<Base *>(view_layer->object_bases.first);
}
if (base == startbase) {
break;
@@ -2249,7 +2254,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- Base *basact = NULL;
+ Base *basact = nullptr;
GPUSelectResult buffer[MAXPICKELEMS];
/* setup view context for argument to callbacks */
@@ -2259,7 +2264,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
- const bool do_material_slot_selection = r_material_slot != NULL;
+ const bool do_material_slot_selection = r_material_slot != nullptr;
const int hits = mixed_bones_object_selectbuffer(&vc,
buffer,
ARRAY_SIZE(buffer),
@@ -2270,7 +2275,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
do_material_slot_selection);
if (hits > 0) {
- const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits);
+ const bool has_bones = (r_material_slot == nullptr) && selectbuffer_has_bones(buffer, hits);
basact = mouse_select_eval_buffer(
&vc, buffer, hits, do_nearest, has_bones, true, r_material_slot);
}
@@ -2280,7 +2285,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
- return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
+ return ed_view3d_give_base_under_cursor_ex(C, mval, nullptr);
}
Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
@@ -2289,33 +2294,33 @@ Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
if (base) {
return base->object;
}
- return NULL;
+ return nullptr;
}
-struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
- const int mval[2],
- int *r_material_slot)
+Object *ED_view3d_give_material_slot_under_cursor(bContext *C,
+ const int mval[2],
+ int *r_material_slot)
{
Base *base = ed_view3d_give_base_under_cursor_ex(C, mval, r_material_slot);
if (base) {
return base->object;
}
- return NULL;
+ return nullptr;
}
bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2])
{
- return ED_view3d_give_object_under_cursor(C, mval) != NULL;
+ return ED_view3d_give_object_under_cursor(C, mval) != nullptr;
}
static void deselect_all_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object;
- object = tracking->objects.first;
+ object = static_cast<MovieTrackingObject *>(tracking->objects.first);
while (object) {
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track = tracksbase->first;
+ MovieTrackingTrack *track = static_cast<MovieTrackingTrack *>(tracksbase->first);
while (track) {
BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
@@ -2331,16 +2336,16 @@ static bool ed_object_select_pick_camera_track(bContext *C,
Scene *scene,
Base *basact,
MovieClip *clip,
- const struct GPUSelectResult *buffer,
+ const GPUSelectResult *buffer,
const short hits,
- const struct SelectPick_Params *params)
+ const SelectPick_Params *params)
{
bool changed = false;
bool found = false;
MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = NULL;
- MovieTrackingTrack *track = NULL;
+ ListBase *tracksbase = nullptr;
+ MovieTrackingTrack *track = nullptr;
for (int i = 0; i < hits; i++) {
const int hitresult = buffer[i].id;
@@ -2428,7 +2433,7 @@ static bool ed_object_select_pick_camera_track(bContext *C,
*/
static bool ed_object_select_pick(bContext *C,
const int mval[2],
- const struct SelectPick_Params *params,
+ const SelectPick_Params *params,
const bool center,
const bool enumerate,
const bool object_only)
@@ -2442,21 +2447,21 @@ static bool ed_object_select_pick(bContext *C,
View3D *v3d = vc.v3d;
/* Menu activation may find a base to make active (if it only finds a single item to select). */
- Base *basact_override = NULL;
+ Base *basact_override = nullptr;
- const bool is_obedit = (vc.obedit != NULL);
+ const bool is_obedit = (vc.obedit != nullptr);
if (object_only) {
/* Signal for #view3d_opengl_select to skip edit-mode objects. */
- vc.obedit = NULL;
+ vc.obedit = nullptr;
}
- /* Set for GPU depth buffer picking, leave NULL when selecting by center. */
- struct {
+ /* Set for GPU depth buffer picking, leave null when selecting by center. */
+ struct GPUData {
GPUSelectResult buffer[MAXPICKELEMS];
int hits;
bool do_nearest;
bool has_bones;
- } *gpu = NULL;
+ } *gpu = nullptr;
/* First handle menu selection, early exit if a menu opens
* since this takes ownership of the selection action.
@@ -2465,7 +2470,7 @@ static bool ed_object_select_pick(bContext *C,
* the item under the cursor. */
if (center == false) {
- gpu = MEM_mallocN(sizeof(*gpu), __func__);
+ gpu = MEM_new<GPUData>(__func__);
gpu->do_nearest = false;
gpu->has_bones = false;
@@ -2492,7 +2497,7 @@ static bool ed_object_select_pick(bContext *C,
if (enumerate) {
bool has_menu = false;
if (center) {
- if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) {
+ if (object_mouse_select_menu(C, &vc, nullptr, 0, mval, params, &basact_override)) {
has_menu = true;
}
}
@@ -2510,7 +2515,7 @@ static bool ed_object_select_pick(bContext *C,
/* Let the menu handle any further actions. */
if (has_menu) {
- if (gpu != NULL) {
+ if (gpu != nullptr) {
MEM_freeN(gpu);
}
return false;
@@ -2521,13 +2526,16 @@ static bool ed_object_select_pick(bContext *C,
ViewLayer *view_layer = vc.view_layer;
/* Don't set when the context has no active object (hidden), see: T60807. */
- const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
+ const Base *oldbasact = vc.obact ? view_layer->basact : nullptr;
/* Always start list from `basact` when cycling the selection. */
- Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer);
+ Base *startbase = (oldbasact && oldbasact->next) ?
+ oldbasact->next :
+ static_cast<Base *>(view_layer->object_bases.first);
/* The next object's base to make active. */
- Base *basact = NULL;
- const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
+ Base *basact = nullptr;
+ const eObjectMode object_mode = oldbasact ? static_cast<eObjectMode>(oldbasact->object->mode) :
+ OB_MODE_OBJECT;
/* When enabled, don't attempt any further selection. */
bool handled = false;
@@ -2574,8 +2582,8 @@ static bool ed_object_select_pick(bContext *C,
gpu->do_nearest,
gpu->has_bones,
do_bones_get_priotity,
- NULL) :
- NULL;
+ nullptr) :
+ nullptr;
}
/* Select pose-bones or camera-tracks. */
@@ -2585,7 +2593,7 @@ static bool ed_object_select_pick(bContext *C,
if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) {
MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
- if (clip != NULL) {
+ if (clip != nullptr) {
if (ed_object_select_pick_camera_track(
C, scene, basact, clip, gpu->buffer, gpu->hits, params)) {
ED_object_base_select(basact, BA_SELECT);
@@ -2598,7 +2606,7 @@ static bool ed_object_select_pick(bContext *C,
/* Fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object. */
basact = mouse_select_eval_buffer(
- &vc, gpu->buffer, gpu->hits, gpu->do_nearest, false, false, NULL);
+ &vc, gpu->buffer, gpu->hits, gpu->do_nearest, false, false, nullptr);
}
}
}
@@ -2615,7 +2623,7 @@ static bool ed_object_select_pick(bContext *C,
/* When there is no `baseact` this will have operated on `oldbasact`,
* allowing #SelectPick_Params.deselect_all work in pose-mode.
* In this case no object operations are needed. */
- if (basact != NULL) {
+ if (basact != nullptr) {
/* By convention the armature-object is selected when in pose-mode.
* While leaving it unselected will work, leaving pose-mode would leave the object
* active + unselected which isn't ideal when performing other actions on the object. */
@@ -2670,11 +2678,11 @@ static bool ed_object_select_pick(bContext *C,
if (is_obedit == false) {
if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
- struct Main *bmain = vc.bmain;
+ Main *bmain = vc.bmain;
ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
}
if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
- basact = NULL;
+ basact = nullptr;
}
}
@@ -2683,7 +2691,7 @@ static bool ed_object_select_pick(bContext *C,
if (basact && oldbasact) {
if ((oldbasact->object->mode != basact->object->mode) &&
(oldbasact->object->mode & basact->object->mode) == 0) {
- basact = NULL;
+ basact = nullptr;
}
}
}
@@ -2692,10 +2700,10 @@ static bool ed_object_select_pick(bContext *C,
/* Ensure code above doesn't change the active base. This code is already fairly involved,
* it's best if changing the active object is localized to a single place. */
- BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
+ BLI_assert(oldbasact == (vc.obact ? view_layer->basact : nullptr));
- bool found = (basact != NULL);
- if ((handled == false) && (vc.obedit == NULL)) {
+ bool found = (basact != nullptr);
+ if ((handled == false) && (vc.obedit == nullptr)) {
/* Object-mode (pose mode will have been handled already). */
if (params->sel_op == SEL_OP_SET) {
if ((found && params->select_passthrough) && (basact->flag & BASE_SELECTED)) {
@@ -2703,7 +2711,7 @@ static bool ed_object_select_pick(bContext *C,
}
else if (found || params->deselect_all) {
/* Deselect everything. */
- /* `basact` may be NULL. */
+ /* `basact` may be nullptr. */
if (ED_view3d_object_deselect_all_except(view_layer, basact)) {
changed_object = true;
}
@@ -2763,7 +2771,7 @@ static bool ed_object_select_pick(bContext *C,
/* Perform the activation even when 'handled', since this is used to ensure
* the object from the pose-bone selected is also activated. */
- if (use_activate_selected_base && (basact != NULL)) {
+ if (use_activate_selected_base && (basact != nullptr)) {
changed_object = true;
ED_object_base_activate(C, basact); /* adds notifier */
if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) {
@@ -2782,7 +2790,7 @@ static bool ed_object_select_pick(bContext *C,
ED_outliner_select_sync_from_pose_bone_tag(C);
}
- if (gpu != NULL) {
+ if (gpu != nullptr) {
MEM_freeN(gpu);
}
@@ -2797,21 +2805,23 @@ static bool ed_object_select_pick(bContext *C,
*/
static bool ed_wpaint_vertex_select_pick(bContext *C,
const int mval[2],
- const struct SelectPick_Params *params,
+ const SelectPick_Params *params,
Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
const bool use_zbuf = !XRAY_ENABLED(v3d);
- Mesh *me = obact->data; /* already checked for NULL */
+ Mesh *me = static_cast<Mesh *>(obact->data); /* already checked for nullptr */
uint index = 0;
+ MVert *verts = BKE_mesh_verts_for_write(me);
+
MVert *mv;
bool changed = false;
bool found = ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index);
if (params->sel_op == SEL_OP_SET) {
- if ((found && params->select_passthrough) && (me->mvert[index].flag & SELECT)) {
+ if ((found && params->select_passthrough) && (verts[index].flag & SELECT)) {
found = false;
}
else if (found || params->deselect_all) {
@@ -2821,7 +2831,7 @@ static bool ed_wpaint_vertex_select_pick(bContext *C,
}
if (found) {
- mv = &me->mvert[index];
+ mv = &verts[index];
switch (params->sel_op) {
case SEL_OP_ADD: {
mv->flag |= SELECT;
@@ -2872,7 +2882,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
- struct SelectPick_Params params = {0};
+ SelectPick_Params params{};
ED_select_pick_params_from_operator(op->ptr, &params);
const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles");
@@ -2892,14 +2902,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
bool changed = false;
int mval[2];
- RNA_int_get_array(op->ptr, "location", mval);
-
- view3d_operator_needs_opengl(C);
- BKE_object_update_select_id(CTX_data_main(C));
-
if (object_only) {
- obedit = NULL;
- obact = NULL;
+ obedit = nullptr;
+ obact = nullptr;
/* ack, this is incorrect but to do this correctly we would need an
* alternative edit-mode/object-mode keymap, this copies the functionality
@@ -2907,6 +2912,19 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
center = false;
}
+ if (obedit && enumerate) {
+ /* Enumerate makes no sense in edit-mode unless also explicitly picking objects or bones.
+ * Pass the event through so the event may be handled by loop-select for e.g. see: T100204. */
+ if (obedit->type != OB_ARMATURE) {
+ return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
+ }
+ }
+
+ RNA_int_get_array(op->ptr, "location", mval);
+
+ view3d_operator_needs_opengl(C);
+ BKE_object_update_select_id(CTX_data_main(C));
+
if (obedit && object_only == false) {
if (obedit->type == OB_MESH) {
changed = EDBM_select_pick(C, mval, &params);
@@ -2998,21 +3016,25 @@ void VIEW3D_OT_select(wmOperatorType *ot)
prop = RNA_def_boolean(
ot->srna,
"center",
- 0,
+ false,
"Center",
"Use the object center when selecting, in edit mode used to extend object selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(
- ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
+ prop = RNA_def_boolean(ot->srna,
+ "enumerate",
+ false,
+ "Enumerate",
+ "List objects under the mouse (object mode only)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)");
+ prop = RNA_def_boolean(
+ ot->srna, "object", false, "Object", "Use object selection (edit mode only)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* Needed for select-through to usefully drag handles, see: T98254.
* NOTE: this option may be removed and become default behavior, see design task: T98552. */
prop = RNA_def_boolean(ot->srna,
"vert_without_handles",
- 0,
+ false,
"Control Point Without Handles",
"Only select the curve control point, not it's handles");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -3020,7 +3042,7 @@ void VIEW3D_OT_select(wmOperatorType *ot)
prop = RNA_def_int_vector(ot->srna,
"location",
2,
- NULL,
+ nullptr,
INT_MIN,
INT_MAX,
"Location",
@@ -3036,7 +3058,7 @@ void VIEW3D_OT_select(wmOperatorType *ot)
/** \name Box Select
* \{ */
-typedef struct BoxSelectUserData {
+struct BoxSelectUserData {
ViewContext *vc;
const rcti *rect;
const rctf *rect_fl;
@@ -3047,7 +3069,7 @@ typedef struct BoxSelectUserData {
/* runtime */
bool is_done;
bool is_changed;
-} BoxSelectUserData;
+};
static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
ViewContext *vc,
@@ -3062,7 +3084,7 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
r_data->sel_op = sel_op;
/* SELECT by default, but can be changed if needed (only few cases use and respect this). */
- r_data->select_flag = SELECT;
+ r_data->select_flag = (eBezTriple_Flag)SELECT;
/* runtime */
r_data->is_done = false;
@@ -3083,7 +3105,7 @@ static void do_paintvert_box_select__doSelectVert(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- BoxSelectUserData *data = userData;
+ BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_select = mv->flag & SELECT;
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
@@ -3099,11 +3121,9 @@ static bool do_paintvert_box_select(ViewContext *vc,
{
const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
- Mesh *me;
-
- me = vc->obact->data;
- if ((me == NULL) || (me->totvert == 0)) {
- return OPERATOR_CANCELLED;
+ Mesh *me = static_cast<Mesh *>(vc->obact->data);
+ if ((me == nullptr) || (me->totvert == 0)) {
+ return false;
}
bool changed = false;
@@ -3115,14 +3135,14 @@ static bool do_paintvert_box_select(ViewContext *vc,
/* pass */
}
else if (use_zbuf) {
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
- if (wm_userdata->data == NULL) {
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
- esel = wm_userdata->data;
+ esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
- vc->depsgraph, vc->region, vc->v3d, rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, rect, nullptr);
}
- if (esel->select_bitmap != NULL) {
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
}
}
@@ -3151,13 +3171,13 @@ static bool do_paintvert_box_select(ViewContext *vc,
static bool do_paintface_box_select(ViewContext *vc,
wmGenericUserData *wm_userdata,
const rcti *rect,
- int sel_op)
+ eSelectOp sel_op)
{
Object *ob = vc->obact;
Mesh *me;
me = BKE_mesh_from_object(ob);
- if ((me == NULL) || (me->totpoly == 0)) {
+ if ((me == nullptr) || (me->totpoly == 0)) {
return false;
}
@@ -3170,20 +3190,20 @@ static bool do_paintface_box_select(ViewContext *vc,
/* pass */
}
else {
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
- if (wm_userdata->data == NULL) {
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
- esel = wm_userdata->data;
+ esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
- vc->depsgraph, vc->region, vc->v3d, rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, rect, nullptr);
}
- if (esel->select_bitmap != NULL) {
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
}
}
if (changed) {
- paintface_flush_flags(vc->C, vc->obact, SELECT);
+ paintface_flush_flags(vc->C, vc->obact, true, false);
}
return changed;
}
@@ -3196,7 +3216,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
bool handles_visible,
const float screen_co[2])
{
- BoxSelectUserData *data = userData;
+ BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
if (bp) {
@@ -3253,14 +3273,14 @@ static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel
data.is_changed |= BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
}
- BKE_curve_nurb_vert_active_validate(vc->obedit->data);
+ BKE_curve_nurb_vert_active_validate(curve);
return data.is_changed;
}
static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
{
- BoxSelectUserData *data = userData;
+ BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_select = bp->f1 & SELECT;
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
@@ -3291,7 +3311,7 @@ static void do_mesh_box_select__doSelectVert(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- BoxSelectUserData *data = userData;
+ BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
@@ -3302,7 +3322,7 @@ static void do_mesh_box_select__doSelectVert(void *userData,
}
struct BoxSelectUserData_ForMeshEdge {
BoxSelectUserData *data;
- struct EditSelectBuf_Cache *esel;
+ EditSelectBuf_Cache *esel;
uint backbuf_offset;
};
/**
@@ -3311,7 +3331,8 @@ struct BoxSelectUserData_ForMeshEdge {
static void do_mesh_box_select__doSelectEdge_pass0(
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
- struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
+ BoxSelectUserData_ForMeshEdge *data_for_edge = static_cast<BoxSelectUserData_ForMeshEdge *>(
+ userData);
BoxSelectUserData *data = data_for_edge->data;
bool is_visible = true;
if (data_for_edge->backbuf_offset) {
@@ -3335,7 +3356,8 @@ static void do_mesh_box_select__doSelectEdge_pass0(
static void do_mesh_box_select__doSelectEdge_pass1(
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
- struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
+ BoxSelectUserData_ForMeshEdge *data_for_edge = static_cast<BoxSelectUserData_ForMeshEdge *>(
+ userData);
BoxSelectUserData *data = data_for_edge->data;
bool is_visible = true;
if (data_for_edge->backbuf_offset) {
@@ -3356,7 +3378,7 @@ static void do_mesh_box_select__doSelectFace(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- BoxSelectUserData *data = userData;
+ BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData);
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
@@ -3389,13 +3411,13 @@ static bool do_mesh_box_select(ViewContext *vc,
const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
if (use_zbuf) {
- if (wm_userdata->data == NULL) {
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
- esel = wm_userdata->data;
+ esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
- vc->depsgraph, vc->region, vc->v3d, rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, rect, nullptr);
}
}
@@ -3411,16 +3433,16 @@ static bool do_mesh_box_select(ViewContext *vc,
}
if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
- struct BoxSelectUserData_ForMeshEdge cb_data = {
- .data = &data,
- .esel = use_zbuf ? esel : NULL,
- .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
- vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
- 0,
+ struct BoxSelectUserData_ForMeshEdge cb_data {
};
+ cb_data.data = &data;
+ cb_data.esel = use_zbuf ? esel : nullptr;
+ cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
+ vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
+ 0;
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
- (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
+ (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB);
/* Fully inside. */
mesh_foreachScreenEdge_clip_bb_segment(
vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
@@ -3470,7 +3492,8 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO
}
int metaelem_id = 0;
- for (ml = mb->editelems->first; ml; ml = ml->next, metaelem_id += 0x10000) {
+ for (ml = static_cast<MetaElem *>(mb->editelems->first); ml;
+ ml = ml->next, metaelem_id += 0x10000) {
bool is_inside_radius = false;
bool is_inside_stiff = false;
@@ -3544,7 +3567,7 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel
Object *obedit = bases[base_index]->object;
obedit->id.tag &= ~LIB_TAG_DOIT;
- bArmature *arm = obedit->data;
+ bArmature *arm = static_cast<bArmature *>(obedit->data);
ED_armature_ebone_listbase_temp_clear(arm->edbo);
}
@@ -3568,7 +3591,8 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel
Object *obedit = bases[base_index]->object;
if (obedit->id.tag & LIB_TAG_DOIT) {
obedit->id.tag &= ~LIB_TAG_DOIT;
- changed |= ED_armature_edit_select_op_from_tagged(obedit->data, sel_op);
+ changed |= ED_armature_edit_select_op_from_tagged(static_cast<bArmature *>(obedit->data),
+ sel_op);
}
}
@@ -3606,8 +3630,8 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
int totobj = MAXPICKELEMS; /* XXX solve later */
/* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */
- GPUSelectResult *buffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult),
- "selection buffer");
+ GPUSelectResult *buffer = static_cast<GPUSelectResult *>(
+ MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__));
const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene,
vc->obact);
const int hits = view3d_opengl_select(
@@ -3617,8 +3641,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
base->object->id.tag &= ~LIB_TAG_DOIT;
}
- Base **bases = NULL;
- BLI_array_declare(bases);
+ blender::Vector<Base *> bases;
bool changed = false;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -3632,7 +3655,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
if (BASE_SELECTABLE(v3d, base)) {
if ((base->object->runtime.select_id & 0x0000FFFF) != 0) {
- BLI_array_append(bases, base);
+ bases.append(base);
}
}
}
@@ -3644,13 +3667,14 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
buf_iter++) {
bPoseChannel *pchan_dummy;
Base *base = ED_armature_base_and_pchan_from_select_buffer(
- bases, BLI_array_len(bases), buf_iter->id, &pchan_dummy);
- if (base != NULL) {
+ bases.data(), bases.size(), buf_iter->id, &pchan_dummy);
+ if (base != nullptr) {
base->object->id.tag |= LIB_TAG_DOIT;
}
}
- for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
+ for (Base *base = static_cast<Base *>(vc->view_layer->object_bases.first); base && hits;
+ base = base->next) {
if (BASE_SELECTABLE(v3d, base)) {
const bool is_select = base->flag & BASE_SELECTED;
const bool is_inside = base->object->id.tag & LIB_TAG_DOIT;
@@ -3663,9 +3687,6 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
}
finally:
- if (bases != NULL) {
- MEM_freeN(bases);
- }
MEM_freeN(buffer);
@@ -3678,14 +3699,13 @@ finally:
static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
- uint bases_len;
- Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
+ blender::Vector<Base *> bases = do_pose_tag_select_op_prepare(vc);
int totobj = MAXPICKELEMS; /* XXX solve later */
/* Selection buffer has bones potentially too, so add #MAXPICKELEMS. */
- GPUSelectResult *buffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult),
- "selection buffer");
+ GPUSelectResult *buffer = static_cast<GPUSelectResult *>(
+ MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__));
const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene,
vc->obact);
const int hits = view3d_opengl_select(
@@ -3709,16 +3729,16 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e
buf_iter++) {
Bone *bone;
Base *base = ED_armature_base_and_bone_from_select_buffer(
- bases, bases_len, buf_iter->id, &bone);
+ bases.data(), bases.size(), buf_iter->id, &bone);
- if (base == NULL) {
+ if (base == nullptr) {
continue;
}
/* Loop over contiguous bone hits for 'base'. */
for (; buf_iter != buf_end; buf_iter++) {
/* should never fail */
- if (bone != NULL) {
+ if (bone != nullptr) {
base->object->id.tag |= LIB_TAG_DOIT;
bone->flag |= BONE_DONE;
}
@@ -3729,28 +3749,26 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e
if ((base->object->runtime.select_id & 0x0000FFFF) != (col_next->id & 0x0000FFFF)) {
break;
}
- if (base->object->pose != NULL) {
+ if (base->object->pose != nullptr) {
const uint hit_bone = (col_next->id & ~BONESEL_ANY) >> 16;
- bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
- bone = pchan ? pchan->bone : NULL;
+ bPoseChannel *pchan = static_cast<bPoseChannel *>(
+ BLI_findlink(&base->object->pose->chanbase, hit_bone));
+ bone = pchan ? pchan->bone : nullptr;
}
else {
- bone = NULL;
+ bone = nullptr;
}
}
}
}
}
- const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
+ const bool changed_multi = do_pose_tag_select_op_exec(bases, sel_op);
if (changed_multi) {
DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
}
- if (bases != NULL) {
- MEM_freeN(bases);
- }
MEM_freeN(buffer);
return changed_multi;
@@ -3763,7 +3781,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
rcti rect;
bool changed_multi = false;
- wmGenericUserData wm_userdata_buf = {0};
+ wmGenericUserData wm_userdata_buf = {nullptr, nullptr, false};
wmGenericUserData *wm_userdata = &wm_userdata_buf;
view3d_operator_needs_opengl(C);
@@ -3772,7 +3790,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ eSelectOp sel_op = static_cast<eSelectOp>(RNA_enum_get(op->ptr, "mode"));
WM_operator_properties_border_to_rcti(op, &rect);
if (vc.obedit) {
@@ -3786,7 +3804,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
vc.em = BKE_editmesh_from_object(vc.obedit);
changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op);
if (changed) {
- DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
@@ -3794,14 +3812,14 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
case OB_SURF:
changed = do_nurbs_box_select(&vc, &rect, sel_op);
if (changed) {
- DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
case OB_MBALL:
changed = do_meta_box_select(&vc, &rect, sel_op);
if (changed) {
- DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
@@ -3816,7 +3834,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
case OB_LATTICE:
changed = do_lattice_box_select(&vc, &rect, sel_op);
if (changed) {
- DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
}
break;
@@ -3888,7 +3906,7 @@ void VIEW3D_OT_select_box(wmOperatorType *ot)
/** \name Circle Select
* \{ */
-typedef struct CircleSelectUserData {
+struct CircleSelectUserData {
ViewContext *vc;
bool select;
int mval[2];
@@ -3899,7 +3917,7 @@ typedef struct CircleSelectUserData {
/* runtime */
bool is_changed;
-} CircleSelectUserData;
+};
static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
ViewContext *vc,
@@ -3917,7 +3935,7 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
r_data->radius_squared = rad * rad;
/* SELECT by default, but can be changed if needed (only few cases use and respect this). */
- r_data->select_flag = SELECT;
+ r_data->select_flag = (eBezTriple_Flag)SELECT;
/* runtime */
r_data->is_changed = false;
@@ -3928,7 +3946,7 @@ static void mesh_circle_doSelectVert(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
BM_vert_select_set(data->vc->em->bm, eve, data->select);
@@ -3941,7 +3959,7 @@ static void mesh_circle_doSelectEdge(void *userData,
const float screen_co_b[2],
int UNUSED(index))
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
BM_edge_select_set(data->vc->em->bm, eed, data->select);
@@ -3953,7 +3971,7 @@ static void mesh_circle_doSelectFace(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
BM_face_select_set(data->vc->em->bm, efa, data->select);
@@ -3990,22 +4008,22 @@ static bool mesh_circle_select(ViewContext *vc,
const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
if (use_zbuf) {
- if (wm_userdata->data == NULL) {
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
}
}
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
if (use_zbuf) {
- if (esel->select_bitmap == NULL) {
+ if (esel->select_bitmap == nullptr) {
esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(
- vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
+ vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), nullptr);
}
}
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
- if (esel->select_bitmap != NULL) {
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_verts(
esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
@@ -4017,7 +4035,7 @@ static bool mesh_circle_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_EDGE) {
if (use_zbuf) {
- if (esel->select_bitmap != NULL) {
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_edges(
esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
@@ -4033,7 +4051,7 @@ static bool mesh_circle_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
- if (esel->select_bitmap != NULL) {
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_faces(
esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
@@ -4060,7 +4078,7 @@ static bool paint_facesel_circle_select(ViewContext *vc,
{
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
Object *ob = vc->obact;
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
bool changed = false;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -4068,23 +4086,23 @@ static bool paint_facesel_circle_select(ViewContext *vc,
changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
}
- if (wm_userdata->data == NULL) {
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
}
{
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(
- vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
- if (esel->select_bitmap != NULL) {
+ vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), nullptr);
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
MEM_freeN(esel->select_bitmap);
- esel->select_bitmap = NULL;
+ esel->select_bitmap = nullptr;
}
}
if (changed) {
- paintface_flush_flags(vc->C, ob, SELECT);
+ paintface_flush_flags(vc->C, ob, true, false);
}
return changed;
}
@@ -4094,7 +4112,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData,
const float screen_co[2],
int UNUSED(index))
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
@@ -4110,8 +4128,8 @@ static bool paint_vertsel_circle_select(ViewContext *vc,
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
Object *ob = vc->obact;
- Mesh *me = ob->data;
- /* CircleSelectUserData data = {NULL}; */ /* UNUSED */
+ Mesh *me = static_cast<Mesh *>(ob->data);
+ /* CircleSelectUserData data = {nullptr}; */ /* UNUSED */
bool changed = false;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -4122,19 +4140,19 @@ static bool paint_vertsel_circle_select(ViewContext *vc,
const bool select = (sel_op != SEL_OP_SUB);
if (use_zbuf) {
- if (wm_userdata->data == NULL) {
+ if (wm_userdata->data == nullptr) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
}
}
if (use_zbuf) {
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(
- vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
- if (esel->select_bitmap != NULL) {
+ vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), nullptr);
+ if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
MEM_freeN(esel->select_bitmap);
- esel->select_bitmap = NULL;
+ esel->select_bitmap = nullptr;
}
}
else {
@@ -4166,7 +4184,7 @@ static void nurbscurve_circle_doSelect(void *userData,
bool UNUSED(handles_visible),
const float screen_co[2])
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (bp) {
@@ -4214,14 +4232,14 @@ static bool nurbscurve_circle_select(ViewContext *vc,
data.is_changed |= BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
}
- BKE_curve_nurb_vert_active_validate(vc->obedit->data);
+ BKE_curve_nurb_vert_active_validate(static_cast<Curve *>(vc->obedit->data));
return data.is_changed;
}
static void latticecurve_circle_doSelect(void *userData, BPoint *bp, const float screen_co[2])
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
@@ -4255,7 +4273,7 @@ static bool pchan_circle_doSelectJoint(void *userData,
bPoseChannel *pchan,
const float screen_co[2])
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (data->select) {
@@ -4264,17 +4282,17 @@ static bool pchan_circle_doSelectJoint(void *userData,
else {
pchan->bone->flag &= ~BONE_SELECTED;
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static void do_circle_select_pose__doSelectBone(void *userData,
- struct bPoseChannel *pchan,
+ bPoseChannel *pchan,
const float screen_co_a[2],
const float screen_co_b[2])
{
- CircleSelectUserData *data = userData;
- bArmature *arm = data->vc->obact->data;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
+ bArmature *arm = static_cast<bArmature *>(data->vc->obact->data);
if (!PBONE_SELECTABLE(arm, pchan->bone)) {
return;
}
@@ -4355,7 +4373,7 @@ static bool armature_circle_doSelectJoint(void *userData,
const float screen_co[2],
bool head)
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (head) {
@@ -4374,17 +4392,17 @@ static bool armature_circle_doSelectJoint(void *userData,
ebone->flag &= ~BONE_TIPSEL;
}
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static void do_circle_select_armature__doSelectBone(void *userData,
- struct EditBone *ebone,
+ EditBone *ebone,
const float screen_co_a[2],
const float screen_co_b[2])
{
- CircleSelectUserData *data = userData;
- const bArmature *arm = data->vc->obedit->data;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
+ const bArmature *arm = static_cast<const bArmature *>(data->vc->obedit->data);
if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) {
return;
}
@@ -4433,19 +4451,19 @@ static void do_circle_select_armature__doSelectBone(void *userData,
data->is_changed |= is_point_done;
}
static void do_circle_select_armature__doSelectBone_clip_content(void *userData,
- struct EditBone *ebone,
+ EditBone *ebone,
const float screen_co_a[2],
const float screen_co_b[2])
{
- CircleSelectUserData *data = userData;
- bArmature *arm = data->vc->obedit->data;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
+ bArmature *arm = static_cast<bArmature *>(data->vc->obedit->data);
if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) {
return;
}
/* Set in the first pass, needed so circle select prioritizes joints. */
- if (ebone->temp.i == true) {
+ if (ebone->temp.i != 0) {
return;
}
@@ -4460,7 +4478,7 @@ static bool armature_circle_select(ViewContext *vc,
float rad)
{
CircleSelectUserData data;
- bArmature *arm = vc->obedit->data;
+ bArmature *arm = static_cast<bArmature *>(vc->obedit->data);
const bool select = (sel_op != SEL_OP_SUB);
@@ -4493,10 +4511,10 @@ static bool armature_circle_select(ViewContext *vc,
}
static void do_circle_select_mball__doSelectElem(void *userData,
- struct MetaElem *ml,
+ MetaElem *ml,
const float screen_co[2])
{
- CircleSelectUserData *data = userData;
+ CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (data->select) {
@@ -4520,7 +4538,7 @@ static bool mball_circle_select(ViewContext *vc,
view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- data.is_changed |= BKE_mball_deselect_all(vc->obedit->data);
+ data.is_changed |= BKE_mball_deselect_all(static_cast<MetaBall *>(vc->obedit->data));
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
@@ -4568,7 +4586,7 @@ static bool obedit_circle_select(bContext *C,
}
if (changed) {
- DEG_id_tag_update(vc->obact->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(vc->obact->data), ID_RECALC_SELECT);
WM_main_add_notifier(NC_GEOM | ND_SELECT, vc->obact->data);
}
return changed;
@@ -4584,7 +4602,7 @@ static bool object_circle_select(ViewContext *vc,
View3D *v3d = vc->v3d;
const float radius_squared = rad * rad;
- const float mval_fl[2] = {mval[0], mval[1]};
+ const float mval_fl[2] = {static_cast<float>(mval[0]), static_cast<float>(mval[1])};
bool changed = false;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -4593,8 +4611,7 @@ static bool object_circle_select(ViewContext *vc,
const bool select = (sel_op != SEL_OP_SUB);
const int select_flag = select ? BASE_SELECTED : 0;
- Base *base;
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) {
float screen_co[2];
if (ED_view3d_project_float_global(
@@ -4614,7 +4631,7 @@ static bool object_circle_select(ViewContext *vc,
/* not a real operator, only for circle test */
static void view3d_circle_select_recalc(void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
@@ -4662,12 +4679,12 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
/* Allow each selection type to allocate their own data that's used between executions. */
- wmGesture *gesture = op->customdata; /* NULL when non-modal. */
- wmGenericUserData wm_userdata_buf = {0};
+ wmGesture *gesture = static_cast<wmGesture *>(op->customdata); /* nullptr when non-modal. */
+ wmGenericUserData wm_userdata_buf = {nullptr, nullptr, false};
wmGenericUserData *wm_userdata = gesture ? &gesture->user_data : &wm_userdata_buf;
- const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
- WM_gesture_is_modal_first(gesture));
+ const eSelectOp sel_op = ED_select_op_modal(
+ static_cast<eSelectOp>(RNA_enum_get(op->ptr, "mode")), WM_gesture_is_modal_first(gesture));
ED_view3d_viewcontext_init(C, &vc, depsgraph);
@@ -4676,7 +4693,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & OB_MODE_POSE))) {
view3d_operator_needs_opengl(C);
- if (obedit == NULL) {
+ if (obedit == nullptr) {
BKE_object_update_select_id(CTX_data_main(C));
}
@@ -4728,10 +4745,10 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
WM_generic_user_data_free(wm_userdata);
}
else {
- struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data);
if (esel && esel->select_bitmap) {
MEM_freeN(esel->select_bitmap);
- esel->select_bitmap = NULL;
+ esel->select_bitmap = nullptr;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 306394ce53d..cb716391fb2 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -44,6 +44,7 @@
#include "ED_keyframing.h"
#include "ED_screen.h"
+#include "ED_undo.h"
#include "ED_view3d.h"
#include "UI_resources.h"
@@ -633,7 +634,7 @@ bool ED_view3d_camera_autokey(const Scene *scene,
const bool do_translate)
{
if (autokeyframe_cfra_can_key(scene, id_key)) {
- const float cfra = (float)CFRA;
+ const float cfra = (float)scene->r.cfra;
ListBase dsources = {NULL, NULL};
/* add data-source override for the camera object */
@@ -688,6 +689,60 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d,
return false;
}
+bool ED_view3d_camera_lock_undo_test(const View3D *v3d,
+ const RegionView3D *rv3d,
+ struct bContext *C)
+{
+ if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+ if (ED_undo_is_memfile_compatible(C)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Create a MEMFILE undo-step for locked camera movement when transforming the view.
+ * Edit and texture paint mode don't use MEMFILE undo so undo push is skipped for them.
+ * NDOF and track-pad navigation would create an undo step on every gesture and we may end up with
+ * unnecessary undo steps so undo push for them is not supported for now.
+ * Operators that use smooth view for navigation are supported via an optional parameter field,
+ * see: #V3D_SmoothParams.undo_str.
+ */
+static bool view3d_camera_lock_undo_ex(const char *str,
+ const View3D *v3d,
+ const RegionView3D *rv3d,
+ struct bContext *C,
+ const bool undo_group)
+{
+ if (ED_view3d_camera_lock_undo_test(v3d, rv3d, C)) {
+ if (undo_group) {
+ ED_undo_grouped_push(C, str);
+ }
+ else {
+ ED_undo_push(C, str);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ED_view3d_camera_lock_undo_push(const char *str,
+ const View3D *v3d,
+ const RegionView3D *rv3d,
+ bContext *C)
+{
+ return view3d_camera_lock_undo_ex(str, v3d, rv3d, C, false);
+}
+
+bool ED_view3d_camera_lock_undo_grouped_push(const char *str,
+ const View3D *v3d,
+ const RegionView3D *rv3d,
+ bContext *C)
+{
+ return view3d_camera_lock_undo_ex(str, v3d, rv3d, C, true);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1492,10 +1547,12 @@ static bool view3d_camera_to_view_selected_impl(struct Main *bmain,
depsgraph, scene, camera_ob_eval, co, &scale, r_clip_start, r_clip_end)) {
ObjectTfmProtectedChannels obtfm;
float obmat_new[4][4];
+ bool is_ortho_camera = false;
if ((camera_ob_eval->type == OB_CAMERA) &&
(((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) {
((Camera *)camera_ob->data)->ortho_scale = scale;
+ is_ortho_camera = true;
}
copy_m4_m4(obmat_new, camera_ob_eval->obmat);
@@ -1508,6 +1565,9 @@ static bool view3d_camera_to_view_selected_impl(struct Main *bmain,
/* notifiers */
DEG_id_tag_update_ex(bmain, &camera_ob->id, ID_RECALC_TRANSFORM);
+ if (is_ortho_camera) {
+ DEG_id_tag_update_ex(bmain, camera_ob->data, ID_RECALC_PARAMETERS);
+ }
return true;
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index fc88737ca70..124527822a5 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -202,6 +202,8 @@ static void sync_viewport_camera_smoothview(bContext *C,
.quat = other_rv3d->viewquat,
.dist = &other_rv3d->dist,
.lens = &other_v3d->lens,
+ /* No undo because this switches cameras. */
+ .undo_str = NULL,
});
}
else {
@@ -256,6 +258,8 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
.quat = rv3d->viewquat,
.dist = &rv3d->dist,
.lens = &v3d->lens,
+ /* No undo because this switches cameras. */
+ .undo_str = NULL,
});
}
@@ -549,7 +553,7 @@ int view3d_opengl_select_ex(ViewContext *vc,
ARegion *region = vc->region;
rcti rect;
int hits = 0;
- const bool use_obedit_skip = (OBEDIT_FROM_VIEW_LAYER(vc->view_layer) != NULL) &&
+ const bool use_obedit_skip = (BKE_view_layer_edit_object_get(vc->view_layer) != NULL) &&
(vc->obedit == NULL);
const bool is_pick_select = (U.gpu_flag & USER_GPU_FLAG_NO_DEPT_PICK) == 0;
const bool do_passes = ((is_pick_select == false) &&
@@ -597,7 +601,7 @@ int view3d_opengl_select_ex(ViewContext *vc,
goto finally;
}
- /* Important to use 'vc->obact', not 'OBACT(vc->view_layer)' below,
+ /* Important to use 'vc->obact', not 'BKE_view_layer_active_object_get(vc->view_layer)' below,
* so it will be NULL when hidden. */
struct {
DRW_ObjectFilterFn fn;
@@ -827,7 +831,6 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
ReportList *reports)
{
View3D *v3d = area->spacedata.first;
- Base *base;
float min[3], max[3], box[3];
float size = 0.0f;
uint local_view_bit;
@@ -848,9 +851,9 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
ok = false;
}
else {
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ Object *obedit = BKE_view_layer_edit_object_get(view_layer);
if (obedit) {
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->local_view_bits &= ~local_view_bit;
}
FOREACH_BASE_IN_EDIT_MODE_BEGIN (view_layer, v3d, base_iter) {
@@ -861,7 +864,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
FOREACH_BASE_IN_EDIT_MODE_END;
}
else {
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED(v3d, base)) {
BKE_object_minmax(base->object, min, max, false);
base->local_view_bits |= local_view_bit;
@@ -939,6 +942,8 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
.quat = rv3d->viewquat,
.dist = ok_dist ? &dist_new : NULL,
.lens = &v3d->lens,
+ /* No undo because this doesn't move the camera. */
+ .undo_str = NULL,
});
}
}
@@ -961,7 +966,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
return;
}
- for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->local_view_bits & v3d->local_view_uuid) {
base->local_view_bits &= ~v3d->local_view_uuid;
}
@@ -1008,6 +1013,8 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
.ofs = rv3d->localvd->ofs,
.quat = rv3d->localvd->viewquat,
.dist = &rv3d->localvd->dist,
+ /* No undo because this doesn't move the camera. */
+ .undo_str = NULL,
});
}
@@ -1086,12 +1093,12 @@ static int localview_remove_from_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
bool changed = false;
- for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED(v3d, base)) {
base->local_view_bits &= ~v3d->local_view_uuid;
ED_object_base_select(base, BA_DESELECT);
- if (base == BASACT(view_layer)) {
+ if (base == view_layer->basact) {
view_layer->basact = NULL;
}
changed = true;
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 68c4f4e76ca..ec6f62e0f5b 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -15,7 +15,6 @@ set(INC
../../render
../../sequencer
../../windowmanager
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -39,6 +38,7 @@ set(SRC
transform_convert_mesh_edge.c
transform_convert_mesh_skin.c
transform_convert_mesh_uv.c
+ transform_convert_mesh_vert_cdata.c
transform_convert_nla.c
transform_convert_node.c
transform_convert_object.c
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 960d9a25ca7..49258d63611 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -19,6 +19,7 @@
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_mask.h"
#include "BKE_scene.h"
@@ -484,7 +485,8 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
/* XXX how to deal with lock? */
SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
if (sima->lock) {
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
+ WM_event_add_notifier(
+ C, NC_GEOM | ND_DATA, BKE_view_layer_edit_object_get(t->view_layer)->data);
}
else {
ED_area_tag_redraw(t->area);
@@ -525,7 +527,8 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
UVCALC_TRANSFORM_CORRECT_SLIDE :
UVCALC_TRANSFORM_CORRECT;
- if ((t->data_type == TC_MESH_VERTS) && (t->settings->uvcalc_flag & uvcalc_correct_flag)) {
+ if ((t->data_type == &TransConvertType_Mesh) &&
+ (t->settings->uvcalc_flag & uvcalc_correct_flag)) {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
@@ -847,7 +850,7 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
return false;
}
- if (t->data_type == TC_SEQ_IMAGE_DATA) {
+ if (t->data_type == &TransConvertType_SequencerImage) {
/* Setup the 2d msg string so it writes out the transform space. */
msg_2d = msg_3d;
@@ -1327,7 +1330,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
- if (t->redraw && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (t->redraw && !ISMOUSE_MOTION(event->type)) {
WM_window_status_area_tag_redraw(CTX_wm_window(t->context));
}
@@ -1475,7 +1478,7 @@ static void drawTransformPixel(const struct bContext *C, ARegion *region, void *
if (region == t->region) {
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
/* draw auto-key-framing hint in the corner
* - only draw if enabled (advanced users may be distracted/annoyed),
@@ -1535,7 +1538,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if (!(t->options & CTX_NO_PET)) {
if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) &&
!RNA_property_is_set(op->ptr, prop)) {
- const Object *obact = OBACT(t->view_layer);
+ const Object *obact = BKE_view_layer_active_object_get(t->view_layer);
if (t->spacetype == SPACE_GRAPH) {
ts->proportional_fcurve = use_prop_edit;
@@ -1577,7 +1580,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if (transformModeUseSnap(t)) {
if (!(t->modifiers & MOD_SNAP) != !(t->tsnap.flag & SCE_SNAP)) {
/* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */
- char *snap_flag_ptr;
+ short *snap_flag_ptr;
wmMsgParams_RNA msg_key_params = {{0}};
RNA_pointer_create(&t->scene->id, &RNA_ToolSettings, ts, &msg_key_params.ptr);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a35942aedec..09fc07f57f4 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -38,6 +38,7 @@ struct ReportList;
struct Scene;
struct ScrArea;
struct SnapObjectContext;
+struct TransConvertTypeInfo;
struct TransDataContainer;
struct TransInfo;
struct TransSnap;
@@ -204,36 +205,6 @@ typedef enum {
HLP_TRACKBALL = 6,
} eTHelpline;
-typedef enum {
- TC_NONE = 0,
- TC_ACTION_DATA,
- TC_POSE,
- TC_ARMATURE_VERTS,
- TC_CURSOR_IMAGE,
- TC_CURSOR_SEQUENCER,
- TC_CURSOR_VIEW3D,
- TC_CURVE_VERTS,
- TC_GRAPH_EDIT_DATA,
- TC_GPENCIL,
- TC_LATTICE_VERTS,
- TC_MASKING_DATA,
- TC_MBALL_VERTS,
- TC_MESH_VERTS,
- TC_MESH_EDGES,
- TC_MESH_SKIN,
- TC_MESH_UV,
- TC_NLA_DATA,
- TC_NODE_DATA,
- TC_OBJECT,
- TC_OBJECT_TEXSPACE,
- TC_PAINT_CURVE_VERTS,
- TC_PARTICLE_VERTS,
- TC_SCULPT,
- TC_SEQ_DATA,
- TC_SEQ_IMAGE_DATA,
- TC_TRACKING_DATA,
-} eTConvertType;
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -306,9 +277,9 @@ typedef struct TransSnap {
eSnapTargetSelect target_select;
bool align;
bool project;
- bool snap_self;
bool peel;
bool use_backface_culling;
+ short face_nearest_steps;
eTSnap status;
/* Snapped Element Type (currently for objects only). */
eSnapMode snapElem;
@@ -384,10 +355,12 @@ typedef struct MouseInput {
/** Initial mouse position. */
int imval[2];
- bool precision;
- float precision_factor;
+ float imval_unproj[3];
float center[2];
float factor;
+ float precision_factor;
+ bool precision;
+
/** Additional data, if needed by the particular function. */
void *data;
@@ -463,6 +436,8 @@ typedef struct TransDataContainer {
int data_len;
/** Total number of transformed data_mirror. */
int data_mirror_len;
+ /** Total number of transformed gp-frames. */
+ int data_gpf_len;
struct Object *obedit;
@@ -516,7 +491,7 @@ typedef struct TransInfo {
int data_len_all;
/** TODO: It should be a member of #TransDataContainer. */
- eTConvertType data_type;
+ struct TransConvertTypeInfo *data_type;
/** Current context/options for transform. */
eTContext options;
@@ -645,6 +620,9 @@ typedef struct TransInfo {
* value of the input parameter, except when a constrain is entered. */
float values_final[4];
+ /** Cache safe value for constraints that require iteration or are slow to calculate. */
+ float values_inside_constraints[4];
+
/* Axis members for modes that use an axis separate from the orientation (rotate & shear). */
/** Primary axis, rotate only uses this. */
@@ -683,6 +661,9 @@ typedef struct TransInfo {
/** Typically for mode settings. */
TransCustomDataContainer custom;
+
+ /* Needed for sculpt transform. */
+ const char *undo_name;
} TransInfo;
/** \} */
@@ -782,6 +763,7 @@ void applyMouseInput(struct TransInfo *t,
struct MouseInput *mi,
const int mval[2],
float output[3]);
+void transform_input_update(TransInfo *t, const float fac);
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]);
void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]);
@@ -830,6 +812,7 @@ void calculateCenter2D(TransInfo *t);
void calculateCenterLocal(TransInfo *t, const float center_global[3]);
void calculateCenter(TransInfo *t);
+void tranformViewUpdate(TransInfo *t);
/* API functions for getting center points */
void calculateCenterBound(TransInfo *t, float r_center[3]);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 0bb00032561..2e12611a7c9 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -177,7 +177,7 @@ static void axisProjection(const TransInfo *t,
const float in[3],
float out[3])
{
- float norm[3], vec[3], factor, angle;
+ float vec[3], factor, angle;
float t_con_center[3];
if (is_zero_v3(in)) {
@@ -214,7 +214,7 @@ static void axisProjection(const TransInfo *t,
}
else {
float v[3];
- float norm_center[3];
+ float norm[3], norm_center[3];
float plane[3];
view_vector_calc(t, t_con_center, norm_center);
@@ -402,7 +402,7 @@ static void applyAxisConstraintVec(const TransInfo *t,
if (activeSnap(t)) {
if (validSnap(t)) {
is_snap_to_edge = (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) != 0;
- is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE) != 0;
+ is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE_RAYCAST) != 0;
is_snap_to_point = !is_snap_to_edge && !is_snap_to_face;
}
else if (t->tsnap.snapElem & SCE_SNAP_MODE_GRID) {
@@ -701,12 +701,12 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
}
}
-void setUserConstraint(TransInfo *t, int mode, const char ftext[])
+void setUserConstraint(TransInfo *t, int mode, const char text_[])
{
char text[256];
const short orientation = transform_orientation_or_default(t);
const char *spacename = transform_orientations_spacename_get(t, orientation);
- BLI_snprintf(text, sizeof(text), ftext, spacename);
+ BLI_snprintf(text, sizeof(text), text_, spacename);
switch (orientation) {
case V3D_ORIENT_LOCAL:
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 9182330b729..90a693b089e 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -34,7 +34,7 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]);
* `ftext` is a format string passed to #BLI_snprintf. It will add the name of
* the orientation where %s is (logically).
*/
-void setUserConstraint(TransInfo *t, int mode, const char text[]);
+void setUserConstraint(TransInfo *t, int mode, const char text_[]);
void drawConstraint(TransInfo *t);
/**
* Called from drawview.c, as an extra per-window draw option.
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 267a519ebee..7a85cb86609 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -479,132 +479,6 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr
/** \name UV Coordinates
* \{ */
-/**
- * Find the correction for the scaling factor when "Constrain to Bounds" is active.
- * \param numerator: How far the UV boundary (unit square) is from the origin of the scale.
- * \param denominator: How far the AABB is from the origin of the scale.
- * \param scale: Scale parameter to update.
- */
-static void constrain_scale_to_boundary(const float numerator,
- const float denominator,
- float *scale)
-{
- if (denominator == 0.0f) {
- /* The origin of the scale is on the edge of the boundary. */
- if (numerator < 0.0f) {
- /* Negative scale will wrap around and put us outside the boundary. */
- *scale = 0.0f; /* Hold at the boundary instead. */
- }
- return; /* Nothing else we can do without more info. */
- }
-
- const float correction = numerator / denominator;
- if (correction < 0.0f || !isfinite(correction)) {
- /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */
- return;
- }
-
- if (denominator < 0.0f) {
- /* Scale origin is outside boundary, only make scale bigger. */
- if (*scale < correction) {
- *scale = correction;
- }
- return;
- }
-
- /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */
- if (*scale > correction) {
- *scale = correction;
- }
-}
-
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
-{
- bool clipx = true, clipy = true;
- float min[2], max[2];
-
- /* Check if the current image in UV editor is a tiled image or not. */
- const SpaceImage *sima = t->area->spacedata.first;
- const Image *image = sima->image;
- const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
- /* Stores the coordinates of the closest UDIM tile.
- * Also acts as an offset to the tile from the origin of UV space. */
- float base_offset[2] = {0.0f, 0.0f};
-
- /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
- if (is_tiled_image) {
- int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global);
- if (nearest_tile_index != -1) {
- nearest_tile_index -= 1001;
- /* Getting coordinates of nearest tile from the tile index. */
- base_offset[0] = nearest_tile_index % 10;
- base_offset[1] = nearest_tile_index / 10;
- }
- }
-
- min[0] = min[1] = FLT_MAX;
- max[0] = max[1] = FLT_MIN;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td;
- int a;
-
- for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
- minmax_v2v2_v2(min, max, td->loc);
- }
- }
-
- if (resize) {
- /* Assume no change is required. */
- float scalex = 1.0f;
- float scaley = 1.0f;
-
- /* Update U against the left border. */
- constrain_scale_to_boundary(
- t->center_global[0] - base_offset[0], t->center_global[0] - min[0], &scalex);
- /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */
- constrain_scale_to_boundary(base_offset[0] + t->aspect[0] - t->center_global[0],
- max[0] - t->center_global[0],
- &scalex);
-
- /* Do the same for the V co-ordinate, which is called `y`. */
- constrain_scale_to_boundary(
- t->center_global[1] - base_offset[1], t->center_global[1] - min[1], &scaley);
- constrain_scale_to_boundary(base_offset[1] + t->aspect[1] - t->center_global[1],
- max[1] - t->center_global[1],
- &scaley);
-
- clipx = (scalex != 1.0f);
- clipy = (scaley != 1.0f);
- vec[0] *= scalex;
- vec[1] *= scaley;
- }
- else {
- if (min[0] < base_offset[0]) {
- vec[0] += base_offset[0] - min[0];
- }
- else if (max[0] > base_offset[0] + t->aspect[0]) {
- vec[0] -= max[0] - base_offset[0] - t->aspect[0];
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < base_offset[1]) {
- vec[1] += base_offset[1] - min[1];
- }
- else if (max[1] > base_offset[1] + t->aspect[1]) {
- vec[1] -= max[1] - base_offset[1] - t->aspect[1];
- }
- else {
- clipy = 0;
- }
- }
-
- return (clipx || clipy);
-}
-
void clipUVData(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -769,7 +643,7 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
}
else {
/* Delete Keyframe */
- delete_fcurve_key(fcu, i, 0);
+ BKE_fcurve_delete_key(fcu, i);
}
/* Update count of how many we've deleted
@@ -779,7 +653,7 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
}
else {
/* Always delete - Unselected keys don't matter */
- delete_fcurve_key(fcu, i, 0);
+ BKE_fcurve_delete_key(fcu, i);
}
/* Stop the RK search... we've found our match now */
@@ -902,62 +776,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
return;
}
- BLI_assert(CTX_data_main(t->context) == CTX_data_main(C));
- switch (t->data_type) {
- case TC_ACTION_DATA:
- special_aftertrans_update__actedit(C, t);
- break;
- case TC_POSE:
- special_aftertrans_update__pose(C, t);
- break;
- case TC_GRAPH_EDIT_DATA:
- special_aftertrans_update__graph(C, t);
- break;
- case TC_MASKING_DATA:
- special_aftertrans_update__mask(C, t);
- break;
- case TC_MESH_VERTS:
- case TC_MESH_EDGES:
- special_aftertrans_update__mesh(C, t);
- break;
- case TC_NLA_DATA:
- special_aftertrans_update__nla(C, t);
- break;
- case TC_NODE_DATA:
- special_aftertrans_update__node(C, t);
- break;
- case TC_OBJECT:
- special_aftertrans_update__object(C, t);
- break;
- case TC_SCULPT:
- special_aftertrans_update__sculpt(C, t);
- break;
- case TC_SEQ_DATA:
- special_aftertrans_update__sequencer(C, t);
- break;
- case TC_SEQ_IMAGE_DATA:
- special_aftertrans_update__sequencer_image(C, t);
- break;
- case TC_TRACKING_DATA:
- special_aftertrans_update__movieclip(C, t);
- break;
- case TC_ARMATURE_VERTS:
- case TC_CURSOR_IMAGE:
- case TC_CURSOR_SEQUENCER:
- case TC_CURSOR_VIEW3D:
- case TC_CURVE_VERTS:
- case TC_GPENCIL:
- case TC_LATTICE_VERTS:
- case TC_MBALL_VERTS:
- case TC_MESH_UV:
- case TC_MESH_SKIN:
- case TC_OBJECT_TEXSPACE:
- case TC_PAINT_CURVE_VERTS:
- case TC_PARTICLE_VERTS:
- case TC_NONE:
- default:
- break;
+ if (!t->data_type || !t->data_type->special_aftertrans_update) {
+ return;
}
+
+ BLI_assert(CTX_data_main(t->context) == CTX_data_main(C));
+ t->data_type->special_aftertrans_update(C, t);
}
int special_transform_moving(TransInfo *t)
@@ -1018,54 +842,44 @@ static int countAndCleanTransDataContainer(TransInfo *t)
static void init_proportional_edit(TransInfo *t)
{
- eTConvertType convert_type = t->data_type;
- switch (convert_type) {
- case TC_ACTION_DATA:
- case TC_CURVE_VERTS:
- case TC_GRAPH_EDIT_DATA:
- case TC_GPENCIL:
- case TC_LATTICE_VERTS:
- case TC_MASKING_DATA:
- case TC_MBALL_VERTS:
- case TC_MESH_VERTS:
- case TC_MESH_EDGES:
- case TC_MESH_SKIN:
- case TC_MESH_UV:
- case TC_NODE_DATA:
- case TC_OBJECT:
- case TC_PARTICLE_VERTS:
- break;
- case TC_POSE: /* Disable PET, its not usable in pose mode yet T32444. */
- case TC_ARMATURE_VERTS:
- case TC_CURSOR_IMAGE:
- case TC_CURSOR_SEQUENCER:
- case TC_CURSOR_VIEW3D:
- case TC_NLA_DATA:
- case TC_OBJECT_TEXSPACE:
- case TC_PAINT_CURVE_VERTS:
- case TC_SCULPT:
- case TC_SEQ_DATA:
- case TC_SEQ_IMAGE_DATA:
- case TC_TRACKING_DATA:
- case TC_NONE:
- default:
- t->options |= CTX_NO_PET;
- t->flag &= ~T_PROP_EDIT_ALL;
- return;
+ /* NOTE: PET is not usable in pose mode yet T32444. */
+ if (!ELEM(t->data_type,
+ &TransConvertType_Action,
+ &TransConvertType_Curve,
+ &TransConvertType_Graph,
+ &TransConvertType_GPencil,
+ &TransConvertType_Lattice,
+ &TransConvertType_Mask,
+ &TransConvertType_MBall,
+ &TransConvertType_Mesh,
+ &TransConvertType_MeshEdge,
+ &TransConvertType_MeshSkin,
+ &TransConvertType_MeshUV,
+ &TransConvertType_MeshVertCData,
+ &TransConvertType_Node,
+ &TransConvertType_Object,
+ &TransConvertType_Particle)) {
+ /* Disable PET */
+ t->options |= CTX_NO_PET;
+ t->flag &= ~T_PROP_EDIT_ALL;
+ return;
}
if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- if (convert_type == TC_OBJECT) {
+ if (t->data_type == &TransConvertType_Object) {
/* Selected objects are already first, no need to presort. */
}
else {
sort_trans_data_selected_first(t);
}
- if (ELEM(convert_type, TC_ACTION_DATA, TC_GRAPH_EDIT_DATA)) {
+ if (ELEM(t->data_type, &TransConvertType_Action, &TransConvertType_Graph)) {
/* Distance has already been set. */
}
- else if (ELEM(convert_type, TC_MESH_VERTS, TC_MESH_SKIN)) {
+ else if (ELEM(t->data_type,
+ &TransConvertType_Mesh,
+ &TransConvertType_MeshSkin,
+ &TransConvertType_MeshVertCData)) {
if (t->flag & T_PROP_CONNECTED) {
/* Already calculated by transform_convert_mesh_connectivity_distance. */
}
@@ -1073,10 +887,10 @@ static void init_proportional_edit(TransInfo *t)
set_prop_dist(t, false);
}
}
- else if (convert_type == TC_MESH_UV && t->flag & T_PROP_CONNECTED) {
+ else if (t->data_type == &TransConvertType_MeshUV && t->flag & T_PROP_CONNECTED) {
/* Already calculated by uv_set_connectivity_distance. */
}
- else if (convert_type == TC_CURVE_VERTS) {
+ else if (t->data_type == &TransConvertType_Curve) {
BLI_assert(t->obedit_type == OB_CURVES_LEGACY);
set_prop_dist(t, false);
}
@@ -1099,44 +913,26 @@ static void init_TransDataContainers(TransInfo *t,
Object **objects,
uint objects_len)
{
- switch (t->data_type) {
- case TC_POSE:
- case TC_ARMATURE_VERTS:
- case TC_CURVE_VERTS:
- case TC_GPENCIL:
- case TC_LATTICE_VERTS:
- case TC_MBALL_VERTS:
- case TC_MESH_VERTS:
- case TC_MESH_EDGES:
- case TC_MESH_SKIN:
- case TC_MESH_UV:
- break;
- case TC_ACTION_DATA:
- case TC_GRAPH_EDIT_DATA:
- case TC_CURSOR_IMAGE:
- case TC_CURSOR_SEQUENCER:
- case TC_CURSOR_VIEW3D:
- case TC_MASKING_DATA:
- case TC_NLA_DATA:
- case TC_NODE_DATA:
- case TC_OBJECT:
- case TC_OBJECT_TEXSPACE:
- case TC_PAINT_CURVE_VERTS:
- case TC_PARTICLE_VERTS:
- case TC_SCULPT:
- case TC_SEQ_DATA:
- case TC_SEQ_IMAGE_DATA:
- case TC_TRACKING_DATA:
- case TC_NONE:
- default:
- /* Does not support Multi object editing. */
- return;
+ if (!ELEM(t->data_type,
+ &TransConvertType_Pose,
+ &TransConvertType_EditArmature,
+ &TransConvertType_Curve,
+ &TransConvertType_GPencil,
+ &TransConvertType_Lattice,
+ &TransConvertType_MBall,
+ &TransConvertType_Mesh,
+ &TransConvertType_MeshEdge,
+ &TransConvertType_MeshSkin,
+ &TransConvertType_MeshUV,
+ &TransConvertType_MeshVertCData)) {
+ /* Does not support Multi object editing. */
+ return;
}
const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
const short object_type = obact ? obact->type : -1;
- if ((object_mode & OB_MODE_EDIT) || (t->data_type == TC_GPENCIL) ||
+ if ((object_mode & OB_MODE_EDIT) || (t->data_type == &TransConvertType_GPencil) ||
((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE))) {
if (t->data_container) {
MEM_freeN(t->data_container);
@@ -1144,15 +940,12 @@ static void init_TransDataContainers(TransInfo *t,
bool free_objects = false;
if (objects == NULL) {
- objects = BKE_view_layer_array_from_objects_in_mode(
- t->view_layer,
- (t->spacetype == SPACE_VIEW3D) ? t->view : NULL,
- &objects_len,
- {
- .object_mode = object_mode,
- /* Pose transform operates on `ob->pose` so don't skip duplicate object-data. */
- .no_dup_data = (object_mode & OB_MODE_POSE) == 0,
- });
+ struct ObjectsInModeParams params = {0};
+ params.object_mode = object_mode;
+ /* Pose transform operates on `ob->pose` so don't skip duplicate object-data. */
+ params.no_dup_data = (object_mode & OB_MODE_POSE) == 0;
+ objects = BKE_view_layer_array_from_objects_in_mode_params(
+ t->view_layer, (t->spacetype == SPACE_VIEW3D) ? t->view : NULL, &objects_len, &params);
free_objects = true;
}
@@ -1178,7 +971,7 @@ static void init_TransDataContainers(TransInfo *t,
tc->poseobj = objects[i];
tc->use_local_mat = true;
}
- else if (t->data_type == TC_GPENCIL) {
+ else if (t->data_type == &TransConvertType_GPencil) {
tc->use_local_mat = true;
}
@@ -1201,173 +994,131 @@ static void init_TransDataContainers(TransInfo *t,
}
}
-static eTFlag flags_from_data_type(eTConvertType data_type)
-{
- switch (data_type) {
- case TC_ACTION_DATA:
- case TC_GRAPH_EDIT_DATA:
- case TC_MASKING_DATA:
- case TC_NLA_DATA:
- case TC_NODE_DATA:
- case TC_PAINT_CURVE_VERTS:
- case TC_SEQ_DATA:
- case TC_SEQ_IMAGE_DATA:
- case TC_TRACKING_DATA:
- return T_POINTS | T_2D_EDIT;
- case TC_ARMATURE_VERTS:
- case TC_CURVE_VERTS:
- case TC_GPENCIL:
- case TC_LATTICE_VERTS:
- case TC_MBALL_VERTS:
- case TC_MESH_VERTS:
- case TC_MESH_SKIN:
- return T_EDIT | T_POINTS;
- case TC_MESH_EDGES:
- return T_EDIT;
- case TC_MESH_UV:
- return T_EDIT | T_POINTS | T_2D_EDIT;
- case TC_CURSOR_IMAGE:
- case TC_CURSOR_SEQUENCER:
- return T_2D_EDIT;
- case TC_PARTICLE_VERTS:
- return T_POINTS;
- case TC_POSE:
- case TC_CURSOR_VIEW3D:
- case TC_OBJECT:
- case TC_OBJECT_TEXSPACE:
- case TC_SCULPT:
- case TC_NONE:
- default:
- break;
- }
- return 0;
-}
-
-static eTConvertType convert_type_get(const TransInfo *t, Object **r_obj_armature)
+static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj_armature)
{
ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
- eTConvertType convert_type = TC_NONE;
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
/* if tests must match recalcData for correct updates */
if (t->options & CTX_CURSOR) {
if (t->spacetype == SPACE_IMAGE) {
- convert_type = TC_CURSOR_IMAGE;
- }
- else if (t->spacetype == SPACE_SEQ) {
- convert_type = TC_CURSOR_SEQUENCER;
+ return &TransConvertType_CursorImage;
}
- else {
- convert_type = TC_CURSOR_VIEW3D;
+
+ if (t->spacetype == SPACE_SEQ) {
+ return &TransConvertType_CursorSequencer;
}
+
+ return &TransConvertType_Cursor3D;
}
- else if (!(t->options & CTX_PAINT_CURVE) && (t->spacetype == SPACE_VIEW3D) && ob &&
- (ob->mode == OB_MODE_SCULPT) && ob->sculpt) {
- convert_type = TC_SCULPT;
+ if (!(t->options & CTX_PAINT_CURVE) && (t->spacetype == SPACE_VIEW3D) && ob &&
+ (ob->mode == OB_MODE_SCULPT) && ob->sculpt) {
+ return &TransConvertType_Sculpt;
}
- else if (t->options & CTX_TEXTURE_SPACE) {
- convert_type = TC_OBJECT_TEXSPACE;
+ if (t->options & CTX_TEXTURE_SPACE) {
+ return &TransConvertType_ObjectTexSpace;
}
- else if (t->options & CTX_EDGE_DATA) {
- convert_type = TC_MESH_EDGES;
+ if (t->options & CTX_EDGE_DATA) {
+ return &TransConvertType_MeshEdge;
}
- else if (t->options & CTX_GPENCIL_STROKES) {
- convert_type = TC_GPENCIL;
+ if (t->options & CTX_GPENCIL_STROKES) {
+ return &TransConvertType_GPencil;
}
- else if (t->spacetype == SPACE_IMAGE) {
+ if (t->spacetype == SPACE_IMAGE) {
if (t->options & CTX_MASK) {
- convert_type = TC_MASKING_DATA;
+ return &TransConvertType_Mask;
}
- else if (t->options & CTX_PAINT_CURVE) {
+ if (t->options & CTX_PAINT_CURVE) {
if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- convert_type = TC_PAINT_CURVE_VERTS;
+ return &TransConvertType_PaintCurve;
}
}
else if (t->obedit_type == OB_MESH) {
- convert_type = TC_MESH_UV;
+ return &TransConvertType_MeshUV;
}
+ return NULL;
}
- else if (t->spacetype == SPACE_ACTION) {
- convert_type = TC_ACTION_DATA;
+ if (t->spacetype == SPACE_ACTION) {
+ return &TransConvertType_Action;
}
- else if (t->spacetype == SPACE_NLA) {
- convert_type = TC_NLA_DATA;
+ if (t->spacetype == SPACE_NLA) {
+ return &TransConvertType_NLA;
}
- else if (t->spacetype == SPACE_SEQ) {
+ if (t->spacetype == SPACE_SEQ) {
if (t->options & CTX_SEQUENCER_IMAGE) {
- convert_type = TC_SEQ_IMAGE_DATA;
- }
- else {
- convert_type = TC_SEQ_DATA;
+ return &TransConvertType_SequencerImage;
}
+ return &TransConvertType_Sequencer;
}
- else if (t->spacetype == SPACE_GRAPH) {
- convert_type = TC_GRAPH_EDIT_DATA;
+ if (t->spacetype == SPACE_GRAPH) {
+ return &TransConvertType_Graph;
}
- else if (t->spacetype == SPACE_NODE) {
- convert_type = TC_NODE_DATA;
+ if (t->spacetype == SPACE_NODE) {
+ return &TransConvertType_Node;
}
- else if (t->spacetype == SPACE_CLIP) {
+ if (t->spacetype == SPACE_CLIP) {
if (t->options & CTX_MOVIECLIP) {
- convert_type = TC_TRACKING_DATA;
+ return &TransConvertType_Tracking;
}
- else if (t->options & CTX_MASK) {
- convert_type = TC_MASKING_DATA;
+ if (t->options & CTX_MASK) {
+ return &TransConvertType_Mask;
}
+ return NULL;
}
- else if (t->obedit_type != -1) {
+ if (t->obedit_type != -1) {
if (t->obedit_type == OB_MESH) {
if (t->mode == TFM_SKIN_RESIZE) {
- convert_type = TC_MESH_SKIN;
+ return &TransConvertType_MeshSkin;
}
- else {
- convert_type = TC_MESH_VERTS;
+ if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) {
+ return &TransConvertType_MeshVertCData;
}
+ return &TransConvertType_Mesh;
}
- else if (ELEM(t->obedit_type, OB_CURVES_LEGACY, OB_SURF)) {
- convert_type = TC_CURVE_VERTS;
+ if (ELEM(t->obedit_type, OB_CURVES_LEGACY, OB_SURF)) {
+ return &TransConvertType_Curve;
}
- else if (t->obedit_type == OB_LATTICE) {
- convert_type = TC_LATTICE_VERTS;
+ if (t->obedit_type == OB_LATTICE) {
+ return &TransConvertType_Lattice;
}
- else if (t->obedit_type == OB_MBALL) {
- convert_type = TC_MBALL_VERTS;
+ if (t->obedit_type == OB_MBALL) {
+ return &TransConvertType_MBall;
}
- else if (t->obedit_type == OB_ARMATURE) {
- convert_type = TC_ARMATURE_VERTS;
+ if (t->obedit_type == OB_ARMATURE) {
+ return &TransConvertType_EditArmature;
}
+ return NULL;
}
- else if (ob && (ob->mode & OB_MODE_POSE)) {
- convert_type = TC_POSE;
+ if (ob && (ob->mode & OB_MODE_POSE)) {
+ return &TransConvertType_Pose;
}
- else if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
+ if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
Object *ob_armature = transform_object_deform_pose_armature_get(t, ob);
if (ob_armature) {
*r_obj_armature = ob_armature;
- convert_type = TC_POSE;
+ return &TransConvertType_Pose;
}
+ return NULL;
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_start_edit(PE_get_current(t->depsgraph, t->scene, ob))) {
- convert_type = TC_PARTICLE_VERTS;
+ if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
+ PE_start_edit(PE_get_current(t->depsgraph, t->scene, ob))) {
+ return &TransConvertType_Particle;
}
- else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- convert_type = TC_PAINT_CURVE_VERTS;
+ return &TransConvertType_PaintCurve;
}
+ return NULL;
}
- else if ((ob) && (ELEM(ob->mode,
- OB_MODE_PAINT_GPENCIL,
- OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL,
- OB_MODE_VERTEX_GPENCIL))) {
+ if ((ob) && (ELEM(ob->mode,
+ OB_MODE_PAINT_GPENCIL,
+ OB_MODE_SCULPT_GPENCIL,
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL))) {
/* In grease pencil all transformations must be canceled if not Object or Edit. */
+ return NULL;
}
- else {
- convert_type = TC_OBJECT;
- }
-
- return convert_type;
+ return &TransConvertType_Object;
}
void createTransData(bContext *C, TransInfo *t)
@@ -1376,133 +1127,64 @@ void createTransData(bContext *C, TransInfo *t)
Object *ob_armature = NULL;
t->data_type = convert_type_get(t, &ob_armature);
- t->flag |= flags_from_data_type(t->data_type);
+ if (t->data_type == NULL) {
+ printf("edit type not implemented!\n");
+ BLI_assert(t->data_len_all == -1);
+ t->data_len_all = 0;
+ return;
+ }
+
+ t->flag |= t->data_type->flags;
if (ob_armature) {
init_TransDataContainers(t, ob_armature, &ob_armature, 1);
}
else {
ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
init_TransDataContainers(t, ob, NULL, 0);
}
- switch (t->data_type) {
- case TC_ACTION_DATA:
- createTransActionData(C, t);
- break;
- case TC_POSE:
- t->options |= CTX_POSE_BONE;
+ if (t->data_type == &TransConvertType_Object) {
+ t->options |= CTX_OBJECT;
- /* XXX active-layer checking isn't done
- * as that should probably be checked through context instead. */
- createTransPose(t);
- break;
- case TC_ARMATURE_VERTS:
- createTransArmatureVerts(t);
- break;
- case TC_CURSOR_IMAGE:
- createTransCursor_image(t);
- break;
- case TC_CURSOR_SEQUENCER:
- createTransCursor_sequencer(t);
- break;
- case TC_CURSOR_VIEW3D:
- createTransCursor_view3d(t);
- break;
- case TC_CURVE_VERTS:
- createTransCurveVerts(t);
- break;
- case TC_GRAPH_EDIT_DATA:
- createTransGraphEditData(C, t);
- break;
- case TC_GPENCIL:
- createTransGPencil(C, t);
- break;
- case TC_LATTICE_VERTS:
- createTransLatticeVerts(t);
- break;
- case TC_MASKING_DATA:
- createTransMaskingData(C, t);
- break;
- case TC_MBALL_VERTS:
- createTransMBallVerts(t);
- break;
- case TC_MESH_VERTS:
- createTransEditVerts(t);
- break;
- case TC_MESH_EDGES:
- createTransEdge(t);
- break;
- case TC_MESH_SKIN:
- createTransMeshSkin(t);
- break;
- case TC_MESH_UV:
- createTransUVs(C, t);
- break;
- case TC_NLA_DATA:
- createTransNlaData(C, t);
- break;
- case TC_NODE_DATA:
- createTransNodeData(t);
- break;
- case TC_OBJECT:
- t->options |= CTX_OBJECT;
-
- /* Needed for correct Object.obmat after duplication, see: T62135. */
- BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
-
- if ((t->settings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
- t->options |= CTX_OBMODE_XFORM_OBDATA;
- }
- if ((t->settings->transform_flag & SCE_XFORM_SKIP_CHILDREN) != 0) {
- t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN;
- }
- createTransObject(C, t);
- /* Check if we're transforming the camera from the camera */
- if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
- View3D *v3d = t->view;
- RegionView3D *rv3d = t->region->regiondata;
- if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
- /* we could have a flag to easily check an object is being transformed */
- if (v3d->camera->id.tag & LIB_TAG_DOIT) {
- t->options |= CTX_CAMERA;
- }
- }
- else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) {
+ /* Needed for correct Object.obmat after duplication, see: T62135. */
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
+
+ if ((t->settings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
+ t->options |= CTX_OBMODE_XFORM_OBDATA;
+ }
+ if ((t->settings->transform_flag & SCE_XFORM_SKIP_CHILDREN) != 0) {
+ t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN;
+ }
+ TransConvertType_Object.createTransData(C, t);
+ /* Check if we're transforming the camera from the camera */
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ View3D *v3d = t->view;
+ RegionView3D *rv3d = t->region->regiondata;
+ if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
+ /* we could have a flag to easily check an object is being transformed */
+ if (v3d->camera->id.tag & LIB_TAG_DOIT) {
t->options |= CTX_CAMERA;
}
}
- break;
- case TC_OBJECT_TEXSPACE:
- createTransTexspace(t);
- break;
- case TC_PAINT_CURVE_VERTS:
- createTransPaintCurveVerts(C, t);
- break;
- case TC_PARTICLE_VERTS:
- createTransParticleVerts(t);
- break;
- case TC_SCULPT:
- createTransSculpt(C, t);
- break;
- case TC_SEQ_DATA:
- t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transform. */
- createTransSeqData(t);
- break;
- case TC_SEQ_IMAGE_DATA:
+ else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) {
+ t->options |= CTX_CAMERA;
+ }
+ }
+ }
+ else {
+ if (t->data_type == &TransConvertType_Pose) {
+ t->options |= CTX_POSE_BONE;
+ }
+ else if (t->data_type == &TransConvertType_Sequencer) {
+ /* Sequencer has no use for floating point transform. */
+ t->num.flag |= NUM_NO_FRACTION;
+ }
+ else if (t->data_type == &TransConvertType_SequencerImage) {
t->obedit_type = -1;
- createTransSeqImageData(t);
- break;
- case TC_TRACKING_DATA:
- createTransTrackingData(C, t);
- break;
- case TC_NONE:
- default:
- printf("edit type not implemented!\n");
- BLI_assert(t->data_len_all == -1);
- t->data_len_all = 0;
- return;
+ }
+ t->data_type->createTransData(C, t);
}
countAndCleanTransDataContainer(t);
@@ -1704,89 +1386,10 @@ void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const fl
void recalcData(TransInfo *t)
{
- switch (t->data_type) {
- case TC_ACTION_DATA:
- recalcData_actedit(t);
- break;
- case TC_POSE:
- recalcData_pose(t);
- break;
- case TC_ARMATURE_VERTS:
- recalcData_edit_armature(t);
- break;
- case TC_CURVE_VERTS:
- recalcData_curve(t);
- break;
- case TC_CURSOR_IMAGE:
- recalcData_cursor_image(t);
- break;
- case TC_CURSOR_SEQUENCER:
- recalcData_cursor_sequencer(t);
- break;
- case TC_CURSOR_VIEW3D:
- recalcData_cursor_view3d(t);
- break;
- case TC_GRAPH_EDIT_DATA:
- recalcData_graphedit(t);
- break;
- case TC_GPENCIL:
- recalcData_gpencil_strokes(t);
- break;
- case TC_MASKING_DATA:
- recalcData_mask_common(t);
- break;
- case TC_MESH_VERTS:
- recalcData_mesh(t);
- break;
- case TC_MESH_EDGES:
- recalcData_mesh_edge(t);
- break;
- case TC_MESH_SKIN:
- recalcData_mesh_skin(t);
- break;
- case TC_MESH_UV:
- recalcData_uv(t);
- break;
- case TC_NLA_DATA:
- recalcData_nla(t);
- break;
- case TC_NODE_DATA:
- flushTransNodes(t);
- break;
- case TC_OBJECT:
- recalcData_objects(t);
- break;
- case TC_OBJECT_TEXSPACE:
- recalcData_texspace(t);
- break;
- case TC_PAINT_CURVE_VERTS:
- flushTransPaintCurve(t);
- break;
- case TC_SCULPT:
- recalcData_sculpt(t);
- break;
- case TC_SEQ_DATA:
- recalcData_sequencer(t);
- break;
- case TC_SEQ_IMAGE_DATA:
- recalcData_sequencer_image(t);
- break;
- case TC_TRACKING_DATA:
- recalcData_tracking(t);
- break;
- case TC_MBALL_VERTS:
- recalcData_mball(t);
- break;
- case TC_LATTICE_VERTS:
- recalcData_lattice(t);
- break;
- case TC_PARTICLE_VERTS:
- recalcData_particles(t);
- break;
- case TC_NONE:
- default:
- break;
+ if (!t->data_type || !t->data_type->recalcData) {
+ return;
}
+ t->data_type->recalcData(t);
}
/** \} */
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 3aeea049150..d30748233ad 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -21,6 +21,25 @@ struct TransDataCurveHandleFlags;
struct TransInfo;
struct bContext;
+typedef struct TransConvertTypeInfo {
+ int flags; /* eTFlag */
+
+ /**
+ * Allocate and initialize `t->data`.
+ */
+ void (*createTransData)(bContext *C, TransInfo *t);
+
+ /**
+ * Force recalculation of data during transformation.
+ */
+ void (*recalcData)(TransInfo *t);
+
+ /**
+ * Called when the operation is finished.
+ */
+ void (*special_aftertrans_update)(bContext *C, TransInfo *t);
+} TransConvertTypeInfo;
+
/* transform_convert.c */
/**
@@ -34,7 +53,6 @@ int special_transform_moving(TransInfo *t);
void special_aftertrans_update(struct bContext *C, TransInfo *t);
void sort_trans_data_dist(TransInfo *t);
void createTransData(struct bContext *C, TransInfo *t);
-bool clipUVTransform(TransInfo *t, float vec[2], bool resize);
void clipUVData(TransInfo *t);
void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac);
/**
@@ -95,82 +113,53 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
/* transform_convert_action.c */
-void createTransActionData(bContext *C, TransInfo *t);
-/* helper for recalcData() - for Action Editor transforms */
-void recalcData_actedit(TransInfo *t);
-void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Action;
/* transform_convert_armature.c */
+extern TransConvertTypeInfo TransConvertType_EditArmature;
+extern TransConvertTypeInfo TransConvertType_Pose;
+
/**
* Sets transform flags in the bones.
* Returns total number of bones with #BONE_TRANSFORM.
*/
void transform_convert_pose_transflags_update(Object *ob, int mode, short around);
-/**
- * When objects array is NULL, use 't->data_container' as is.
- */
-void createTransPose(TransInfo *t);
-void createTransArmatureVerts(TransInfo *t);
-void recalcData_edit_armature(TransInfo *t);
-void recalcData_pose(TransInfo *t);
-void special_aftertrans_update__pose(bContext *C, TransInfo *t);
-
/* transform_convert_cursor.c */
-void createTransCursor_image(TransInfo *t);
-void createTransCursor_sequencer(TransInfo *t);
-void createTransCursor_view3d(TransInfo *t);
-void recalcData_cursor_image(TransInfo *t);
-void recalcData_cursor_sequencer(TransInfo *t);
-void recalcData_cursor_view3d(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_CursorImage;
+extern TransConvertTypeInfo TransConvertType_CursorSequencer;
+extern TransConvertTypeInfo TransConvertType_Cursor3D;
/* transform_convert_curve.c */
-void createTransCurveVerts(TransInfo *t);
-void recalcData_curve(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Curve;
/* transform_convert_graph.c */
-/**
- * It is important to note that this doesn't always act on the selection (like it's usually done),
- * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
- * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
- * selected left or right handles accordingly.
- * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
- * functions may need to be made aware of this. It's ugly that these act based on selection state
- * anyway.
- */
-void createTransGraphEditData(bContext *C, TransInfo *t);
-/* helper for recalcData() - for Graph Editor transforms */
-void recalcData_graphedit(TransInfo *t);
-void special_aftertrans_update__graph(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Graph;
/* transform_convert_gpencil.c */
-void createTransGPencil(bContext *C, TransInfo *t);
-/* force recalculation of triangles during transformation */
-void recalcData_gpencil_strokes(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_GPencil;
/* transform_convert_lattice.c */
-void createTransLatticeVerts(TransInfo *t);
-void recalcData_lattice(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Lattice;
/* transform_convert_mask.c */
-void createTransMaskingData(bContext *C, TransInfo *t);
-void recalcData_mask_common(TransInfo *t);
-void special_aftertrans_update__mask(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Mask;
/* transform_convert_mball.c */
-void createTransMBallVerts(TransInfo *t);
-void recalcData_mball(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_MBall;
/* transform_convert_mesh.c */
+extern TransConvertTypeInfo TransConvertType_Mesh;
+
struct TransIslandData {
float (*center)[3];
float (*axismtx)[3][3];
@@ -229,84 +218,60 @@ void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3],
struct TransData *r_td);
void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data);
-void createTransEditVerts(TransInfo *t);
-void recalcData_mesh(TransInfo *t);
void special_aftertrans_update__mesh(bContext *C, TransInfo *t);
/* transform_convert_mesh_edge.c */
-void createTransEdge(TransInfo *t);
-void recalcData_mesh_edge(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_MeshEdge;
/* transform_convert_mesh_skin.c */
-void createTransMeshSkin(TransInfo *t);
-void recalcData_mesh_skin(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_MeshSkin;
/* transform_convert_mesh_uv.c */
-void createTransUVs(bContext *C, TransInfo *t);
-/* helper for recalcData() - for Image Editor transforms */
-void recalcData_uv(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_MeshUV;
+
+/* transform_convert_mesh_vert_cdata.c */
+
+extern TransConvertTypeInfo TransConvertType_MeshVertCData;
/* transform_convert_nla.c */
-void createTransNlaData(bContext *C, TransInfo *t);
-/* helper for recalcData() - for NLA Editor transforms */
-void recalcData_nla(TransInfo *t);
-void special_aftertrans_update__nla(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_NLA;
/* transform_convert_node.c */
-void createTransNodeData(TransInfo *t);
-void flushTransNodes(TransInfo *t);
-void special_aftertrans_update__node(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Node;
/* transform_convert_object.c */
-void createTransObject(bContext *C, TransInfo *t);
-/* helper for recalcData() - for object transforms, typically in the 3D view */
-void recalcData_objects(TransInfo *t);
-void special_aftertrans_update__object(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Object;
/* transform_convert_object_texspace.c */
-void createTransTexspace(TransInfo *t);
-/* helper for recalcData() - for object transforms, typically in the 3D view */
-void recalcData_texspace(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_ObjectTexSpace;
/* transform_convert_paintcurve.c */
-void createTransPaintCurveVerts(bContext *C, TransInfo *t);
-void flushTransPaintCurve(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_PaintCurve;
/* transform_convert_particle.c */
-void createTransParticleVerts(TransInfo *t);
-void recalcData_particles(TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Particle;
/* transform_convert_sculpt.c */
-void createTransSculpt(bContext *C, TransInfo *t);
-void recalcData_sculpt(TransInfo *t);
-void special_aftertrans_update__sculpt(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Sculpt;
/* transform_convert_sequencer.c */
-void createTransSeqData(TransInfo *t);
-/* helper for recalcData() - for sequencer transforms */
-void recalcData_sequencer(TransInfo *t);
-void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Sequencer;
/* transform_convert_sequencer_image.c */
-void createTransSeqImageData(TransInfo *t);
-void recalcData_sequencer_image(TransInfo *t);
-void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_SequencerImage;
/* transform_convert_tracking.c */
-void createTransTrackingData(bContext *C, TransInfo *t);
-/* helper for recalcData() - for Movie Clip transforms */
-void recalcData_tracking(TransInfo *t);
-void special_aftertrans_update__movieclip(bContext *C, TransInfo *t);
+extern TransConvertTypeInfo TransConvertType_Tracking;
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 71c245cd512..252f150995e 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -18,6 +18,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_mask.h"
#include "BKE_nla.h"
@@ -289,7 +290,7 @@ static int MaskLayerToTransData(TransData *td,
return count;
}
-void createTransActionData(bContext *C, TransInfo *t)
+static void createTransActionData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
TransData *td = NULL;
@@ -311,6 +312,7 @@ void createTransActionData(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
int count = 0;
+ int gpf_count = 0;
float cfra;
float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur);
@@ -320,17 +322,12 @@ void createTransActionData(bContext *C, TransInfo *t)
}
/* filter data */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -345,10 +342,10 @@ void createTransActionData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
@@ -365,13 +362,16 @@ void createTransActionData(bContext *C, TransInfo *t)
}
if (adt_count > 0) {
+ if (ELEM(ale->type, ANIMTYPE_GPLAYER, ANIMTYPE_MASKLAYER)) {
+ gpf_count += adt_count;
+ }
count += adt_count;
ale->tag = true;
}
}
/* stop if trying to build list if nothing selected */
- if (count == 0) {
+ if (count == 0 && gpf_count == 0) {
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
return;
@@ -387,8 +387,9 @@ void createTransActionData(bContext *C, TransInfo *t)
td = tc->data;
td2d = tc->data_2d;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
+ tc->data_gpf_len = gpf_count;
+ tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * gpf_count, "tGPFtransdata");
tc->custom.type.use_free = true;
}
@@ -399,7 +400,7 @@ void createTransActionData(bContext *C, TransInfo *t)
continue;
}
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
{
AnimData *adt;
@@ -447,10 +448,10 @@ void createTransActionData(bContext *C, TransInfo *t)
adt = ANIM_nla_mapping_get(&ac, ale);
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
if (ale->type == ANIMTYPE_GPLAYER) {
@@ -558,13 +559,14 @@ static void flushTransIntFrameActionData(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
tGPFtransdata *tfd = tc->custom.type.data;
- /* flush data! */
- for (int i = 0; i < tc->data_len; i++, tfd++) {
+ /* flush data!
+ * Expects data_gpf_len to be set in the data container. */
+ for (int i = 0; i < tc->data_gpf_len; i++, tfd++) {
*(tfd->sdata) = round_fl_to_int(tfd->val);
}
}
-void recalcData_actedit(TransInfo *t)
+static void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
@@ -579,7 +581,7 @@ void recalcData_actedit(TransInfo *t)
ac.bmain = CTX_data_main(t->context);
ac.scene = t->scene;
ac.view_layer = t->view_layer;
- ac.obact = OBACT(view_layer);
+ ac.obact = BKE_view_layer_active_object_get(view_layer);
ac.area = t->area;
ac.region = t->region;
ac.sl = (t->area) ? t->area->spacedata.first : NULL;
@@ -589,7 +591,7 @@ void recalcData_actedit(TransInfo *t)
ANIM_animdata_context_getdata(&ac);
/* perform flush */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
/* flush transform values back to actual coordinates */
flushTransIntFrameActionData(t);
}
@@ -735,7 +737,7 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
int filter;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
/* loop through relevant data, removing keyframes as appropriate
@@ -758,7 +760,7 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
ANIM_animdata_freelist(&anim_data);
}
-void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
+static void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
{
SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac;
@@ -776,32 +778,44 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- /* these should all be F-Curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- else {
- posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
+ switch (ale->datatype) {
+ case ALE_GPFRAME:
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_gpd_clean((bGPdata *)ale->id);
+ break;
+
+ case ALE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
+ }
+ }
+ break;
}
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be transformed into this animation type.");
}
}
@@ -847,15 +861,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_GPFRAME) {
- ale->id->tag |= LIB_TAG_DOIT;
- }
- }
- LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
- if (ale->datatype == ALE_GPFRAME) {
- if (ale->id->tag & LIB_TAG_DOIT) {
- ale->id->tag &= ~LIB_TAG_DOIT;
- posttrans_gpd_clean((bGPdata *)ale->id);
- }
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_gpd_clean((bGPdata *)ale->id);
}
}
ANIM_animdata_freelist(&anim_data);
@@ -878,15 +885,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_MASKLAY) {
- ale->id->tag |= LIB_TAG_DOIT;
- }
- }
- LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
- if (ale->datatype == ALE_MASKLAY) {
- if (ale->id->tag & LIB_TAG_DOIT) {
- ale->id->tag &= ~LIB_TAG_DOIT;
- posttrans_mask_clean((Mask *)ale->id);
- }
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_mask_clean((Mask *)ale->id);
}
}
ANIM_animdata_freelist(&anim_data);
@@ -927,3 +927,10 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Action = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransActionData,
+ /* recalcData */ recalcData_actedit,
+ /* special_aftertrans_update */ special_aftertrans_update__actedit,
+};
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 485425c644a..8fb48986b29 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -93,8 +93,8 @@ static void autokeyframe_pose(
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase nla_cache = {NULL, NULL};
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
eInsertKeyFlags flag = 0;
/* flag is initialized from UserPref keyframing settings
@@ -701,7 +701,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
td->con = pchan->constraints.first;
}
-void createTransPose(TransInfo *t)
+static void createTransPose(bContext *UNUSED(C), TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
@@ -879,7 +879,7 @@ void createTransPose(TransInfo *t)
}
}
-void createTransArmatureVerts(TransInfo *t)
+static void createTransArmatureVerts(bContext *UNUSED(C), TransInfo *t)
{
t->data_len_all = 0;
@@ -1189,10 +1189,10 @@ static void restoreBones(TransDataContainer *tc)
}
}
-void recalcData_edit_armature(TransInfo *t)
+static void recalcData_edit_armature(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -1356,7 +1356,7 @@ static void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, O
}
mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
if (pid) {
- /* TODO(germano): Relative Mirror support. */
+ /* TODO(@germano): Relative Mirror support. */
}
data->flag |= CONSTRAINT_IK_AUTO;
/* Add a temporary auto IK constraint here, as we will only temporarily active this
@@ -1412,7 +1412,7 @@ static void restoreMirrorPoseBones(TransDataContainer *tc)
}
}
-void recalcData_pose(TransInfo *t)
+static void recalcData_pose(TransInfo *t)
{
if (t->mode == TFM_BONESIZE) {
/* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
@@ -1684,7 +1684,7 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
}
}
-void special_aftertrans_update__pose(bContext *C, TransInfo *t)
+static void special_aftertrans_update__pose(bContext *C, TransInfo *t)
{
Object *ob;
@@ -1768,3 +1768,17 @@ void special_aftertrans_update__pose(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_EditArmature = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransArmatureVerts,
+ /* recalcData */ recalcData_edit_armature,
+ /* special_aftertrans_update */ NULL,
+};
+
+TransConvertTypeInfo TransConvertType_Pose = {
+ /* flags */ 0,
+ /* createTransData */ createTransPose,
+ /* recalcData */ recalcData_pose,
+ /* special_aftertrans_update */ special_aftertrans_update__pose,
+};
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
index 5e6eee192f2..0bf6f06a9f2 100644
--- a/source/blender/editors/transform/transform_convert_cursor.c
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -82,13 +82,13 @@ static void recalcData_cursor_2D_impl(TransInfo *t)
/** \name Image Cursor
* \{ */
-void createTransCursor_image(TransInfo *t)
+static void createTransCursor_image(bContext *UNUSED(C), TransInfo *t)
{
SpaceImage *sima = t->area->spacedata.first;
createTransCursor_2D_impl(t, sima->cursor);
}
-void recalcData_cursor_image(TransInfo *t)
+static void recalcData_cursor_image(TransInfo *t)
{
recalcData_cursor_2D_impl(t);
}
@@ -99,7 +99,7 @@ void recalcData_cursor_image(TransInfo *t)
/** \name Sequencer Cursor
* \{ */
-void createTransCursor_sequencer(TransInfo *t)
+static void createTransCursor_sequencer(bContext *UNUSED(C), TransInfo *t)
{
SpaceSeq *sseq = t->area->spacedata.first;
if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
@@ -108,7 +108,7 @@ void createTransCursor_sequencer(TransInfo *t)
createTransCursor_2D_impl(t, sseq->cursor);
}
-void recalcData_cursor_sequencer(TransInfo *t)
+static void recalcData_cursor_sequencer(TransInfo *t)
{
recalcData_cursor_2D_impl(t);
}
@@ -119,7 +119,7 @@ void recalcData_cursor_sequencer(TransInfo *t)
/** \name View 3D Cursor
* \{ */
-void createTransCursor_view3d(TransInfo *t)
+static void createTransCursor_view3d(bContext *UNUSED(C), TransInfo *t)
{
TransData *td;
@@ -178,9 +178,30 @@ void createTransCursor_view3d(TransInfo *t)
td->ext->rotOrder = cursor->rotation_mode;
}
-void recalcData_cursor_view3d(TransInfo *t)
+static void recalcData_cursor_view3d(TransInfo *t)
{
DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_CursorImage = {
+ /* flags */ T_2D_EDIT,
+ /* createTransData */ createTransCursor_image,
+ /* recalcData */ recalcData_cursor_image,
+ /* special_aftertrans_update */ NULL,
+};
+
+TransConvertTypeInfo TransConvertType_CursorSequencer = {
+ /* flags */ T_2D_EDIT,
+ /* createTransData */ createTransCursor_sequencer,
+ /* recalcData */ recalcData_cursor_sequencer,
+ /* special_aftertrans_update */ NULL,
+};
+
+TransConvertTypeInfo TransConvertType_Cursor3D = {
+ /* flags */ 0,
+ /* createTransData */ createTransCursor_view3d,
+ /* recalcData */ recalcData_cursor_view3d,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 51acfb2a788..404b1293208 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -62,7 +62,7 @@ static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const boo
return flag;
}
-void createTransCurveVerts(TransInfo *t)
+static void createTransCurveVerts(bContext *UNUSED(C), TransInfo *t)
{
#define SEL_F1 (1 << 0)
@@ -415,10 +415,10 @@ void createTransCurveVerts(TransInfo *t)
#undef SEL_F3
}
-void recalcData_curve(TransInfo *t)
+static void recalcData_curve(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -446,3 +446,10 @@ void recalcData_curve(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Curve = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransCurveVerts,
+ /* recalcData */ recalcData_curve,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index a88d42b7f30..5056b30f77f 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -19,6 +19,7 @@
#include "BKE_gpencil.h"
#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
+#include "BKE_layer.h"
#include "ED_gpencil.h"
#include "ED_keyframing.h"
@@ -672,7 +673,7 @@ static void createTransGPencil_strokes(bContext *C,
}
}
-void createTransGPencil(bContext *C, TransInfo *t)
+static void createTransGPencil(bContext *C, TransInfo *t)
{
if (t->data_container_len == 0) {
return;
@@ -681,11 +682,11 @@ void createTransGPencil(bContext *C, TransInfo *t)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obact = OBACT(t->view_layer);
+ Object *obact = BKE_view_layer_active_object_get(t->view_layer);
bGPdata *gpd = obact->data;
BLI_assert(gpd != NULL);
- const int cfra_scene = CFRA;
+ const int cfra_scene = scene->r.cfra;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) !=
@@ -737,7 +738,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
}
-void recalcData_gpencil_strokes(TransInfo *t)
+static void recalcData_gpencil_strokes(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
GHash *strokes = BLI_ghash_ptr_new(__func__);
@@ -762,3 +763,10 @@ void recalcData_gpencil_strokes(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_GPencil = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransGPencil,
+ /* recalcData */ recalcData_gpencil_strokes,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 2039daee386..fad192d54db 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -14,6 +14,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_layer.h"
#include "BKE_nla.h"
#include "BKE_report.h"
@@ -199,7 +200,16 @@ static void graph_key_shortest_dist(
}
}
-void createTransGraphEditData(bContext *C, TransInfo *t)
+/**
+ * It is important to note that this doesn't always act on the selection (like it's usually done),
+ * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
+ * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
+ * selected left or right handles accordingly.
+ * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
+ * functions may need to be made aware of this. It's ugly that these act based on selection state
+ * anyway.
+ */
+static void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
@@ -232,13 +242,14 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
anim_map_flag |= ANIM_get_normalization_flags(&ac);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
/* XXX we still want this mode, but how to get this using standard transform too? */
if (t->mode == TFM_TIME_EXTEND) {
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -263,10 +274,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -369,10 +380,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
unit_scale = ANIM_unit_mapping_get_factor(
@@ -560,10 +571,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -885,7 +896,7 @@ static void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
}
}
-void recalcData_graphedit(TransInfo *t)
+static void recalcData_graphedit(TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
ViewLayer *view_layer = t->view_layer;
@@ -902,7 +913,7 @@ void recalcData_graphedit(TransInfo *t)
ac.bmain = CTX_data_main(t->context);
ac.scene = t->scene;
ac.view_layer = t->view_layer;
- ac.obact = OBACT(view_layer);
+ ac.obact = BKE_view_layer_active_object_get(view_layer);
ac.area = t->area;
ac.region = t->region;
ac.sl = (t->area) ? t->area->spacedata.first : NULL;
@@ -915,7 +926,8 @@ void recalcData_graphedit(TransInfo *t)
flushTransGraphData(t);
/* get curves to check if a re-sort is needed */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* now test if there is a need to re-sort */
@@ -932,7 +944,7 @@ void recalcData_graphedit(TransInfo *t)
dosort++;
}
else {
- calchandles_fcurve_ex(fcu, BEZT_FLAG_TEMP_TAG);
+ BKE_fcurve_handles_recalc_ex(fcu, BEZT_FLAG_TEMP_TAG);
}
/* set refresh tags for objects using this animation,
@@ -958,7 +970,7 @@ void recalcData_graphedit(TransInfo *t)
/** \name Special After Transform Graph
* \{ */
-void special_aftertrans_update__graph(bContext *C, TransInfo *t)
+static void special_aftertrans_update__graph(bContext *C, TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimContext ac;
@@ -975,7 +987,8 @@ void special_aftertrans_update__graph(bContext *C, TransInfo *t)
if (ac.datatype) {
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1018,3 +1031,10 @@ void special_aftertrans_update__graph(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Graph = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransGraphEditData,
+ /* recalcData */ recalcData_graphedit,
+ /* special_aftertrans_update */ special_aftertrans_update__graph,
+};
diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c
index f02d4e94448..b77538dc249 100644
--- a/source/blender/editors/transform/transform_convert_lattice.c
+++ b/source/blender/editors/transform/transform_convert_lattice.c
@@ -25,7 +25,7 @@
/** \name Curve/Surfaces Transform Creation
* \{ */
-void createTransLatticeVerts(TransInfo *t)
+static void createTransLatticeVerts(bContext *UNUSED(C), TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -98,10 +98,10 @@ void createTransLatticeVerts(TransInfo *t)
}
}
-void recalcData_lattice(TransInfo *t)
+static void recalcData_lattice(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -114,3 +114,10 @@ void recalcData_lattice(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Lattice = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransLatticeVerts,
+ /* recalcData */ recalcData_lattice,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 5255cc4412e..2dca59a5da1 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -117,7 +117,7 @@ static void MaskPointToTransData(Scene *scene,
const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
float parent_matrix[3][3], parent_inverse_matrix[3][3];
- BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
+ BKE_mask_point_parent_matrix_get(point, scene->r.cfra, parent_matrix);
invert_m3_m3(parent_inverse_matrix, parent_matrix);
if (is_prop_edit || is_sel_point) {
@@ -245,7 +245,7 @@ static void MaskPointToTransData(Scene *scene,
}
}
-void createTransMaskingData(bContext *C, TransInfo *t)
+static void createTransMaskingData(bContext *C, TransInfo *t)
{
Scene *scene = CTX_data_scene(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -261,18 +261,10 @@ void createTransMaskingData(bContext *C, TransInfo *t)
tc->data_len = 0;
- if (!mask) {
+ if (!ED_maskedit_mask_visible_splines_poll(C)) {
return;
}
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->area->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!clip) {
- return;
- }
- }
-
/* count */
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
@@ -424,7 +416,7 @@ static void flushTransMasking(TransInfo *t)
}
}
-void recalcData_mask_common(TransInfo *t)
+static void recalcData_mask_common(TransInfo *t)
{
Mask *mask = CTX_data_edit_mask(t->context);
@@ -439,7 +431,7 @@ void recalcData_mask_common(TransInfo *t)
/** \name Special After Transform Mask
* \{ */
-void special_aftertrans_update__mask(bContext *C, TransInfo *t)
+static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
{
Mask *mask = NULL;
@@ -463,7 +455,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
if (IS_AUTOKEY_ON(t->scene)) {
Scene *scene = t->scene;
- if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) {
+ if (ED_mask_layer_shape_auto_key_select(mask, scene->r.cfra)) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
DEG_id_tag_update(&mask->id, 0);
}
@@ -471,3 +463,10 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Mask = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransMaskingData,
+ /* recalcData */ recalcData_mask_common,
+ /* special_aftertrans_update */ special_aftertrans_update__mask,
+};
diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c
index 7cba4f97886..7ae93524d0b 100644
--- a/source/blender/editors/transform/transform_convert_mball.c
+++ b/source/blender/editors/transform/transform_convert_mball.c
@@ -22,7 +22,7 @@
/** \name Meta Elements Transform Creation
* \{ */
-void createTransMBallVerts(TransInfo *t)
+static void createTransMBallVerts(bContext *UNUSED(C), TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
MetaBall *mb = (MetaBall *)tc->obedit->data;
@@ -119,10 +119,10 @@ void createTransMBallVerts(TransInfo *t)
/** \name Recalc Meta Ball
* \{ */
-void recalcData_mball(TransInfo *t)
+static void recalcData_mball(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->data_len) {
@@ -132,3 +132,10 @@ void recalcData_mball(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_MBall = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransMBallVerts,
+ /* recalcData */ recalcData_mball,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index d4b12142162..f67a44703e5 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1314,7 +1314,8 @@ void transform_convert_mesh_crazyspace_detect(TransInfo *t,
* correction with \a quats, relative to the coordinates after
* the modifiers that support deform matrices \a defcos. */
-#if 0 /* TODO(campbell): fix crazy-space & extrude so it can be enabled for general use. */
+#if 0 /* TODO(@campbellbarton): fix crazy-space & extrude so it can be enabled for general use. \
+ */
if ((totleft > 0) || (totleft == -1))
#else
if (totleft > 0)
@@ -1408,7 +1409,6 @@ static void VertsToTransData(TransInfo *t,
TransDataExtension *tx,
BMEditMesh *em,
BMVert *eve,
- float *bweight,
const struct TransIslandData *island_data,
const int island_index)
{
@@ -1449,17 +1449,13 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
- if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) {
- td->val = bweight;
- td->ival = *bweight;
- }
- else if (t->mode == TFM_SHRINKFATTEN) {
+ if (t->mode == TFM_SHRINKFATTEN) {
td->ext = tx;
tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
}
}
-void createTransEditVerts(TransInfo *t)
+static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransDataExtension *tx = NULL;
@@ -1589,17 +1585,6 @@ void createTransEditVerts(TransInfo *t)
"TransObData ext");
}
- int cd_vert_bweight_offset = -1;
- int cd_vert_crease_offset = -1;
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- }
- else if (t->mode == TFM_VERT_CREASE) {
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE);
- cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
- }
-
TransData *tob = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
@@ -1632,15 +1617,9 @@ void createTransEditVerts(TransInfo *t)
td_mirror++;
}
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float *bweight = (cd_vert_bweight_offset != -1) ?
- BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
- (cd_vert_crease_offset != -1) ?
- BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) :
- NULL;
-
/* Do not use the island center in case we are using islands
* only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index);
+ VertsToTransData(t, tob, tx, em, eve, &island_data, island_index);
if (tx) {
tx++;
}
@@ -1940,7 +1919,7 @@ static void tc_mesh_partial_types_calc(TransInfo *t, struct PartialTypeState *r_
}
/* With projection, transform isn't affine. */
- if (activeSnap_with_project(t)) {
+ if (activeSnap_SnappingIndividual(t)) {
if (partial_for_looptri == PARTIAL_TYPE_GROUP) {
partial_for_looptri = PARTIAL_TYPE_ALL;
}
@@ -2051,12 +2030,12 @@ static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc)
}
}
-void recalcData_mesh(TransInfo *t)
+static void recalcData_mesh(TransInfo *t)
{
bool is_canceling = t->state == TRANS_CANCEL;
/* Apply corrections. */
if (!is_canceling) {
- applyProject(t);
+ applySnappingIndividual(t);
bool do_mirror = !(t->flag & T_NO_MIRROR);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -2145,9 +2124,16 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
/* table needs to be created for each edit command, since vertices can move etc */
ED_mesh_mirror_spatial_table_end(tc->obedit);
- /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ /* TODO(@campbellbarton): xform: We need support for many mirror objects at once! */
break;
}
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Mesh = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransEditVerts,
+ /* recalcData */ recalcData_mesh,
+ /* special_aftertrans_update */ special_aftertrans_update__mesh,
+};
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 2d6c6a933d6..becf3c7ce5a 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -23,7 +23,7 @@
/** \name Edge (for crease) Transform Creation
* \{ */
-void createTransEdge(TransInfo *t)
+static void createTransEdge(bContext *UNUSED(C), TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -99,8 +99,8 @@ void createTransEdge(TransInfo *t)
td->ext = NULL;
fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
- td->val = fl_ptr;
- td->ival = *fl_ptr;
+ td->loc = fl_ptr;
+ td->iloc[0] = *fl_ptr;
td++;
}
@@ -108,7 +108,7 @@ void createTransEdge(TransInfo *t)
}
}
-void recalcData_mesh_edge(TransInfo *t)
+static void recalcData_mesh_edge(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
@@ -116,3 +116,10 @@ void recalcData_mesh_edge(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_MeshEdge = {
+ /* flags */ T_EDIT,
+ /* createTransData */ createTransEdge,
+ /* recalcData */ recalcData_mesh_edge,
+ /* special_aftertrans_update */ special_aftertrans_update__mesh,
+};
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index fdc2ba59035..376e559181e 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -66,7 +66,7 @@ static void tc_mesh_skin_transdata_create(TransDataBasic *td,
td->extra = eve;
}
-void createTransMeshSkin(TransInfo *t)
+static void createTransMeshSkin(bContext *UNUSED(C), TransInfo *t)
{
BLI_assert(t->mode == TFM_SKIN_RESIZE);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -271,7 +271,7 @@ static void tc_mesh_skin_apply_to_mirror(TransInfo *t)
}
}
-void recalcData_mesh_skin(TransInfo *t)
+static void recalcData_mesh_skin(TransInfo *t)
{
bool is_canceling = t->state == TRANS_CANCEL;
/* mirror modifier clipping? */
@@ -289,3 +289,10 @@ void recalcData_mesh_skin(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_MeshSkin = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransMeshSkin,
+ /* recalcData */ recalcData_mesh_skin,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 18868643b6d..f3bef2c283b 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -234,11 +234,10 @@ static void uv_set_connectivity_distance(BMesh *bm, float *dists, const float as
MEM_freeN(dists_prev);
}
-void createTransUVs(bContext *C, TransInfo *t)
+static void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = t->scene;
- ToolSettings *ts = CTX_data_tool_settings(C);
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -266,13 +265,12 @@ void createTransUVs(bContext *C, TransInfo *t)
/* count */
if (is_island_center) {
/* create element map with island information */
- const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true);
+ elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true);
if (elementmap == NULL) {
continue;
}
- island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->total_islands, __func__);
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
@@ -317,9 +315,7 @@ void createTransUVs(bContext *C, TransInfo *t)
}
if (is_island_center) {
- int i;
-
- for (i = 0; i < elementmap->totalIslands; i++) {
+ for (int i = 0; i < elementmap->total_islands; i++) {
mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
mul_v2_v2(island_center[i].co, t->aspect);
}
@@ -448,7 +444,7 @@ static void flushTransUVs(TransInfo *t)
}
}
-void recalcData_uv(TransInfo *t)
+static void recalcData_uv(TransInfo *t)
{
SpaceImage *sima = t->area->spacedata.first;
@@ -465,3 +461,10 @@ void recalcData_uv(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_MeshUV = {
+ /* flags */ (T_EDIT | T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransUVs,
+ /* recalcData */ recalcData_uv,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
new file mode 100644
index 00000000000..f05688f3325
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
@@ -0,0 +1,296 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_crazyspace.h"
+#include "BKE_editmesh.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+
+#include "ED_mesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_orientations.h"
+
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mesh #CD_BWEIGHT and #CD_CREASE Transform Creation
+ * \{ */
+
+static float *tc_mesh_cdata_transdata_center(const struct TransIslandData *island_data,
+ const int island_index,
+ BMVert *eve)
+{
+ if (island_data->center && island_index != -1) {
+ return island_data->center[island_index];
+ }
+ return eve->co;
+}
+
+static void tc_mesh_cdata_transdata_create(TransDataBasic *td,
+ BMVert *eve,
+ float *weight,
+ const struct TransIslandData *island_data,
+ const int island_index)
+{
+ BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
+
+ td->loc = weight;
+ td->iloc[0] = *weight;
+
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ td->flag |= TD_SELECTED;
+ }
+
+ copy_v3_v3(td->center, tc_mesh_cdata_transdata_center(island_data, island_index, eve));
+ td->extra = eve;
+}
+
+static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t)
+{
+ BLI_assert(ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE));
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ Mesh *me = tc->obedit->data;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+
+ struct TransIslandData island_data = {NULL};
+ struct TransMirrorData mirror_data = {NULL};
+ struct TransMeshDataCrazySpace crazyspace_data = {NULL};
+
+ /* Support other objects using PET to adjust these, unless connected is enabled. */
+ if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
+ continue;
+ }
+
+ int cd_offset = -1;
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
+ cd_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ }
+ else {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
+ cd_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ }
+
+ if (cd_offset == -1) {
+ continue;
+ }
+
+ int data_len = 0;
+ if (prop_mode) {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ data_len++;
+ }
+ }
+ }
+ else {
+ data_len = bm->totvertsel;
+ }
+
+ if (data_len == 0) {
+ continue;
+ }
+
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+ if (is_island_center) {
+ /* In this specific case, near-by vertices will need to know
+ * the island of the nearest connected vertex. */
+ const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
+
+ const bool calc_island_center = false;
+ const bool calc_island_axismtx = false;
+
+ transform_convert_mesh_islands_calc(
+ em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data);
+ }
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
+ * matrix inversion still works and we can still moving along the other */
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ /* Original index of our connected vertex when connected distances are calculated.
+ * Optional, allocate if needed. */
+ int *dists_index = NULL;
+ float *dists = NULL;
+ if (prop_mode & T_PROP_CONNECTED) {
+ dists = MEM_mallocN(bm->totvert * sizeof(float), __func__);
+ if (is_island_center) {
+ dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__);
+ }
+ transform_convert_mesh_connectivity_distance(em->bm, mtx, dists, dists_index);
+ }
+
+ /* Create TransDataMirror. */
+ if (tc->use_mirror_axis_any) {
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_select = (t->flag & T_PROP_EDIT) == 0;
+ const bool mirror_axis[3] = {
+ tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z};
+ transform_convert_mesh_mirrordata_calc(
+ em, use_select, use_topology, mirror_axis, &mirror_data);
+
+ if (mirror_data.vert_map) {
+ tc->data_mirror_len = mirror_data.mirror_elem_len;
+ tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
+ __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (mirror_data.vert_map[a].index != -1) {
+ data_len--;
+ }
+ }
+ }
+ }
+ }
+
+ /* Detect CrazySpace [tm]. */
+ transform_convert_mesh_crazyspace_detect(t, tc, em, &crazyspace_data);
+
+ /* Create TransData. */
+ BLI_assert(data_len >= 1);
+ tc->data_len = data_len;
+ tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
+
+ TransData *td = tc->data;
+ TransDataMirror *td_mirror = tc->data_mirror;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
+ int island_index = -1;
+ if (island_data.island_vert_map) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ island_index = island_data.island_vert_map[connected_index];
+ }
+
+ float *weight = BM_ELEM_CD_GET_VOID_P(eve, cd_offset);
+ if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) {
+ tc_mesh_cdata_transdata_create(
+ (TransDataBasic *)td_mirror, eve, weight, &island_data, island_index);
+
+ int elem_index = mirror_data.vert_map[a].index;
+ BMVert *v_src = BM_vert_at_index(bm, elem_index);
+
+ td_mirror->flag |= mirror_data.vert_map[a].flag;
+ td_mirror->loc_src = BM_ELEM_CD_GET_VOID_P(v_src, cd_offset);
+ td_mirror++;
+ }
+ else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ tc_mesh_cdata_transdata_create(
+ (TransDataBasic *)td, eve, weight, &island_data, island_index);
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ createSpaceNormal(td->axismtx, eve->no);
+ }
+ else {
+ /* Setting normals */
+ copy_v3_v3(td->axismtx[2], eve->no);
+ td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
+ td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
+ }
+
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
+ td->dist = dists[a];
+ }
+ else {
+ td->flag |= TD_NOTCONNECTED;
+ td->dist = FLT_MAX;
+ }
+ }
+
+ /* CrazySpace */
+ transform_convert_mesh_crazyspace_transdata_set(
+ mtx,
+ smtx,
+ crazyspace_data.defmats ? crazyspace_data.defmats[a] : NULL,
+ crazyspace_data.quats && BM_elem_flag_test(eve, BM_ELEM_TAG) ?
+ crazyspace_data.quats[a] :
+ NULL,
+ td);
+
+ td++;
+ }
+ }
+
+ transform_convert_mesh_islanddata_free(&island_data);
+ transform_convert_mesh_mirrordata_free(&mirror_data);
+ transform_convert_mesh_crazyspace_free(&crazyspace_data);
+ if (dists) {
+ MEM_freeN(dists);
+ }
+ if (dists_index) {
+ MEM_freeN(dists_index);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Mesh Data
+ * \{ */
+
+static void tc_mesh_cdata_apply_to_mirror(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->use_mirror_axis_any) {
+ TransDataMirror *td_mirror = tc->data_mirror;
+ for (int i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
+ td_mirror->loc[0] = td_mirror->loc_src[0];
+ }
+ }
+ }
+}
+
+static void recalcData_mesh_cdata(TransInfo *t)
+{
+ bool is_canceling = t->state == TRANS_CANCEL;
+ /* mirror modifier clipping? */
+ if (!is_canceling) {
+ if (!(t->flag & T_NO_MIRROR)) {
+ tc_mesh_cdata_apply_to_mirror(t);
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BKE_editmesh_looptri_and_normals_calc(em);
+ }
+}
+
+/** \} */
+
+TransConvertTypeInfo TransConvertType_MeshVertCData = {
+ /* flags */ (T_EDIT | T_POINTS),
+ /* createTransData */ createTransMeshVertCData,
+ /* recalcData */ recalcData_mesh_cdata,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 2fa8fcf65ba..cfa933d1600 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -59,7 +59,7 @@ typedef struct TransDataNla {
/** \name NLA Transform Creation
* \{ */
-void createTransNlaData(bContext *C, TransInfo *t)
+static void createTransNlaData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
SpaceNla *snla = NULL;
@@ -82,12 +82,13 @@ void createTransNlaData(bContext *C, TransInfo *t)
snla = (SpaceNla *)ac.sl;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -108,10 +109,10 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* transition strips can't get directly transformed */
if (strip->type != NLASTRIP_TYPE_TRANSITION) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)scene->r.cfra)) {
count++;
}
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)scene->r.cfra)) {
count++;
}
}
@@ -122,7 +123,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* stop if trying to build list if nothing selected */
if (count == 0) {
/* clear temp metas that may have been created but aren't needed now
- * because they fell on the wrong side of CFRA
+ * because they fell on the wrong side of scene->r.cfra
*/
for (ale = anim_data.first; ale; ale = ale->next) {
NlaTrack *nlt = (NlaTrack *)ale->data;
@@ -181,12 +182,12 @@ void createTransNlaData(bContext *C, TransInfo *t)
tdn->h2[0] = strip->end;
tdn->h2[1] = yval;
- center[0] = (float)CFRA;
+ center[0] = (float)scene->r.cfra;
center[1] = yval;
center[2] = 0.0f;
/* set td's based on which handles are applicable */
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)scene->r.cfra)) {
/* just set tdn to assume that it only has one handle for now */
tdn->handle = -1;
@@ -206,7 +207,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
td->extra = tdn;
td++;
}
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)scene->r.cfra)) {
/* if tdn is already holding the start handle,
* then we're doing both, otherwise, only end */
tdn->handle = (tdn->handle) ? 2 : 1;
@@ -248,7 +249,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
-void recalcData_nla(TransInfo *t)
+static void recalcData_nla(TransInfo *t)
{
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
@@ -463,7 +464,7 @@ void recalcData_nla(TransInfo *t)
/** \name Special After Transform NLA
* \{ */
-void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
+static void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
{
bAnimContext ac;
@@ -475,7 +476,7 @@ void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
if (ac.datatype) {
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -505,3 +506,10 @@ void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_NLA = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransNlaData,
+ /* recalcData */ recalcData_nla,
+ /* special_aftertrans_update */ special_aftertrans_update__nla,
+};
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index 8281052c314..ed19789fdd8 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -27,6 +27,13 @@
#include "transform_convert.h"
#include "transform_snap.h"
+struct TransCustomDataNode {
+ View2DEdgePanData edgepan_data;
+
+ /* Compare if the view has changed so we can update with `transformViewUpdate`. */
+ rctf viewrect_prev;
+};
+
/* -------------------------------------------------------------------- */
/** \name Node Transform Creation
* \{ */
@@ -89,21 +96,23 @@ static bool is_node_parent_select(bNode *node)
return false;
}
-void createTransNodeData(TransInfo *t)
+static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
SpaceNode *snode = t->area->spacedata.first;
/* Custom data to enable edge panning during the node transform */
- View2DEdgePanData *customdata = MEM_callocN(sizeof(*customdata), __func__);
+ struct TransCustomDataNode *customdata = MEM_callocN(sizeof(*customdata), __func__);
UI_view2d_edge_pan_init(t->context,
- customdata,
+ &customdata->edgepan_data,
NODE_EDGE_PAN_INSIDE_PAD,
NODE_EDGE_PAN_OUTSIDE_PAD,
NODE_EDGE_PAN_SPEED_RAMP,
NODE_EDGE_PAN_MAX_SPEED,
NODE_EDGE_PAN_DELAY,
NODE_EDGE_PAN_ZOOM_INFLUENCE);
+ customdata->viewrect_prev = customdata->edgepan_data.initial_rect;
+
t->custom.type.data = customdata;
t->custom.type.use_free = true;
@@ -150,15 +159,15 @@ void createTransNodeData(TransInfo *t)
/** \name Node Transform Creation
* \{ */
-void flushTransNodes(TransInfo *t)
+static void flushTransNodes(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
- View2DEdgePanData *customdata = (View2DEdgePanData *)t->custom.type.data;
+ struct TransCustomDataNode *customdata = (struct TransCustomDataNode *)t->custom.type.data;
if (t->options & CTX_VIEW2D_EDGE_PAN) {
if (t->state == TRANS_CANCEL) {
- UI_view2d_edge_pan_cancel(t->context, customdata);
+ UI_view2d_edge_pan_cancel(t->context, &customdata->edgepan_data);
}
else {
/* Edge panning functions expect window coordinates, mval is relative to region */
@@ -166,13 +175,19 @@ void flushTransNodes(TransInfo *t)
t->region->winrct.xmin + t->mval[0],
t->region->winrct.ymin + t->mval[1],
};
- UI_view2d_edge_pan_apply(t->context, customdata, xy);
+ UI_view2d_edge_pan_apply(t->context, &customdata->edgepan_data, xy);
}
}
- /* Initial and current view2D rects for additional transform due to view panning and zooming */
- const rctf *rect_src = &customdata->initial_rect;
- const rctf *rect_dst = &t->region->v2d.cur;
+ float offset[2] = {0.0f, 0.0f};
+ if (t->state != TRANS_CANCEL) {
+ if (!BLI_rctf_compare(&customdata->viewrect_prev, &t->region->v2d.cur, FLT_EPSILON)) {
+ /* Additional offset due to change in view2D rect. */
+ BLI_rctf_transform_pt_v(&t->region->v2d.cur, &customdata->viewrect_prev, offset, offset);
+ tranformViewUpdate(t);
+ customdata->viewrect_prev = t->region->v2d.cur;
+ }
+ }
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
applyGridAbsolute(t);
@@ -184,10 +199,7 @@ void flushTransNodes(TransInfo *t)
bNode *node = td->extra;
float loc[2];
- copy_v2_v2(loc, td2d->loc);
-
- /* additional offset due to change in view2D rect */
- BLI_rctf_transform_pt_v(rect_dst, rect_src, loc, loc);
+ add_v2_v2v2(loc, td2d->loc, offset);
#ifdef USE_NODE_CENTER
loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr);
@@ -220,7 +232,7 @@ void flushTransNodes(TransInfo *t)
/** \name Special After Transform Node
* \{ */
-void special_aftertrans_update__node(bContext *C, TransInfo *t)
+static void special_aftertrans_update__node(bContext *C, TransInfo *t)
{
struct Main *bmain = CTX_data_main(C);
const bool canceled = (t->state == TRANS_CANCEL);
@@ -249,3 +261,10 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Node = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransNodeData,
+ /* recalcData */ flushTransNodes,
+ /* special_aftertrans_update */ special_aftertrans_update__node,
+};
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 02549390c6a..c79dab409ca 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -480,7 +480,7 @@ static void clear_trans_object_base_flags(TransInfo *t)
}
}
-void createTransObject(bContext *C, TransInfo *t)
+static void createTransObject(bContext *C, TransInfo *t)
{
Main *bmain = CTX_data_main(C);
TransData *td = NULL;
@@ -732,8 +732,8 @@ void ED_transform_autokeyframe_object(
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase dsources = {NULL, NULL};
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
eInsertKeyFlags flag = 0;
/* Get flags used for inserting keyframes. */
@@ -782,7 +782,7 @@ void ED_transform_autokeyframe_object(
}
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
- if (ob != OBACT(view_layer)) {
+ if (ob != BKE_view_layer_active_object_get(view_layer)) {
do_loc = true;
}
}
@@ -796,7 +796,7 @@ void ED_transform_autokeyframe_object(
}
else if (tmode == TFM_RESIZE) {
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
- if (ob != OBACT(view_layer)) {
+ if (ob != BKE_view_layer_active_object_get(view_layer)) {
do_loc = true;
}
}
@@ -860,12 +860,12 @@ bool ED_transform_motionpath_need_update_object(Scene *scene, Object *ob)
/** \name Recalc Data object
* \{ */
-void recalcData_objects(TransInfo *t)
+static void recalcData_objects(TransInfo *t)
{
bool motionpath_update = false;
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -918,7 +918,7 @@ void recalcData_objects(TransInfo *t)
/** \name Special After Transform Object
* \{ */
-void special_aftertrans_update__object(bContext *C, TransInfo *t)
+static void special_aftertrans_update__object(bContext *C, TransInfo *t)
{
BLI_assert(t->options & CTX_OBJECT);
@@ -991,3 +991,10 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Object = {
+ /* flags */ 0,
+ /* createTransData */ createTransObject,
+ /* recalcData */ recalcData_objects,
+ /* special_aftertrans_update */ special_aftertrans_update__object,
+};
diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c
index 1f58ec80f02..4dc4218c433 100644
--- a/source/blender/editors/transform/transform_convert_object_texspace.c
+++ b/source/blender/editors/transform/transform_convert_object_texspace.c
@@ -11,6 +11,7 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -29,7 +30,7 @@
*
* \{ */
-void createTransTexspace(TransInfo *t)
+static void createTransTexspace(bContext *UNUSED(C), TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
TransData *td;
@@ -37,7 +38,7 @@ void createTransTexspace(TransInfo *t)
ID *id;
char *texflag;
- ob = OBACT(view_layer);
+ ob = BKE_view_layer_active_object_get(view_layer);
if (ob == NULL) { /* Shouldn't logically happen, but still. */
return;
@@ -86,11 +87,11 @@ void createTransTexspace(TransInfo *t)
/** \name Recalc Data object
* \{ */
-void recalcData_texspace(TransInfo *t)
+static void recalcData_texspace(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -106,3 +107,10 @@ void recalcData_texspace(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_ObjectTexSpace = {
+ /* flags */ 0,
+ /* createTransData */ createTransTexspace,
+ /* recalcData */ recalcData_texspace,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_paintcurve.c b/source/blender/editors/transform/transform_convert_paintcurve.c
index b2566016496..61b1cb9493b 100644
--- a/source/blender/editors/transform/transform_convert_paintcurve.c
+++ b/source/blender/editors/transform/transform_convert_paintcurve.c
@@ -108,7 +108,7 @@ static void PaintCurvePointToTransData(PaintCurvePoint *pcp,
}
}
-void createTransPaintCurveVerts(bContext *C, TransInfo *t)
+static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
{
Paint *paint = BKE_paint_get_active_from_context(C);
PaintCurve *pc;
@@ -188,7 +188,7 @@ void createTransPaintCurveVerts(bContext *C, TransInfo *t)
/** \name Paint Curve Transform Flush
* \{ */
-void flushTransPaintCurve(TransInfo *t)
+static void flushTransPaintCurve(TransInfo *t)
{
int i;
@@ -204,3 +204,10 @@ void flushTransPaintCurve(TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_PaintCurve = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransPaintCurveVerts,
+ /* recalcData */ flushTransPaintCurve,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index d7b0f378c8a..354402a305f 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -13,6 +13,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -28,13 +29,13 @@
/** \name Particle Edit Transform Creation
* \{ */
-void createTransParticleVerts(TransInfo *t)
+static void createTransParticleVerts(bContext *UNUSED(C), TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = NULL;
TransDataExtension *tx;
- Object *ob = OBACT(t->view_layer);
+ Object *ob = BKE_view_layer_active_object_get(t->view_layer);
ParticleEditSettings *pset = PE_settings(t->scene);
PTCacheEdit *edit = PE_get_current(t->depsgraph, t->scene, ob);
ParticleSystem *psys = NULL;
@@ -183,7 +184,7 @@ static void flushTransParticles(TransInfo *t)
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
PTCacheEdit *edit = PE_get_current(t->depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
PTCacheEditPoint *point;
@@ -223,7 +224,7 @@ static void flushTransParticles(TransInfo *t)
}
}
- PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
+ PE_update_object(t->depsgraph, scene, BKE_view_layer_active_object_get(view_layer), 1);
BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
}
@@ -235,12 +236,19 @@ static void flushTransParticles(TransInfo *t)
/** \name Recalc Transform Particles Data
* \{ */
-void recalcData_particles(TransInfo *t)
+static void recalcData_particles(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
flushTransParticles(t);
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Particle = {
+ /* flags */ T_POINTS,
+ /* createTransData */ createTransParticleVerts,
+ /* recalcData */ recalcData_particles,
+ /* special_aftertrans_update */ NULL,
+};
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
index 5bf6bfa8644..86dc9f42b6b 100644
--- a/source/blender/editors/transform/transform_convert_sculpt.c
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -10,6 +10,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -23,7 +24,7 @@
/** \name Sculpt Transform Creation
* \{ */
-void createTransSculpt(bContext *C, TransInfo *t)
+static void createTransSculpt(bContext *C, TransInfo *t)
{
TransData *td;
@@ -33,7 +34,7 @@ void createTransSculpt(bContext *C, TransInfo *t)
return;
}
- Object *ob = OBACT(t->view_layer);
+ Object *ob = BKE_view_layer_active_object_get(t->view_layer);
SculptSession *ss = ob->sculpt;
{
@@ -85,7 +86,7 @@ void createTransSculpt(bContext *C, TransInfo *t)
copy_m3_m4(td->axismtx, ob->obmat);
BLI_assert(!(t->options & CTX_PAINT_CURVE));
- ED_sculpt_init_transform(C, ob);
+ ED_sculpt_init_transform(C, ob, t->undo_name);
}
/** \} */
@@ -94,13 +95,13 @@ void createTransSculpt(bContext *C, TransInfo *t)
/** \name Recalc Data object
* \{ */
-void recalcData_sculpt(TransInfo *t)
+static void recalcData_sculpt(TransInfo *t)
{
- Object *ob = OBACT(t->view_layer);
+ Object *ob = BKE_view_layer_active_object_get(t->view_layer);
ED_sculpt_update_modal_transform(t->context, ob);
}
-void special_aftertrans_update__sculpt(bContext *C, TransInfo *t)
+static void special_aftertrans_update__sculpt(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
if (!BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
@@ -108,9 +109,16 @@ void special_aftertrans_update__sculpt(bContext *C, TransInfo *t)
return;
}
- Object *ob = OBACT(t->view_layer);
+ Object *ob = BKE_view_layer_active_object_get(t->view_layer);
BLI_assert(!(t->options & CTX_PAINT_CURVE));
ED_sculpt_end_transform(C, ob);
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Sculpt = {
+ /* flags */ 0,
+ /* createTransData */ createTransSculpt,
+ /* recalcData */ recalcData_sculpt,
+ /* special_aftertrans_update */ special_aftertrans_update__sculpt,
+};
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 226b0f84f14..eefc9d0cc2a 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -90,9 +90,9 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag)
if (t->mode == TFM_TIME_EXTEND) {
/* *** Extend Transform *** */
- int cfra = CFRA;
- int left = SEQ_time_left_handle_frame_get(seq);
- int right = SEQ_time_right_handle_frame_get(seq);
+ int cfra = scene->r.cfra;
+ int left = SEQ_time_left_handle_frame_get(scene, seq);
+ int right = SEQ_time_right_handle_frame_get(scene, seq);
if (((seq->flag & SELECT) == 0 || SEQ_transform_is_locked(channels, seq))) {
*r_count = 0;
@@ -163,8 +163,13 @@ static int SeqTransCount(TransInfo *t, ListBase *seqbase)
return tot;
}
-static TransData *SeqToTransData(
- TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
+static TransData *SeqToTransData(Scene *scene,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataSeq *tdsq,
+ Sequence *seq,
+ int flag,
+ int sel_flag)
{
int start_left;
@@ -173,16 +178,16 @@ static TransData *SeqToTransData(
/* Use seq_tx_get_final_left() and an offset here
* so transform has the left hand location of the strip.
* tdsq->start_offset is used when flushing the tx data back */
- start_left = SEQ_time_left_handle_frame_get(seq);
+ start_left = SEQ_time_left_handle_frame_get(scene, seq);
td2d->loc[0] = start_left;
tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
break;
case SEQ_LEFTSEL:
- start_left = SEQ_time_left_handle_frame_get(seq);
+ start_left = SEQ_time_left_handle_frame_get(scene, seq);
td2d->loc[0] = start_left;
break;
case SEQ_RIGHTSEL:
- td2d->loc[0] = SEQ_time_right_handle_frame_get(seq);
+ td2d->loc[0] = SEQ_time_right_handle_frame_get(scene, seq);
break;
}
@@ -227,6 +232,7 @@ static int SeqToTransData_build(
TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
{
Sequence *seq;
+ Scene *scene = t->scene;
int count, flag;
int tot = 0;
@@ -238,16 +244,16 @@ static int SeqToTransData_build(
if (flag & SELECT) {
if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
if (flag & SEQ_LEFTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
+ SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
tot++;
}
if (flag & SEQ_RIGHTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
+ SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
tot++;
}
}
else {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
+ SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SELECT);
tot++;
}
}
@@ -275,7 +281,7 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
/* Handle pre-existing overlapping strips even when operator is canceled.
* This is necessary for SEQUENCER_OT_duplicate_move macro for example. */
- if (SEQ_transform_test_overlap(seqbase, seq)) {
+ if (SEQ_transform_test_overlap(t->scene, seqbase, seq)) {
SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene);
}
}
@@ -318,7 +324,8 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc);
- SEQ_collection_expand(seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(
+ t->scene, seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
@@ -363,11 +370,11 @@ typedef enum SeqInputSide {
SEQ_INPUT_RIGHT = 1,
} SeqInputSide;
-static Sequence *effect_input_get(Sequence *effect, SeqInputSide side)
+static Sequence *effect_input_get(const Scene *scene, Sequence *effect, SeqInputSide side)
{
Sequence *input = effect->seq1;
- if (effect->seq2 && (SEQ_time_left_handle_frame_get(effect->seq2) -
- SEQ_time_left_handle_frame_get(effect->seq1)) *
+ if (effect->seq2 && (SEQ_time_left_handle_frame_get(scene, effect->seq2) -
+ SEQ_time_left_handle_frame_get(scene, effect->seq1)) *
side >
0) {
input = effect->seq2;
@@ -375,12 +382,12 @@ static Sequence *effect_input_get(Sequence *effect, SeqInputSide side)
return input;
}
-static Sequence *effect_base_input_get(Sequence *effect, SeqInputSide side)
+static Sequence *effect_base_input_get(const Scene *scene, Sequence *effect, SeqInputSide side)
{
Sequence *input = effect, *seq_iter = effect;
while (seq_iter != NULL) {
input = seq_iter;
- seq_iter = effect_input_get(seq_iter, side);
+ seq_iter = effect_input_get(scene, seq_iter, side);
}
return input;
}
@@ -400,7 +407,7 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
SeqCollection *strips_no_handles = query_selected_strips_no_handles(seqbase);
/* Selection is needed as reference for related strips. */
SeqCollection *dependent = SEQ_collection_duplicate(strips_no_handles);
- SEQ_collection_expand(seqbase, strips_no_handles, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(t->scene, seqbase, strips_no_handles, SEQ_query_strip_effect_chain);
bool strip_added = true;
while (strip_added) {
@@ -430,7 +437,7 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
* With single input effect, it is less likely desirable to move animation. */
SeqCollection *selected_strips = SEQ_query_selected_strips(seqbase);
- SEQ_collection_expand(seqbase, selected_strips, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(t->scene, seqbase, selected_strips, SEQ_query_strip_effect_chain);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, selected_strips) {
/* Check only 2 input effects. */
@@ -439,8 +446,8 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
}
/* Find immediate base inputs(left and right side). */
- Sequence *input_left = effect_base_input_get(seq, SEQ_INPUT_LEFT);
- Sequence *input_right = effect_base_input_get(seq, SEQ_INPUT_RIGHT);
+ Sequence *input_left = effect_base_input_get(t->scene, seq, SEQ_INPUT_LEFT);
+ Sequence *input_right = effect_base_input_get(t->scene, seq, SEQ_INPUT_RIGHT);
if ((input_left->flag & SEQ_RIGHTSEL) != 0 && (input_right->flag & SEQ_LEFTSEL) != 0) {
SEQ_collection_append_strip(seq, dependent);
@@ -458,7 +465,7 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
return dependent;
}
-void createTransSeqData(TransInfo *t)
+static void createTransSeqData(bContext *UNUSED(C), TransInfo *t)
{
Scene *scene = t->scene;
Editing *ed = SEQ_editing_get(t->scene);
@@ -482,7 +489,7 @@ void createTransSeqData(TransInfo *t)
}
tc->custom.type.free_cb = freeSeqData;
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
count = SeqTransCount(t, ed->seqbasep);
@@ -571,6 +578,8 @@ static void flushTransSeq(TransInfo *t)
TransDataSeq *tdsq = NULL;
Sequence *seq;
+ Scene *scene = t->scene;
+
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* This is calculated for offsetting animation of effects that change position with inputs.
@@ -594,7 +603,7 @@ static void flushTransSeq(TransInfo *t)
case SELECT: {
if (SEQ_transform_sequence_can_be_translated(seq)) {
offset = new_frame - tdsq->start_offset - seq->start;
- SEQ_transform_translate_sequence(t->scene, seq, offset);
+ SEQ_transform_translate_sequence(scene, seq, offset);
if (abs(offset) > abs(max_offset)) {
max_offset = offset;
}
@@ -604,24 +613,22 @@ static void flushTransSeq(TransInfo *t)
break;
}
case SEQ_LEFTSEL: { /* No vertical transform. */
- int old_startdisp = SEQ_time_left_handle_frame_get(seq);
+ int old_startdisp = SEQ_time_left_handle_frame_get(scene, seq);
SEQ_time_left_handle_frame_set(t->scene, seq, new_frame);
- SEQ_transform_handle_xlimits(
- t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(t->scene, seq);
- if (abs(SEQ_time_left_handle_frame_get(seq) - old_startdisp) > abs(max_offset)) {
- max_offset = SEQ_time_left_handle_frame_get(seq) - old_startdisp;
+
+ if (abs(SEQ_time_left_handle_frame_get(scene, seq) - old_startdisp) > abs(max_offset)) {
+ max_offset = SEQ_time_left_handle_frame_get(scene, seq) - old_startdisp;
}
break;
}
case SEQ_RIGHTSEL: { /* No vertical transform. */
- int old_enddisp = SEQ_time_right_handle_frame_get(seq);
+ int old_enddisp = SEQ_time_right_handle_frame_get(scene, seq);
SEQ_time_right_handle_frame_set(t->scene, seq, new_frame);
- SEQ_transform_handle_xlimits(
- t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(t->scene, seq);
- if (abs(SEQ_time_right_handle_frame_get(seq) - old_enddisp) > abs(max_offset)) {
- max_offset = SEQ_time_right_handle_frame_get(seq) - old_enddisp;
+
+ if (abs(SEQ_time_right_handle_frame_get(scene, seq) - old_enddisp) > abs(max_offset)) {
+ max_offset = SEQ_time_right_handle_frame_get(scene, seq) - old_enddisp;
}
break;
}
@@ -638,12 +645,13 @@ static void flushTransSeq(TransInfo *t)
/* need to do the overlap check in a new loop otherwise adjacent strips
* will not be updated and we'll get false positives */
SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc);
- SEQ_collection_expand(seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(
+ t->scene, seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
/* test overlap, displays red outline */
seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, seqbasep, seq)) {
seq->flag |= SEQ_OVERLAP;
}
}
@@ -651,7 +659,7 @@ static void flushTransSeq(TransInfo *t)
SEQ_collection_free(transformed_strips);
}
-void recalcData_sequencer(TransInfo *t)
+static void recalcData_sequencer(TransInfo *t)
{
TransData *td;
int a;
@@ -681,7 +689,7 @@ void recalcData_sequencer(TransInfo *t)
/** \name Special After Transform Sequencer
* \{ */
-void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t)
+static void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t)
{
if (t->state == TRANS_CANCEL) {
return;
@@ -726,3 +734,10 @@ void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2])
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Sequencer = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransSeqData,
+ /* recalcData */ recalcData_sequencer,
+ /* special_aftertrans_update */ special_aftertrans_update__sequencer,
+};
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index 741b1e35838..d7f6a2ab366 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -105,7 +105,7 @@ static void freeSeqData(TransInfo *UNUSED(t),
MEM_freeN(td->extra);
}
-void createTransSeqImageData(TransInfo *t)
+static void createTransSeqImageData(bContext *UNUSED(C), TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
const SpaceSeq *sseq = t->area->spacedata.first;
@@ -123,7 +123,8 @@ void createTransSeqImageData(TransInfo *t)
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, t->scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(
+ t->scene, channels, seqbase, t->scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
const int count = SEQ_collection_len(strips);
@@ -172,25 +173,25 @@ static bool autokeyframe_sequencer_image(bContext *C,
bool changed = false;
if (do_rot) {
prop = RNA_struct_find_property(&ptr, "rotation");
- changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
}
if (do_loc) {
prop = RNA_struct_find_property(&ptr, "offset_x");
- changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
prop = RNA_struct_find_property(&ptr, "offset_y");
- changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
}
if (do_scale) {
prop = RNA_struct_find_property(&ptr, "scale_x");
- changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
prop = RNA_struct_find_property(&ptr, "scale_y");
- changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false);
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
}
return changed;
}
-void recalcData_sequencer_image(TransInfo *t)
+static void recalcData_sequencer_image(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
TransData *td = NULL;
@@ -246,7 +247,7 @@ void recalcData_sequencer_image(TransInfo *t)
}
}
-void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
+static void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -270,3 +271,10 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
}
}
}
+
+TransConvertTypeInfo TransConvertType_SequencerImage = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransSeqImageData,
+ /* recalcData */ recalcData_sequencer_image,
+ /* special_aftertrans_update */ special_aftertrans_update__sequencer_image,
+};
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index d447cd71a40..c0c660289a5 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -518,7 +518,7 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
}
}
-void createTransTrackingData(bContext *C, TransInfo *t)
+static void createTransTrackingData(bContext *C, TransInfo *t)
{
ARegion *region = CTX_wm_region(C);
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -694,7 +694,7 @@ static void flushTransTracking(TransInfo *t)
}
}
-void recalcData_tracking(TransInfo *t)
+static void recalcData_tracking(TransInfo *t)
{
SpaceClip *sc = t->area->spacedata.first;
@@ -747,7 +747,7 @@ void recalcData_tracking(TransInfo *t)
/** \name Special After Transform Tracking
* \{ */
-void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
+static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -790,3 +790,10 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
}
/** \} */
+
+TransConvertTypeInfo TransConvertType_Tracking = {
+ /* flags */ (T_POINTS | T_2D_EDIT),
+ /* createTransData */ createTransTrackingData,
+ /* recalcData */ recalcData_tracking,
+ /* special_aftertrans_update */ special_aftertrans_update__movieclip,
+};
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index 42942493dc3..b5a8decc390 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -116,7 +116,7 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd
/* Dashed lines first. */
if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
GPU_line_width(DASH_WIDTH);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
immUniform1i("colors_len", 0); /* "simple" mode */
immUniformThemeColor3(TH_VIEW_OVERLAY);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index e45cac36736..9ba5c9ebfe8 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -176,7 +176,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
{
Scene *sce = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
ToolSettings *ts = CTX_data_tool_settings(C);
ARegion *region = CTX_wm_region(C);
@@ -333,7 +333,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = area->spacedata.first;
- if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
+ if (ED_space_image_show_uvedit(sima, BKE_view_layer_active_object_get(t->view_layer))) {
/* UV transform */
}
else if (sima->mode == SI_MODE_MASK) {
@@ -555,7 +555,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else {
/* Release confirms preference should not affect node editor (T69288, T70504). */
- if (ISMOUSE(t->launch_event) &&
+ if (ISMOUSE_BUTTON(t->launch_event) &&
((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) {
/* Global "release confirm" on mouse bindings */
t->flag |= T_RELEASE_CONFIRM;
@@ -1067,7 +1067,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
else if (t->options & CTX_POSE_BONE) {
ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) {
mul_m4_v3(ob->obmat, r_center);
return true;
@@ -1084,8 +1084,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
else {
/* object mode */
ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
- Base *base = BASACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
+ Base *base = view_layer->basact;
if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
copy_v3_v3(r_center, ob->obmat[3]);
return true;
@@ -1132,6 +1132,33 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
}
}
+static void calculateZfac(TransInfo *t)
+{
+ /* ED_view3d_calc_zfac() defines a factor for perspective depth correction,
+ * used in ED_view3d_win_to_delta() */
+
+ /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
+ * and never used in other cases.
+ *
+ * We need special case here as well, since ED_view3d_calc_zfac will crash when called
+ * for a region different from RGN_TYPE_WINDOW.
+ */
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global);
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->area->spacedata.first;
+ t->zfac = 1.0f / sima->zoom;
+ }
+ else if (t->region) {
+ View2D *v2d = &t->region->v2d;
+ /* Get zoom fac the same way as in
+ * `ui_view2d_curRect_validate_resize` - better keep in sync! */
+ const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
+ t->zfac = 1.0f / zoomx;
+ }
+}
+
void calculateCenter(TransInfo *t)
{
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
@@ -1166,22 +1193,46 @@ void calculateCenter(TransInfo *t)
}
}
- if (t->spacetype == SPACE_VIEW3D) {
- /* #ED_view3d_calc_zfac() defines a factor for perspective depth correction,
- * used in #ED_view3d_win_to_delta(). */
+ calculateZfac(t);
+}
- /* NOTE: `t->zfac` is only used #convertViewVec only in cases operator was invoked in
- * #RGN_TYPE_WINDOW and never used in other cases.
- *
- * We need special case here as well, since #ED_view3d_calc_zfac will crash when called
- * for a region different from #RGN_TYPE_WINDOW. */
- if (t->region->regiontype == RGN_TYPE_WINDOW) {
- t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global);
+/* Called every time the view changes due to navigation.
+ * Adjusts the mouse position relative to the object. */
+void tranformViewUpdate(TransInfo *t)
+{
+ float zoom_prev = t->zfac;
+ float zoom_new;
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ if (!t->persp) {
+ zoom_prev *= len_v3(t->persinv[0]);
}
- else {
- t->zfac = 0.0f;
+
+ setTransformViewMatrices(t);
+ calculateZfac(t);
+
+ zoom_new = t->zfac;
+ if (!t->persp) {
+ zoom_new *= len_v3(t->persinv[0]);
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(t->orient); i++) {
+ if (t->orient[i].type == V3D_ORIENT_VIEW) {
+ copy_m3_m4(t->orient[i].matrix, t->viewinv);
+ normalize_m3(t->orient[i].matrix);
+ if (t->orient_curr == i) {
+ copy_m3_m3(t->spacemtx, t->orient[i].matrix);
+ invert_m3_m3_safe_ortho(t->spacemtx_inv, t->spacemtx);
+ }
+ }
}
}
+ else {
+ calculateZfac(t);
+ zoom_new = t->zfac;
+ }
+
+ calculateCenter2D(t);
+ transform_input_update(t, zoom_prev / zoom_new);
}
void calculatePropRatio(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 838b40c2040..426b338f8a7 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -247,7 +247,7 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
int selected_strips = SEQ_collection_len(strips);
if (selected_strips > 0) {
@@ -299,7 +299,7 @@ static int gizmo2d_calc_transform_orientation(const bContext *C)
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
bool use_local_orient = SEQ_collection_len(strips) == 1;
@@ -322,7 +322,7 @@ static float gizmo2d_calc_rotation(const bContext *C)
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
if (SEQ_collection_len(strips) == 1) {
@@ -348,7 +348,7 @@ static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
bool has_select = SEQ_collection_len(strips) != 0;
@@ -387,7 +387,8 @@ static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(
+ scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
has_select = SEQ_collection_len(strips) != 0;
SEQ_collection_free(strips);
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 5b749e05052..7b6c0e1654d 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -639,7 +639,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
(params->orientation_index - 1) :
BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
Object *obpose = BKE_object_pose_armature_get(ob);
@@ -1014,8 +1014,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
else {
/* we need the one selected object, if its not active */
- base = BASACT(view_layer);
- ob = OBACT(view_layer);
+ base = view_layer->basact;
+ ob = BKE_view_layer_active_object_get(view_layer);
if (base && ((base->flag & BASE_SELECTED) == 0)) {
ob = NULL;
}
@@ -1103,7 +1103,7 @@ static void gizmo_prepare_mat(const bContext *C,
/* pass */
}
else {
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob != NULL) {
if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index 131a7fd517f..a3b5fd2c575 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -261,7 +261,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
copy_m3_m3(ggd->data.normal_mat3, tbounds_normal.axis);
}
- /* TODO(campbell): run second since this modifies the 3D view, it should not. */
+ /* TODO(@campbellbarton): run second since this modifies the 3D view, it should not. */
if (!ED_transform_calc_gizmo_stats(C,
&(struct TransformCalcParams){
.orientation_index = ggd->data.orientation_index + 1,
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 3b320ff51d5..38dbe742279 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BKE_context.h"
@@ -18,6 +19,7 @@
#include "WM_types.h"
#include "transform.h"
+#include "transform_mode.h"
#include "MEM_guardedalloc.h"
@@ -251,11 +253,8 @@ void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[
/** \name Setup & Handle Mouse Input
* \{ */
-void initMouseInput(TransInfo *UNUSED(t),
- MouseInput *mi,
- const float center[2],
- const int mval[2],
- const bool precision)
+void initMouseInput(
+ TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision)
{
mi->factor = 0;
mi->precision = precision;
@@ -266,14 +265,20 @@ void initMouseInput(TransInfo *UNUSED(t),
mi->imval[0] = mval[0];
mi->imval[1] = mval[1];
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ float delta[3] = {mval[0] - center[0], mval[1] - center[1]};
+ ED_view3d_win_to_delta(t->region, delta, t->zfac, delta);
+ add_v3_v3v3(mi->imval_unproj, t->center_global, delta);
+ }
+
mi->post = NULL;
}
static void calcSpringFactor(MouseInput *mi)
{
- mi->factor = sqrtf(
- ((float)(mi->center[1] - mi->imval[1])) * ((float)(mi->center[1] - mi->imval[1])) +
- ((float)(mi->center[0] - mi->imval[0])) * ((float)(mi->center[0] - mi->imval[0])));
+ float mdir[2] = {(float)(mi->center[1] - mi->imval[1]), (float)(mi->center[0] - mi->imval[0])};
+
+ mi->factor = len_v2(mdir);
if (mi->factor == 0.0f) {
mi->factor = 1.0f; /* prevent Inf */
@@ -441,4 +446,52 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp
}
}
+void transform_input_update(TransInfo *t, const float fac)
+{
+ MouseInput *mi = &t->mouse;
+ t->mouse.factor *= fac;
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ projectIntView(t, mi->imval_unproj, mi->imval);
+ }
+ else {
+ int offset[2], center_2d_int[2] = {mi->center[0], mi->center[1]};
+ sub_v2_v2v2_int(offset, mi->imval, center_2d_int);
+ offset[0] *= fac;
+ offset[1] *= fac;
+
+ center_2d_int[0] = t->center2d[0];
+ center_2d_int[1] = t->center2d[1];
+ add_v2_v2v2_int(mi->imval, center_2d_int, offset);
+ }
+
+ float center_old[2];
+ copy_v2_v2(center_old, mi->center);
+ copy_v2_v2(mi->center, t->center2d);
+
+ if (mi->use_virtual_mval) {
+ /* Update accumulator. */
+ double mval_delta[2];
+ sub_v2_v2v2_db(mval_delta, mi->virtual_mval.accum, mi->virtual_mval.prev);
+ mval_delta[0] *= fac;
+ mval_delta[1] *= fac;
+ copy_v2_v2_db(mi->virtual_mval.accum, mi->virtual_mval.prev);
+ add_v2_v2_db(mi->virtual_mval.accum, mval_delta);
+ }
+
+ if (ELEM(mi->apply, InputAngle, InputAngleSpring)) {
+ float offset_center[2];
+ sub_v2_v2v2(offset_center, mi->center, center_old);
+ struct InputAngle_Data *data = mi->data;
+ data->mval_prev[0] += offset_center[0];
+ data->mval_prev[1] += offset_center[1];
+ }
+
+ if (t->mode == TFM_EDGE_SLIDE) {
+ transform_mode_edge_slide_reproject_input(t);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ transform_mode_vert_slide_reproject_input(t);
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 83f1bd35f81..10ea022757d 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -292,6 +292,9 @@ void constraintTransLim(const TransInfo *t, TransData *td)
continue;
}
+ /* Initialize the custom space for use in calculating the matrices. */
+ BKE_constraint_custom_object_space_init(&cob, con);
+
/* get constraint targets if needed */
BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
@@ -549,18 +552,14 @@ void ElementRotation_ex(const TransInfo *t,
mul_m3_m3m3(totmat, mat, td->mtx);
mul_m3_m3m3(smat, td->smtx, totmat);
- /* apply gpencil falloff */
+ /* Apply gpencil falloff. */
if (t->options & CTX_GPENCIL_STROKES) {
bGPDstroke *gps = (bGPDstroke *)td->extra;
- float sx = smat[0][0];
- float sy = smat[1][1];
- float sz = smat[2][2];
-
- mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
- /* fix scale */
- smat[0][0] = sx;
- smat[1][1] = sy;
- smat[2][2] = sz;
+ if (gps->runtime.multi_frame_falloff != 1.0f) {
+ float ident_mat[3][3];
+ unit_m3(ident_mat);
+ interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff);
+ }
}
sub_v3_v3v3(vec, td->iloc, center);
@@ -945,7 +944,11 @@ void ElementResize(const TransInfo *t,
if (td->ext && td->ext->size) {
float fsize[3];
- if (ELEM(t->data_type, TC_SCULPT, TC_OBJECT, TC_OBJECT_TEXSPACE, TC_POSE)) {
+ if (ELEM(t->data_type,
+ &TransConvertType_Sculpt,
+ &TransConvertType_Object,
+ &TransConvertType_ObjectTexSpace,
+ &TransConvertType_Pose)) {
float obsizemat[3][3];
/* Reorient the size mat to fit the oriented object. */
mul_m3_m3m3(obsizemat, tmat, td->axismtx);
@@ -1205,13 +1208,13 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
break;
}
- if (t->data_type == TC_MESH_VERTS) {
+ if (t->data_type == &TransConvertType_Mesh) {
/* Init Custom Data correction.
* Ideally this should be called when creating the TransData. */
transform_convert_mesh_customdatacorrect_init(t);
}
- /* TODO(germano): Some of these operations change the `t->mode`.
+ /* TODO(@germano): Some of these operations change the `t->mode`.
* This can be bad for Redo. */
// BLI_assert(t->mode == mode);
}
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index eac6734ed88..063de87ebb2 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -117,6 +117,7 @@ void drawEdgeSlide(TransInfo *t);
void initEdgeSlide_ex(
TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
void initEdgeSlide(TransInfo *t);
+void transform_mode_edge_slide_reproject_input(TransInfo *t);
/* transform_mode_gpopacity.c */
@@ -191,3 +192,4 @@ void initTranslation(TransInfo *t);
void drawVertSlide(TransInfo *t);
void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
void initVertSlide(TransInfo *t);
+void transform_mode_vert_slide_reproject_input(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index acc6b20810f..a48f84ef0bc 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -262,7 +262,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
+values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
}
- /* TODO(campbell): xform, compensate object center. */
+ /* TODO(@campbellbarton): xform, compensate object center. */
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
float warp_sta_local[3];
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index aa4d608de04..f7f9e14b8ac 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -64,10 +64,8 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (td->val) {
*td->val = td->ival * ratio;
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) {
- *td->val = 0.001f;
- }
+ *td->val = interpf(*td->val, td->ival, td->factor);
+ CLAMP_MIN(*td->val, 0.0f);
}
}
}
@@ -93,10 +91,6 @@ void initCurveShrinkFatten(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
-#endif
-
t->flag |= T_NO_CONSTRAINT;
}
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
index 987d8396907..e96e74b596c 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -44,16 +44,11 @@ static void transdata_elem_bevel_weight(const TransInfo *UNUSED(t),
TransData *td,
const float weight)
{
- if (td->val == NULL) {
+ if (td->loc == NULL) {
return;
}
- *td->val = td->ival + weight * td->factor;
- if (*td->val < 0.0f) {
- *td->val = 0.0f;
- }
- if (*td->val > 1.0f) {
- *td->val = 1.0f;
- }
+ *td->loc = td->iloc[0] + weight * td->factor;
+ CLAMP(*td->loc, 0.0f, 1.0f);
}
static void transdata_elem_bevel_weight_fn(void *__restrict iter_data_v,
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index f1acc2a4c9a..1a3ccf30387 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -44,17 +44,12 @@ static void transdata_elem_crease(const TransInfo *UNUSED(t),
TransData *td,
const float crease)
{
- if (td->val == NULL) {
+ if (td->loc == NULL) {
return;
}
- *td->val = td->ival + crease * td->factor;
- if (*td->val < 0.0f) {
- *td->val = 0.0f;
- }
- if (*td->val > 1.0f) {
- *td->val = 1.0f;
- }
+ *td->loc = td->iloc[0] + crease * td->factor;
+ CLAMP(*td->loc, 0.0f, 1.0f);
}
static void transdata_elem_crease_fn(void *__restrict iter_data_v,
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
index 2327aa4e9c4..8d790b4699b 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -84,7 +84,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
transform_snap_increment(t, &angle);
- applySnapping(t, &angle);
+ applySnappingAsGroup(t, &angle);
applyNumInput(&t->num, &angle);
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 9a732562709..5ca1fdf75c6 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -87,7 +87,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
}
else {
copy_v2_v2(values_final, t->values);
- applySnapping(t, values_final);
+ applySnappingAsGroup(t, values_final);
transform_convert_sequencer_channel_clamp(t, values_final);
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index b8e9a0d1a4d..85285e38bdd 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -292,6 +292,73 @@ static BMLoop *get_next_loop(
return NULL;
}
+static void edge_slide_projmat_get(TransInfo *t, TransDataContainer *tc, float r_projectMat[4][4])
+{
+ RegionView3D *rv3d = NULL;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* Background mode support. */
+ rv3d = t->region ? t->region->regiondata : NULL;
+ }
+
+ if (!rv3d) {
+ /* Ok, let's try to survive this. */
+ unit_m4(r_projectMat);
+ }
+ else {
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, r_projectMat);
+ }
+}
+
+static void edge_slide_pair_project(TransDataEdgeSlideVert *sv,
+ ARegion *region,
+ float projectMat[4][4],
+ float r_sco_a[3],
+ float r_sco_b[3])
+{
+ BMVert *v = sv->v;
+
+ if (sv->v_side[1]) {
+ ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, r_sco_b, projectMat);
+ }
+ else {
+ add_v3_v3v3(r_sco_b, v->co, sv->dir_side[1]);
+ ED_view3d_project_float_v3_m4(region, r_sco_b, r_sco_b, projectMat);
+ }
+
+ if (sv->v_side[0]) {
+ ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, r_sco_a, projectMat);
+ }
+ else {
+ add_v3_v3v3(r_sco_a, v->co, sv->dir_side[0]);
+ ED_view3d_project_float_v3_m4(region, r_sco_a, r_sco_a, projectMat);
+ }
+}
+
+static void edge_slide_data_init_mval(MouseInput *mi, EdgeSlideData *sld, float *mval_dir)
+{
+ /* Possible all of the edge loops are pointing directly at the view. */
+ if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
+ mval_dir[0] = 0.0f;
+ mval_dir[1] = 100.0f;
+ }
+
+ float mval_start[2], mval_end[2];
+
+ /* Zero out Start. */
+ zero_v2(mval_start);
+
+ /* dir holds a vector along edge loop */
+ copy_v2_v2(mval_end, mval_dir);
+ mul_v2_fl(mval_end, 0.5f);
+
+ sld->mval_start[0] = mi->imval[0] + mval_start[0];
+ sld->mval_start[1] = mi->imval[1] + mval_start[1];
+
+ sld->mval_end[0] = mi->imval[0] + mval_end[0];
+ sld->mval_end[1] = mi->imval[1] + mval_end[1];
+}
+
/**
* Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
*/
@@ -308,29 +375,20 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
ARegion *region = t->region;
View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
float projectMat[4][4];
BMBVHTree *bmbvh;
/* only for use_calc_direction */
float(*loop_dir)[3] = NULL, *loop_maxdist = NULL;
- float mval_start[2], mval_end[2];
float mval_dir[3], dist_best_sq;
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
v3d = t->area ? t->area->spacedata.first : NULL;
- rv3d = t->region ? t->region->regiondata : NULL;
}
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
- }
+ edge_slide_projmat_get(t, tc, projectMat);
if (use_occlude_geometry) {
bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
@@ -379,21 +437,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
continue;
}
- if (sv->v_side[1]) {
- ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat);
- }
- else {
- add_v3_v3v3(sco_b, v->co, sv->dir_side[1]);
- ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat);
- }
-
- if (sv->v_side[0]) {
- ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat);
- }
- else {
- add_v3_v3v3(sco_a, v->co, sv->dir_side[0]);
- ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat);
- }
+ edge_slide_pair_project(sv, region, projectMat, sco_a, sco_b);
/* global direction */
dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
@@ -433,24 +477,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
MEM_freeN(loop_maxdist);
}
- /* possible all of the edge loops are pointing directly at the view */
- if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
- mval_dir[0] = 0.0f;
- mval_dir[1] = 100.0f;
- }
-
- /* zero out start */
- zero_v2(mval_start);
-
- /* dir holds a vector along edge loop */
- copy_v2_v2(mval_end, mval_dir);
- mul_v2_fl(mval_end, 0.5f);
-
- sld->mval_start[0] = t->mval[0] + mval_start[0];
- sld->mval_start[1] = t->mval[1] + mval_start[1];
-
- sld->mval_end[0] = t->mval[0] + mval_end[0];
- sld->mval_end[1] = t->mval[1] + mval_end[1];
+ edge_slide_data_init_mval(&t->mouse, sld, mval_dir);
if (bmbvh) {
BKE_bmbvh_free(bmbvh);
@@ -466,7 +493,6 @@ static void calcEdgeSlide_even(TransInfo *t,
if (sld->totsv > 0) {
ARegion *region = t->region;
- RegionView3D *rv3d = NULL;
float projectMat[4][4];
int i = 0;
@@ -475,18 +501,7 @@ static void calcEdgeSlide_even(TransInfo *t,
float dist_sq = 0;
float dist_min_sq = FLT_MAX;
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
- rv3d = t->region ? t->region->regiondata : NULL;
- }
-
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
- }
+ edge_slide_projmat_get(t, tc, projectMat);
for (i = 0; i < sld->totsv; i++, sv++) {
/* Set length */
@@ -1204,7 +1219,7 @@ void drawEdgeSlide(TransInfo *t)
immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
immBegin(GPU_PRIM_LINES, sld->totsv * 2);
- /* TODO(campbell): Loop over all verts. */
+ /* TODO(@campbellbarton): Loop over all verts. */
sv = sld->sv;
for (i = 0; i < sld->totsv; i++, sv++) {
float a[3], b[3];
@@ -1292,7 +1307,7 @@ static void edge_slide_snap_apply(TransInfo *t, float *value)
side_index = t_snap >= t_mid;
}
- if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
+ if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) {
float co_dir[3];
sub_v3_v3v3(co_dir, co_dest[side_index], co_orig);
normalize_v3(co_dir);
@@ -1444,7 +1459,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0] + t->values_modal_offset[0];
- applySnapping(t, &final);
+ applySnappingAsGroup(t, &final);
if (!validSnap(t)) {
transform_snap_increment(t, &final);
}
@@ -1553,3 +1568,32 @@ void initEdgeSlide(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Input Utilities
+ * \{ */
+
+void transform_mode_edge_slide_reproject_input(TransInfo *t)
+{
+ ARegion *region = t->region;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ if (sld) {
+ float projectMat[4][4];
+ edge_slide_projmat_get(t, tc, projectMat);
+
+ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+
+ float mval_dir[3], sco_a[3], sco_b[3];
+ edge_slide_pair_project(curr_sv, region, projectMat, sco_a, sco_b);
+ sub_v3_v3v3(mval_dir, sco_b, sco_a);
+ edge_slide_data_init_mval(&t->mouse, sld, mval_dir);
+ }
+ }
+
+ EdgeSlideData *sld = edgeSlideFirstGet(t);
+ setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 83dce17d104..8b9431b65ea 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -74,7 +74,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
if (td->val) {
*td->val = td->ival * ratio;
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ *td->val = interpf(*td->val, td->ival, td->factor);
CLAMP(*td->val, 0.0f, 1.0f);
}
}
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index 796d5c7ae9c..d8ec7d4ff50 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -74,7 +74,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (td->val) {
*td->val = td->ival * ratio;
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ *td->val = interpf(*td->val, td->ival, td->factor);
if (*td->val <= 0.0f) {
*td->val = 0.001f;
}
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 19a3deade63..e2ccf61796b 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -90,7 +90,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ *td->val = interpf(*td->val, td->ival, td->factor);
if (*td->val <= 0.0f) {
*td->val = 0.001f;
}
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index ffae651e4aa..70599c3577c 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -11,6 +11,7 @@
#include "BLI_task.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_unit.h"
#include "ED_screen.h"
@@ -84,6 +85,98 @@ static void ApplySnapResize(TransInfo *t, float vec[3])
}
}
+/**
+ * Find the correction for the scaling factor when "Constrain to Bounds" is active.
+ * \param numerator: How far the UV boundary (unit square) is from the origin of the scale.
+ * \param denominator: How far the AABB is from the origin of the scale.
+ * \param scale: Scale parameter to update.
+ */
+static void constrain_scale_to_boundary(const float numerator,
+ const float denominator,
+ float *scale)
+{
+ if (denominator == 0.0f) {
+ /* The origin of the scale is on the edge of the boundary. */
+ if (numerator < 0.0f) {
+ /* Negative scale will wrap around and put us outside the boundary. */
+ *scale = 0.0f; /* Hold at the boundary instead. */
+ }
+ return; /* Nothing else we can do without more info. */
+ }
+
+ const float correction = numerator / denominator;
+ if (correction < 0.0f || !isfinite(correction)) {
+ /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */
+ return;
+ }
+
+ if (denominator < 0.0f) {
+ /* Scale origin is outside boundary, only make scale bigger. */
+ if (*scale < correction) {
+ *scale = correction;
+ }
+ return;
+ }
+
+ /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */
+ if (*scale > correction) {
+ *scale = correction;
+ }
+}
+
+static bool clip_uv_transform_resize(TransInfo *t, float vec[2])
+{
+
+ /* Stores the coordinates of the closest UDIM tile.
+ * Also acts as an offset to the tile from the origin of UV space. */
+ float base_offset[2] = {0.0f, 0.0f};
+
+ /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
+ const SpaceImage *sima = t->area->spacedata.first;
+ BKE_image_find_nearest_tile_with_offset(sima->image, t->center_global, base_offset);
+
+ /* Assume no change is required. */
+ float scale = 1.0f;
+
+ /* Are we scaling U and V together, or just one axis? */
+ const bool adjust_u = !(t->con.mode & CON_AXIS1);
+ const bool adjust_v = !(t->con.mode & CON_AXIS0);
+ const bool use_local_center = transdata_check_local_center(t, t->around);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) {
+
+ /* Get scale origin. */
+ const float *scale_origin = use_local_center ? td->center : t->center_global;
+
+ /* Alias td->loc as min and max just in case we need to optimize later. */
+ const float *min = td->loc;
+ const float *max = td->loc;
+
+ if (adjust_u) {
+ /* Update U against the left border. */
+ constrain_scale_to_boundary(
+ scale_origin[0] - base_offset[0], scale_origin[0] - min[0], &scale);
+
+ /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */
+ constrain_scale_to_boundary(
+ base_offset[0] + t->aspect[0] - scale_origin[0], max[0] - scale_origin[0], &scale);
+ }
+
+ /* Do the same for the V co-ordinate. */
+ if (adjust_v) {
+ constrain_scale_to_boundary(
+ scale_origin[1] - base_offset[1], scale_origin[1] - min[1], &scale);
+
+ constrain_scale_to_boundary(
+ base_offset[1] + t->aspect[1] - scale_origin[1], max[1] - scale_origin[1], &scale);
+ }
+ }
+ }
+ vec[0] *= scale;
+ vec[1] *= scale;
+ return scale != 1.0f;
+}
+
static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
{
float mat[3][3];
@@ -105,7 +198,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
constraintNumInput(t, t->values_final);
}
- applySnapping(t, t->values_final);
+ applySnappingAsGroup(t, t->values_final);
}
size_to_mat3(mat, t->values_final);
@@ -157,7 +250,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
}
/* Evil hack - redo resize if clipping needed. */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) {
+ if (t->flag & T_CLIP_UV && clip_uv_transform_resize(t, t->values_final)) {
size_to_mat3(mat, t->values_final);
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index 94caaa288e5..f3186b21cb9 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -11,6 +11,7 @@
#include "BLI_task.h"
#include "BKE_context.h"
+#include "BKE_report.h"
#include "BKE_unit.h"
#include "ED_screen.h"
@@ -285,9 +286,72 @@ static void applyRotationValue(TransInfo *t,
}
}
+static bool uv_rotation_in_clip_bounds_test(const TransInfo *t, const float angle)
+{
+ const float cos_angle = cosf(angle);
+ const float sin_angle = sinf(angle);
+ const float *center = t->center_global;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+ if (td->factor < 1.0f) {
+ continue; /* Proportional edit, will get picked up in next phase. */
+ }
+
+ float uv[2];
+ sub_v2_v2v2(uv, td->iloc, center);
+ float pr[2];
+ pr[0] = cos_angle * uv[0] + sin_angle * uv[1];
+ pr[1] = -sin_angle * uv[0] + cos_angle * uv[1];
+ add_v2_v2(pr, center);
+ /* TODO: UDIM support. */
+ if (pr[0] < 0.0f || 1.0f < pr[0]) {
+ return false;
+ }
+ if (pr[1] < 0.0f || 1.0f < pr[1]) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool clip_uv_transform_rotate(const TransInfo *t, float *vec, float *vec_inside_bounds)
+{
+ float angle = vec[0];
+ if (uv_rotation_in_clip_bounds_test(t, angle)) {
+ vec_inside_bounds[0] = angle; /* Store for next iteration. */
+ return false; /* Nothing to do. */
+ }
+ float angle_inside_bounds = vec_inside_bounds[0];
+ if (!uv_rotation_in_clip_bounds_test(t, angle_inside_bounds)) {
+ return false; /* No known way to fix, may as well rotate anyway. */
+ }
+ const int max_i = 32; /* Limit iteration, mainly for debugging. */
+ for (int i = 0; i < max_i; i++) {
+ /* Binary search. */
+ const float angle_mid = (angle_inside_bounds + angle) / 2.0f;
+ if (angle_mid == angle_inside_bounds || angle_mid == angle) {
+ break; /* float precision reached. */
+ }
+ if (uv_rotation_in_clip_bounds_test(t, angle_mid)) {
+ angle_inside_bounds = angle_mid;
+ }
+ else {
+ angle = angle_mid;
+ }
+ }
+
+ vec_inside_bounds[0] = angle_inside_bounds; /* Store for next iteration. */
+ vec[0] = angle_inside_bounds; /* Update rotation angle. */
+ return true;
+}
+
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
{
- char str[UI_MAX_DRAW_STR];
float axis_final[3];
float final = t->values[0] + t->values_modal_offset[0];
@@ -304,7 +368,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
final = large_rotation_limit(final);
}
else {
- applySnapping(t, &final);
+ applySnappingAsGroup(t, &final);
if (!(activeSnap(t) && validSnap(t))) {
transform_snap_increment(t, &final);
}
@@ -312,13 +376,27 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
t->values_final[0] = final;
- headerRotation(t, str, sizeof(str), final);
-
const bool is_large_rotation = hasNumInput(&t->num);
applyRotationValue(t, final, axis_final, is_large_rotation);
+ if (t->flag & T_CLIP_UV) {
+ if (clip_uv_transform_rotate(t, t->values_final, t->values_inside_constraints)) {
+ applyRotationValue(t, t->values_final[0], axis_final, is_large_rotation);
+ }
+
+ /* In proportional edit it can happen that */
+ /* vertices in the radius of the brush end */
+ /* outside the clipping area */
+ /* XXX HACK - dg */
+ if (t->flag & T_PROP_EDIT) {
+ clipUVData(t);
+ }
+ }
+
recalcData(t);
+ char str[UI_MAX_DRAW_STR];
+ headerRotation(t, str, sizeof(str), t->values_final[0]);
ED_area_status_text(t->area, str);
}
@@ -343,6 +421,11 @@ static void applyRotationMatrix(TransInfo *t, float mat_xform[4][4])
void initRotation(TransInfo *t)
{
+ if (t->spacetype == SPACE_ACTION) {
+ BKE_report(t->reports, RPT_ERROR, "Rotation is not supported in the Dope Sheet Editor");
+ t->state = TRANS_CANCEL;
+ }
+
t->mode = TFM_ROTATION;
t->transform = applyRotation;
t->transform_matrix = applyRotationMatrix;
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 8099449ec23..bdbb66b72f4 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -99,7 +99,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
constraintNumInput(t, t->values_final);
}
- applySnapping(t, t->values_final);
+ applySnappingAsGroup(t, t->values_final);
}
size_to_mat3(mat_final, t->values_final);
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index 4130f6dc034..1474bc4591a 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -59,7 +59,7 @@ static void applyTimeScaleValue(TransInfo *t, float value)
* (this is only valid when not in NLA)
*/
AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float startx = CFRA;
+ float startx = scene->r.cfra;
float fac = value;
/* take proportional editing into account */
@@ -107,7 +107,7 @@ void initTimeScale(TransInfo *t)
t->mode = TFM_TIME_SCALE;
t->transform = applyTimeScale;
- /* recalculate center2d to use CFRA and mouse Y, since that's
+ /* recalculate center2d to use scene->r.cfra and mouse Y, since that's
* what is used in time scale */
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
t->center_global[0] = t->scene->r.cfra;
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 3c6b6ea4117..8f6ec7bd98f 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -16,6 +16,7 @@
#include "BLI_task.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_report.h"
#include "BKE_unit.h"
@@ -434,6 +435,48 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
custom_data->prev.rotate_mode = rotate_mode;
}
+static bool clip_uv_transform_translation(TransInfo *t, float vec[2])
+{
+ /* Stores the coordinates of the closest UDIM tile.
+ * Also acts as an offset to the tile from the origin of UV space. */
+ float base_offset[2] = {0.0f, 0.0f};
+
+ /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
+ const SpaceImage *sima = t->area->spacedata.first;
+ BKE_image_find_nearest_tile_with_offset(sima->image, t->center_global, base_offset);
+
+ float min[2], max[2];
+ min[0] = min[1] = FLT_MAX;
+ max[0] = max[1] = -FLT_MAX;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) {
+ minmax_v2v2_v2(min, max, td->loc);
+ }
+ }
+
+ bool result = false;
+ if (min[0] < base_offset[0]) {
+ vec[0] += base_offset[0] - min[0];
+ result = true;
+ }
+ else if (max[0] > base_offset[0] + t->aspect[0]) {
+ vec[0] -= max[0] - base_offset[0] - t->aspect[0];
+ result = true;
+ }
+
+ if (min[1] < base_offset[1]) {
+ vec[1] += base_offset[1] - min[1];
+ result = true;
+ }
+ else if (max[1] > base_offset[1] + t->aspect[1]) {
+ vec[1] -= max[1] - base_offset[1] - t->aspect[1];
+ result = true;
+ }
+
+ return result;
+}
+
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
@@ -470,7 +513,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
}
t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
- applySnapping(t, global_dir);
+ applySnappingAsGroup(t, global_dir);
transform_snap_grid(t, global_dir);
if (t->con.mode & CON_APPLY) {
@@ -498,7 +541,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
applyTranslationValue(t, global_dir);
/* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) {
+ if (t->flag & T_CLIP_UV && clip_uv_transform_translation(t, global_dir)) {
applyTranslationValue(t, global_dir);
/* In proportional edit it can happen that */
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index 77c5707d814..d7c4d862b23 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -68,7 +68,7 @@ typedef struct VertSlideParams {
bool flipped;
} VertSlideParams;
-static void calcVertSlideCustomPoints(struct TransInfo *t)
+static void vert_slide_update_input(TransInfo *t)
{
VertSlideParams *slp = t->custom.mode.data;
VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
@@ -94,6 +94,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
else {
setCustomPoints(t, &t->mouse, mval_end, mval_start);
}
+}
+
+static void calcVertSlideCustomPoints(struct TransInfo *t)
+{
+ vert_slide_update_input(t);
/* setCustomPoints isn't normally changing as the mouse moves,
* in this case apply mouse input immediately so we don't refresh
@@ -539,7 +544,7 @@ static void vert_slide_snap_apply(TransInfo *t, float *value)
getSnapPoint(t, dvec);
sub_v3_v3(dvec, t->tsnap.snapTarget);
- if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
+ if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) {
float co_dir[3];
sub_v3_v3v3(co_dir, co_curr_3d, co_orig_3d);
normalize_v3(co_dir);
@@ -568,7 +573,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0] + t->values_modal_offset[0];
- applySnapping(t, &final);
+ applySnappingAsGroup(t, &final);
if (!validSnap(t)) {
transform_snap_increment(t, &final);
}
@@ -673,3 +678,22 @@ void initVertSlide(TransInfo *t)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Input Utilities
+ * \{ */
+
+void transform_mode_vert_slide_reproject_input(TransInfo *t)
+{
+ if (t->spacetype == SPACE_VIEW3D) {
+ RegionView3D *rv3d = t->region->regiondata;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
+ }
+ }
+
+ vert_slide_update_input(t);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index cd8a2f17554..99919c0ed78 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -379,6 +379,8 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event)
if (op->customdata == NULL) {
TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data2");
+ t->undo_name = op->type->name;
+
int mode = transformops_mode(op);
retval = initTransform(C, t, op, event, mode);
@@ -566,6 +568,17 @@ static bool transform_poll_property(const bContext *UNUSED(C),
}
}
+ /* Snapping. */
+ {
+ PropertyRNA *prop_snap = RNA_struct_find_property(op->ptr, "snap");
+ if (prop_snap && (prop_snap != prop) &&
+ (RNA_property_boolean_get(op->ptr, prop_snap) == false)) {
+ if (STRPREFIX(prop_id, "snap") || STRPREFIX(prop_id, "use_snap")) {
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -644,28 +657,63 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
}
if (flags & P_SNAP) {
- prop = RNA_def_boolean(ot->srna, "snap", 0, "Use Snapping Options", "");
+ prop = RNA_def_boolean(ot->srna, "snap", false, "Use Snapping Options", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_enum(ot->srna,
+ "snap_elements",
+ rna_enum_snap_element_items,
+ SCE_SNAP_MODE_INCREMENT,
+ "Snap to Elements",
+ "");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+
+ RNA_def_boolean(ot->srna, "use_snap_project", false, "Project Individual Elements", "");
+
if (flags & P_GEO_SNAP) {
- /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
- * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
- * geometry to which moved geometry is snapped). Use "Source snap point" and "Point on
- * source that will snap to target" for name and description, respectively. */
- prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Target", "");
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
+ * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
+ * geometry is snapped). Use "Source snap point" and "Point on source that will snap to
+ * target" for name and description, respectively. */
+ prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Snap With", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* Target selection. */
+ prop = RNA_def_boolean(ot->srna, "use_snap_self", true, "Target: Include Active", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "use_snap_edit", true, "Target: Include Edit", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "use_snap_nonedit", true, "Target: Include Non-Edited", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(
+ ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* Face Nearest options */
+ prop = RNA_def_boolean(
+ ot->srna, "use_snap_to_same_target", false, "Snap to Same Target", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_int(
+ ot->srna, "snap_face_nearest_steps", 1, 1, 32767, "Face Nearest Steps", "", 1, 32767);
RNA_def_property_flag(prop, PROP_HIDDEN);
+
prop = RNA_def_float_vector(
ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
if (flags & P_ALIGN_SNAP) {
- prop = RNA_def_boolean(ot->srna, "snap_align", 0, "Align with Point Normal", "");
+ prop = RNA_def_boolean(ot->srna, "snap_align", false, "Align with Point Normal", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_float_vector(
ot->srna, "snap_normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
}
}
+ else {
+ prop = RNA_def_boolean(
+ ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
}
if (flags & P_GPENCIL_EDIT) {
@@ -849,17 +897,6 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
-/* Similar to #transform_shear_poll. */
-static bool transform_rotate_poll(bContext *C)
-{
- if (!ED_operator_screenactive(C)) {
- return false;
- }
-
- ScrArea *area = CTX_wm_area(C);
- return area && !ELEM(area->spacetype, SPACE_ACTION);
-}
-
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
{
/* identifiers */
@@ -873,7 +910,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = transform_rotate_poll;
+ ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;
RNA_def_float_rotation(
@@ -938,7 +975,6 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
-/* Similar to #transform_rotate_poll. */
static bool transform_shear_poll(bContext *C)
{
if (!ED_operator_screenactive(C)) {
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index c0d943e17ee..53f496a5d3c 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -476,7 +476,7 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
Object *obedit = CTX_data_edit_object(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = region->regiondata;
- Object *ob = OBACT(view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
const short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
const int pivot_point = scene->toolsettings->transform_pivot_point;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 649217092aa..02355fd4642 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -51,9 +51,6 @@
static bool doForceIncrementSnap(const TransInfo *t);
-/* this should be passed as an arg for use in snap functions */
-#undef BASACT
-
/* use half of flt-max so we can scale up without an exception */
/* -------------------------------------------------------------------- */
@@ -126,8 +123,12 @@ bool activeSnap(const TransInfo *t)
((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT);
}
-bool activeSnap_with_project(const TransInfo *t)
+bool activeSnap_SnappingIndividual(const TransInfo *t)
{
+ if (activeSnap(t) && t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) {
+ return true;
+ }
+
if (!t->tsnap.project) {
return false;
}
@@ -143,6 +144,27 @@ bool activeSnap_with_project(const TransInfo *t)
return true;
}
+bool activeSnap_SnappingAsGroup(const TransInfo *t)
+{
+ if (!activeSnap(t)) {
+ return false;
+ }
+
+ if (t->tsnap.mode == SCE_SNAP_MODE_FACE_RAYCAST && t->tsnap.project) {
+ return false;
+ }
+
+ if (t->tsnap.mode == SCE_SNAP_MODE_FACE_NEAREST) {
+ return false;
+ }
+
+ if (doForceIncrementSnap(t)) {
+ return false;
+ }
+
+ return true;
+}
+
bool transformModeUseSnap(const TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -170,156 +192,152 @@ static bool doForceIncrementSnap(const TransInfo *t)
void drawSnapping(const struct bContext *C, TransInfo *t)
{
uchar col[4], selectedCol[4], activeCol[4];
-
if (!activeSnap(t)) {
return;
}
- if (t->spacetype == SPACE_VIEW3D) {
- bool draw_target = (t->tsnap.status & TARGET_INIT) &&
- (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
-
- if (draw_target || validSnap(t)) {
- UI_GetThemeColor3ubv(TH_TRANSFORM, col);
- col[3] = 128;
+ bool draw_target = (t->spacetype == SPACE_VIEW3D) && (t->tsnap.status & TARGET_INIT) &&
+ (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
- UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
- selectedCol[3] = 128;
+ if (!(draw_target || validSnap(t))) {
+ return;
+ }
- UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
- activeCol[3] = 192;
+ if (t->spacetype == SPACE_SEQ) {
+ UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col);
+ col[3] = 128;
+ }
+ else if (t->spacetype != SPACE_IMAGE) {
+ UI_GetThemeColor3ubv(TH_TRANSFORM, col);
+ col[3] = 128;
- const float *loc_cur = NULL;
- const float *loc_prev = NULL;
- const float *normal = NULL;
+ UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
+ selectedCol[3] = 128;
- GPU_depth_test(GPU_DEPTH_NONE);
+ UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
+ activeCol[3] = 192;
+ }
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (!BLI_listbase_is_empty(&t->tsnap.points)) {
- /* Draw snap points. */
+ if (t->spacetype == SPACE_VIEW3D) {
+ const float *loc_cur = NULL;
+ const float *loc_prev = NULL;
+ const float *normal = NULL;
- float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- float view_inv[4][4];
- copy_m4_m4(view_inv, rv3d->viewinv);
+ GPU_depth_test(GPU_DEPTH_NONE);
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (!BLI_listbase_is_empty(&t->tsnap.points)) {
+ /* Draw snap points. */
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
- LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
- if (p == t->tsnap.selectedPoint) {
- immUniformColor4ubv(selectedCol);
- }
- else {
- immUniformColor4ubv(col);
- }
- imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
- }
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immUnbindProgram();
- }
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- /* draw normal if needed */
- if (usingSnappingNormal(t) && validSnappingNormal(t)) {
- normal = t->tsnap.snapNormal;
+ LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
+ if (p == t->tsnap.selectedPoint) {
+ immUniformColor4ubv(selectedCol);
+ }
+ else {
+ immUniformColor4ubv(col);
+ }
+ imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
}
- if (draw_target) {
- loc_prev = t->tsnap.snapTarget;
- }
+ immUnbindProgram();
+ }
- if (validSnap(t)) {
- loc_cur = t->tsnap.snapPoint;
- }
+ /* draw normal if needed */
+ if (usingSnappingNormal(t) && validSnappingNormal(t)) {
+ normal = t->tsnap.snapNormal;
+ }
- ED_view3d_cursor_snap_draw_util(
- rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
+ if (draw_target) {
+ loc_prev = t->tsnap.snapTarget;
+ }
- GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
+ if (validSnap(t)) {
+ loc_cur = t->tsnap.snapPoint;
}
+
+ ED_view3d_cursor_snap_draw_util(
+ rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
+
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
else if (t->spacetype == SPACE_IMAGE) {
- if (validSnap(t)) {
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- float x, y;
- const float snap_point[2] = {
- t->tsnap.snapPoint[0] / t->aspect[0],
- t->tsnap.snapPoint[1] / t->aspect[1],
- };
- UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y);
- float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize;
-
- GPU_matrix_push_projection();
- wmOrtho2_region_pixelspace(t->region);
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3ub(255, 255, 255);
- imm_draw_circle_wire_2d(pos, x, y, radius, 8);
- immUnbindProgram();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- GPU_matrix_pop_projection();
- }
- }
- else if (t->spacetype == SPACE_NODE) {
- if (validSnap(t)) {
- ARegion *region = CTX_wm_region(C);
- TransSnapPoint *p;
- float size;
+ float x, y;
+ const float snap_point[2] = {
+ t->tsnap.snapPoint[0] / t->aspect[0],
+ t->tsnap.snapPoint[1] / t->aspect[1],
+ };
+ UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y);
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize;
- size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(t->region);
- GPU_blend(GPU_BLEND_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ub(255, 255, 255);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 8);
+ immUnbindProgram();
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_matrix_pop_projection();
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ ARegion *region = CTX_wm_region(C);
+ TransSnapPoint *p;
+ float size;
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- for (p = t->tsnap.points.first; p; p = p->next) {
- if (p == t->tsnap.selectedPoint) {
- immUniformColor4ubv(selectedCol);
- }
- else {
- immUniformColor4ubv(col);
- }
+ GPU_blend(GPU_BLEND_ALPHA);
- ED_node_draw_snap(&region->v2d, p->co, size, 0, pos);
- }
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- if (t->tsnap.status & POINT_INIT) {
- immUniformColor4ubv(activeCol);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- ED_node_draw_snap(&region->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
+ for (p = t->tsnap.points.first; p; p = p->next) {
+ if (p == t->tsnap.selectedPoint) {
+ immUniformColor4ubv(selectedCol);
+ }
+ else {
+ immUniformColor4ubv(col);
}
- immUnbindProgram();
+ ED_node_draw_snap(&region->v2d, p->co, size, 0, pos);
+ }
+
+ if (t->tsnap.status & POINT_INIT) {
+ immUniformColor4ubv(activeCol);
- GPU_blend(GPU_BLEND_NONE);
+ ED_node_draw_snap(&region->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
}
+
+ immUnbindProgram();
+
+ GPU_blend(GPU_BLEND_NONE);
}
else if (t->spacetype == SPACE_SEQ) {
- if (validSnap(t)) {
- const ARegion *region = CTX_wm_region(C);
- GPU_blend(GPU_BLEND_ALPHA);
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col);
- col[3] = 128;
- immUniformColor4ubv(col);
- float pixelx = BLI_rctf_size_x(&region->v2d.cur) / BLI_rcti_size_x(&region->v2d.mask);
- immRectf(pos,
- t->tsnap.snapPoint[0] - pixelx,
- region->v2d.cur.ymax,
- t->tsnap.snapPoint[0] + pixelx,
- region->v2d.cur.ymin);
- immUnbindProgram();
- GPU_blend(GPU_BLEND_NONE);
- }
+ const ARegion *region = CTX_wm_region(C);
+ GPU_blend(GPU_BLEND_ALPHA);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4ubv(col);
+ float pixelx = BLI_rctf_size_x(&region->v2d.cur) / BLI_rcti_size_x(&region->v2d.mask);
+ immRectf(pos,
+ t->tsnap.snapPoint[0] - pixelx,
+ region->v2d.cur.ymax,
+ t->tsnap.snapPoint[0] + pixelx,
+ region->v2d.cur.ymin);
+ immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
}
}
@@ -343,93 +361,157 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
return status;
}
-void applyProject(TransInfo *t)
+static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td)
{
- if (!activeSnap_with_project(t)) {
- return;
+ if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ return false;
+ }
+
+ float iloc[3], loc[3], no[3];
+ float mval_fl[2];
+
+ copy_v3_v3(iloc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, iloc);
+ }
+ else if (t->options & CTX_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(iloc, td->ob->obmat[3]);
+ }
+
+ if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) !=
+ V3D_PROJ_RET_OK) {
+ return false;
+ }
+
+ eSnapMode hit = ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ t->region,
+ t->view,
+ SCE_SNAP_MODE_FACE_RAYCAST,
+ &(const struct SnapObjectParams){
+ .snap_target_select = t->tsnap.target_select,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
+ .use_occlusion_test = false,
+ .use_backface_culling = t->tsnap.use_backface_culling,
+ },
+ NULL,
+ mval_fl,
+ NULL,
+ 0,
+ loc,
+ no);
+ if (hit != SCE_SNAP_MODE_FACE_RAYCAST) {
+ return false;
}
float tvec[3];
- int i;
+ sub_v3_v3v3(tvec, loc, iloc);
- /* XXX FLICKER IN OBJECT MODE */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- float iloc[3], loc[3], no[3];
- float mval_fl[2];
- if (td->flag & TD_SKIP) {
- continue;
- }
+ mul_m3_v3(td->smtx, tvec);
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
- continue;
- }
+ add_v3_v3(td->loc, tvec);
- copy_v3_v3(iloc, td->loc);
- if (tc->use_local_mat) {
- mul_m4_v3(tc->mat, iloc);
- }
- else if (t->options & CTX_OBJECT) {
- BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
+ if (t->tsnap.align && (t->options & CTX_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float mat[3][3];
- if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
- V3D_PROJ_RET_OK) {
- eSnapMode hit = ED_transform_snap_object_project_view3d(
- t->tsnap.object_context,
- t->depsgraph,
- t->region,
- t->view,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_target_select = t->tsnap.target_select,
- .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = false,
- .use_backface_culling = t->tsnap.use_backface_culling,
- },
- mval_fl,
- NULL,
- 0,
- loc,
- no);
- if (hit != SCE_SNAP_MODE_FACE) {
- return;
- }
+ /* In pose mode, we want to align normals with Y axis of bones. */
+ original_normal = td->axismtx[2];
-#if 0
- if (tc->use_local_mat) {
- mul_m4_v3(tc->imat, loc);
- }
-#endif
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
- sub_v3_v3v3(tvec, loc, iloc);
+ transform_data_ext_rotate(td, mat, true);
- mul_m3_v3(td->smtx, tvec);
+ /* TODO: support constraints for rotation too? see #ElementRotation. */
+ }
+ return true;
+}
- add_v3_v3(td->loc, tvec);
+static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td)
+{
+ if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) {
+ return;
+ }
+
+ float init_loc[3];
+ float prev_loc[3];
+ float snap_loc[3], snap_no[3];
+
+ copy_v3_v3(init_loc, td->iloc);
+ copy_v3_v3(prev_loc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, init_loc);
+ mul_m4_v3(tc->mat, prev_loc);
+ }
+ else if (t->options & CTX_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(init_loc, td->ob->obmat[3]);
+ }
- if (t->tsnap.align && (t->options & CTX_OBJECT)) {
- /* handle alignment as well */
- const float *original_normal;
- float mat[3][3];
+ eSnapMode hit = ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ t->region,
+ t->view,
+ SCE_SNAP_MODE_FACE_NEAREST,
+ &(const struct SnapObjectParams){
+ .snap_target_select = t->tsnap.target_select,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
+ .use_occlusion_test = false,
+ .use_backface_culling = false,
+ .face_nearest_steps = t->tsnap.face_nearest_steps,
+ .keep_on_same_target = t->tsnap.flag & SCE_SNAP_KEEP_ON_SAME_OBJECT,
+ },
+ init_loc,
+ NULL,
+ prev_loc,
+ 0,
+ snap_loc,
+ snap_no);
+
+ if (hit != SCE_SNAP_MODE_FACE_NEAREST) {
+ return;
+ }
- /* In pose mode, we want to align normals with Y axis of bones... */
- original_normal = td->axismtx[2];
+ float tvec[3];
+ sub_v3_v3v3(tvec, snap_loc, prev_loc);
+ mul_m3_v3(td->smtx, tvec);
+ add_v3_v3(td->loc, tvec);
- rotation_between_vecs_to_mat3(mat, original_normal, no);
+ /* TODO: support snap alignment similar to #SCE_SNAP_MODE_FACE_RAYCAST? */
+}
- transform_data_ext_rotate(td, mat, true);
+void applySnappingIndividual(TransInfo *t)
+{
+ if (!activeSnap_SnappingIndividual(t)) {
+ return;
+ }
- /* TODO: support constraints for rotation too? see #ElementRotation. */
- }
+ /* XXX FLICKER IN OBJECT MODE */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
+ continue;
}
- }
+ /* If both face ray-cast and face nearest methods are enabled, start with face ray-cast and
+ * fallback to face nearest ray-cast does not hit. */
+ bool hit = applyFaceProject(t, tc, td);
+ if (!hit) {
+ applyFaceNearest(t, tc, td);
+ }
#if 0 /* TODO: support this? */
- constraintTransLim(t, td);
+ constraintTransLim(t, td);
#endif
+ }
}
}
@@ -483,15 +565,9 @@ void applyGridAbsolute(TransInfo *t)
}
}
-void applySnapping(TransInfo *t, float *vec)
+void applySnappingAsGroup(TransInfo *t, float *vec)
{
- /* Each Trans Data already makes the snap to face */
- if (doForceIncrementSnap(t)) {
- return;
- }
-
- if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
- /* A similar snap will be applied to each transdata in `applyProject`. */
+ if (!activeSnap_SnappingAsGroup(t)) {
return;
}
@@ -644,70 +720,76 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
-static eSnapTargetSelect snap_select_type_get(TransInfo *t)
+static eSnapTargetSelect snap_target_select_from_spacetype(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
Base *base_act = view_layer->basact;
+
+ eSnapTargetSelect ret = SCE_SNAP_TARGET_ALL;
+
+ bool use_snap_active = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_ACTIVE) == 0;
+ bool use_snap_edit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_EDITED) == 0;
+ bool use_snap_nonedit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_NONEDITED) == 0;
+ bool use_snap_selectable_only = (t->tsnap.target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0;
+
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
+ if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
+ /* Particles edit mode. */
+ return ret;
+ }
+
+ if (use_snap_selectable_only) {
+ ret |= SCE_SNAP_TARGET_ONLY_SELECTABLE;
+ }
+
if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) {
/* In "Edit Strokes" mode,
* snap tool can perform snap to selected or active objects (see T49632)
* TODO: perform self snap in gpencil_strokes.
*
* When we're moving the origins, allow snapping onto our own geometry (see T69132). */
- return SCE_SNAP_TARGET_ALL;
+ return ret;
}
const int obedit_type = t->obedit_type;
if (obedit_type != -1) {
/* Edit mode */
- if (ELEM(obedit_type,
- OB_MESH,
- OB_ARMATURE,
- OB_CURVES_LEGACY,
- OB_SURF,
- OB_LATTICE,
- OB_MBALL)) {
- /* Temporary limited to edit mode meshes, armature, curves, lattice and metaballs. */
-
- if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
- /* Exclude editmesh if using proportional edit */
- return SCE_SNAP_TARGET_NOT_EDITED;
+ if (obedit_type == OB_MESH) {
+ /* Editing a mesh */
+ if ((t->flag & T_PROP_EDIT) != 0) {
+ /* Exclude editmesh when using proportional edit */
+ ret |= SCE_SNAP_TARGET_NOT_EDITED;
}
-
- if (!t->tsnap.snap_self) {
- return SCE_SNAP_TARGET_NOT_ACTIVE;
+ if (!use_snap_active) {
+ ret |= SCE_SNAP_TARGET_NOT_ACTIVE;
+ }
+ if (!use_snap_edit) {
+ ret |= SCE_SNAP_TARGET_NOT_EDITED;
+ }
+ if (!use_snap_nonedit) {
+ ret |= SCE_SNAP_TARGET_NOT_NONEDITED;
}
-
- return SCE_SNAP_TARGET_NOT_SELECTED;
}
-
- return SCE_SNAP_TARGET_ALL;
+ else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) {
+ /* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */
+ ret |= SCE_SNAP_TARGET_NOT_SELECTED;
+ }
}
-
- if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
- /* Particles edit mode. */
- return SCE_SNAP_TARGET_ALL;
+ else {
+ /* Object or pose mode. */
+ ret |= SCE_SNAP_TARGET_NOT_SELECTED | SCE_SNAP_TARGET_NOT_ACTIVE;
}
-
- /* Object or pose mode. */
- return SCE_SNAP_TARGET_NOT_SELECTED;
}
-
- if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
- return SCE_SNAP_TARGET_NOT_SELECTED;
+ else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
+ ret |= SCE_SNAP_TARGET_NOT_SELECTED;
}
- return SCE_SNAP_TARGET_ALL;
+ return ret;
}
static void initSnappingMode(TransInfo *t)
{
- ToolSettings *ts = t->settings;
- t->tsnap.mode = snap_mode_from_spacetype(t);
- t->tsnap.target_select = snap_select_type_get(t);
-
- if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) {
+ if ((t->spacetype != SPACE_VIEW3D) || !(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
/* Force project off when not supported. */
t->tsnap.project = false;
}
@@ -724,7 +806,7 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.use_backface_culling = snap_use_backface_culling(t);
t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0);
- if (t->data_type == TC_MESH_VERTS) {
+ if (t->data_type == &TransConvertType_Mesh) {
/* Ignore elements being transformed. */
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
@@ -753,9 +835,14 @@ static void initSnappingMode(TransInfo *t)
void initSnapping(TransInfo *t, wmOperator *op)
{
+ ToolSettings *ts = t->settings;
+ eSnapSourceSelect snap_source = ts->snap_target;
+
resetSnapping(t);
+ t->tsnap.mode = snap_mode_from_spacetype(t);
t->tsnap.flag = snap_flag_from_spacetype(t);
- eSnapSourceSelect snap_source = t->settings->snap_target;
+ t->tsnap.target_select = snap_target_select_from_spacetype(t);
+ t->tsnap.face_nearest_steps = max_ii(ts->snap_face_nearest_steps, 1);
/* if snap property exists */
PropertyRNA *prop;
@@ -764,11 +851,16 @@ void initSnapping(TransInfo *t, wmOperator *op)
if (RNA_property_boolean_get(op->ptr, prop)) {
t->modifiers |= MOD_SNAP;
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.mode = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
+ * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
+ * geometry is snapped). */
if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
RNA_property_is_set(op->ptr, prop)) {
- /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid
- * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is
- * geometry to which moved geometry is snapped). */
snap_source = RNA_property_enum_get(op->ptr, prop);
}
@@ -791,9 +883,33 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.project = RNA_property_boolean_get(op->ptr, prop);
}
+ /* use_snap_self is misnamed and should be use_snap_active */
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
RNA_property_is_set(op->ptr, prop)) {
- t->tsnap.snap_self = RNA_property_boolean_get(op->ptr, prop);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_NOT_ACTIVE);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_NOT_EDITED);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_NOT_NONEDITED);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_ONLY_SELECTABLE);
}
}
}
@@ -805,8 +921,19 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0);
t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
- t->tsnap.snap_self = !((t->tsnap.flag & SCE_SNAP_NO_SELF) != 0);
t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ (ts->snap_flag & SCE_SNAP_NOT_TO_ACTIVE),
+ SCE_SNAP_TARGET_NOT_ACTIVE);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_EDITED),
+ SCE_SNAP_TARGET_NOT_EDITED);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED),
+ SCE_SNAP_TARGET_NOT_NONEDITED);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ (ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE),
+ SCE_SNAP_TARGET_ONLY_SELECTABLE);
}
t->tsnap.source_select = snap_source;
@@ -991,8 +1118,8 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
found = (snap_elem != SCE_SNAP_MODE_NONE);
}
if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
- found = peelObjectsTransform(
- t, mval, (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, loc, no, NULL);
+ bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0;
+ found = peelObjectsTransform(t, mval, use_peel, loc, no, NULL);
if (found) {
snap_elem = SCE_SNAP_MODE_VOLUME;
@@ -1026,7 +1153,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
objects,
objects_len,
t->mval,
- t->tsnap.target_select == SCE_SNAP_TARGET_NOT_SELECTED,
+ t->tsnap.target_select & SCE_SNAP_TARGET_NOT_SELECTED,
&dist_sq,
t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
@@ -1118,7 +1245,7 @@ static void snap_target_grid_ensure(TransInfo *t)
{
/* Only need to calculate once. */
if ((t->tsnap.status & TARGET_GRID_INIT) == 0) {
- if (t->data_type == TC_CURSOR_VIEW3D) {
+ if (t->data_type == &TransConvertType_Cursor3D) {
/* Use a fallback when transforming the cursor.
* In this case the center is _not_ derived from the cursor which is being transformed. */
copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
@@ -1321,9 +1448,10 @@ eSnapMode snapObjectsTransform(
&(const struct SnapObjectParams){
.snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
+ .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST,
.use_backface_culling = t->tsnap.use_backface_culling,
},
+ NULL,
mval,
target,
dist_px,
@@ -1423,7 +1551,7 @@ bool peelObjectsTransform(TransInfo *t,
static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select)
{
/* node is use for snapping only if a) snap mode matches and b) node is inside the view */
- return ((snap_target_select == SCE_SNAP_TARGET_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
+ return (((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && !(node->flag & NODE_SELECT)) ||
(snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) &&
(node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index 6db027df067..3672e76c778 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -40,15 +40,16 @@ float transform_snap_increment_get(const TransInfo *t);
bool transform_snap_grid(TransInfo *t, float *val);
bool activeSnap(const TransInfo *t);
-bool activeSnap_with_project(const TransInfo *t);
+bool activeSnap_SnappingIndividual(const TransInfo *t);
+bool activeSnap_SnappingAsGroup(const TransInfo *t);
bool validSnap(const TransInfo *t);
void initSnapping(struct TransInfo *t, struct wmOperator *op);
void freeSnapping(struct TransInfo *t);
-void applyProject(TransInfo *t);
+void applySnappingIndividual(TransInfo *t);
void applyGridAbsolute(TransInfo *t);
-void applySnapping(TransInfo *t, float *vec);
+void applySnappingAsGroup(TransInfo *t, float *vec);
void resetSnapping(TransInfo *t);
eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event);
void drawSnapping(const struct bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index cf99d4b2ef3..c72511d213d 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -47,6 +47,7 @@
using blender::float3;
using blender::float4x4;
using blender::Map;
+using blender::Span;
/* -------------------------------------------------------------------- */
/** \name Internal Data Types
@@ -243,6 +244,11 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
SnapData_Mesh *sod;
bool init = false;
+ const Span<MVert> verts = me_eval->verts();
+ const Span<MEdge> edges = me_eval->edges();
+ const Span<MPoly> polys = me_eval->polys();
+ const Span<MLoop> loops = me_eval->loops();
+
if (std::unique_ptr<SnapData_Mesh> *sod_p = sctx->mesh_caches.lookup_ptr(ob_eval)) {
sod = sod_p->get();
bool is_dirty = false;
@@ -264,16 +270,16 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
else if (sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) {
is_dirty = true;
}
- else if (sod->treedata_mesh.vert != me_eval->mvert) {
+ else if (sod->treedata_mesh.vert != verts.data()) {
is_dirty = true;
}
- else if (sod->treedata_mesh.loop != me_eval->mloop) {
+ else if (sod->treedata_mesh.loop != loops.data()) {
is_dirty = true;
}
- else if (sod->treedata_mesh.edge != me_eval->medge) {
+ else if (sod->treedata_mesh.edge != edges.data()) {
is_dirty = true;
}
- else if (sod->poly != me_eval->mpoly) {
+ else if (sod->poly != polys.data()) {
is_dirty = true;
}
@@ -303,16 +309,16 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI,
4);
- BLI_assert(sod->treedata_mesh.vert == me_eval->mvert);
- BLI_assert(!me_eval->mvert || sod->treedata_mesh.vert_normals);
- BLI_assert(sod->treedata_mesh.loop == me_eval->mloop);
- BLI_assert(!me_eval->mpoly || sod->treedata_mesh.looptri);
+ BLI_assert(sod->treedata_mesh.vert == verts.data());
+ BLI_assert(!verts.data() || sod->treedata_mesh.vert_normals);
+ BLI_assert(sod->treedata_mesh.loop == loops.data());
+ BLI_assert(!polys.data() || sod->treedata_mesh.looptri);
sod->has_looptris = sod->treedata_mesh.tree != nullptr;
/* Required for snapping with occlusion. */
- sod->treedata_mesh.edge = me_eval->medge;
- sod->poly = me_eval->mpoly;
+ sod->treedata_mesh.edge = edges.data();
+ sod->poly = polys.data();
/* Start assuming that it has each of these element types. */
sod->has_loose_edge = true;
@@ -405,6 +411,62 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
return sod;
}
+static BVHTreeFromMesh *snap_object_data_mesh_treedata_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ bool use_hide)
+{
+ SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
+ return &sod->treedata_mesh;
+}
+
+static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ BMEditMesh *em)
+{
+ SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
+
+ BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
+
+ if (treedata->tree == nullptr) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BLI_assert(sod->treedata_editmesh.em ==
+ BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
+ em = sod->treedata_editmesh.em;
+
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ BMesh *bm = em->bm;
+ BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
+
+ BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ bm,
+ elem_mask,
+ sctx->callbacks.edit_mesh.test_face_fn,
+ sctx->callbacks.edit_mesh.user_data);
+
+ bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6);
+
+ MEM_freeN(elem_mask);
+ }
+ else {
+ /* Only cache if BVH-tree is created without a mask.
+ * This helps keep a standardized BVH-tree in cache. */
+ BKE_bvhtree_from_editmesh_get(treedata,
+ em,
+ 4,
+ BVHTREE_FROM_EM_LOOPTRI,
+ &sod->mesh_runtime->bvh_cache,
+ static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ }
+ }
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return nullptr;
+ }
+
+ return treedata;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -419,16 +481,16 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx,
void *data);
static bool snap_object_is_snappable(const SnapObjectContext *sctx,
- const eSnapTargetSelect snap_select,
+ const eSnapTargetSelect snap_target_select,
const Base *base_act,
- const Base *base,
- const bool is_in_object_mode)
+ const Base *base)
{
if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
return false;
}
- if ((snap_select == SCE_SNAP_TARGET_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ if ((snap_target_select == SCE_SNAP_TARGET_ALL) ||
+ (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
return true;
}
@@ -436,25 +498,38 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if (snap_select == SCE_SNAP_TARGET_NOT_ACTIVE) {
- return base_act != base;
- }
+ /* Get attributes of potential target. */
+ const bool is_active = (base_act == base);
+ const bool is_selected = (base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL);
+ const bool is_edited = (base->object->mode == OB_MODE_EDIT);
+ const bool is_selectable = (base->flag & BASE_SELECTABLE);
+ /* Get attributes of state. */
+ const bool is_in_object_mode = (base_act == nullptr) ||
+ (base_act->object->mode == OB_MODE_OBJECT);
- if (snap_select == SCE_SNAP_TARGET_NOT_EDITED) {
- return base->object->mode != OB_MODE_EDIT;
+ if (is_in_object_mode) {
+ /* Handle target selection options that make sense for object mode. */
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && is_selected) {
+ /* What is selectable or not is part of the object and depends on the mode. */
+ return false;
+ }
}
-
- if (snap_select == SCE_SNAP_TARGET_NOT_SELECTED) {
- if (is_in_object_mode) {
- return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
+ else {
+ /* Handle target selection options that make sense for edit/pose mode. */
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_ACTIVE) && is_active) {
+ return false;
+ }
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_EDITED) && is_edited && !is_active) {
+ /* Base is edited, but not active. */
+ return false;
+ }
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_NONEDITED) && !is_edited) {
+ return false;
}
-
- /* What is selectable or not is part of the object and depends on the mode. */
- return true;
}
- if (snap_select == SCE_SNAP_TARGET_ONLY_SELECTABLE) {
- return (base->flag & BASE_SELECTABLE) != 0;
+ if ((snap_target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) && !is_selectable) {
+ return false;
}
return true;
@@ -470,11 +545,10 @@ static void iter_snap_objects(SnapObjectContext *sctx,
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
const eSnapTargetSelect snap_target_select = params->snap_target_select;
-
Base *base_act = view_layer->basact;
- const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
+
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base, is_in_object_mode)) {
+ if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base)) {
continue;
}
@@ -850,40 +924,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
-
- if (treedata->tree == nullptr) {
- em = sod->treedata_editmesh.em;
-
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- BMesh *bm = em->bm;
- BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
-
- BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- bm,
- elem_mask,
- sctx->callbacks.edit_mesh.test_face_fn,
- sctx->callbacks.edit_mesh.user_data);
-
- bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6);
-
- MEM_freeN(elem_mask);
- }
- else {
- /* Only cache if bvhtree is created without a mask.
- * This helps keep a standardized bvhtree in cache. */
- BKE_bvhtree_from_editmesh_get(treedata,
- em,
- 4,
- BVHTREE_FROM_EM_LOOPTRI,
- &sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
- }
-
- if (treedata->tree == nullptr) {
- return retval;
- }
+ BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
+ if (treedata == nullptr) {
+ return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -1098,7 +1141,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
@@ -1150,6 +1193,324 @@ static bool raycastObjects(SnapObjectContext *sctx,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Surface Snap Funcs
+ * \{ */
+
+struct NearestWorldObjUserData {
+ const float *init_co;
+ const float *curr_co;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ float r_dist_sq;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool ret;
+};
+
+static void nearest_world_tree_co(BVHTree *tree,
+ BVHTree_NearestPointCallback nearest_cb,
+ void *treedata,
+ float co[3],
+ float r_co[3],
+ float r_no[3],
+ int *r_index,
+ float *r_dist_sq)
+{
+ BVHTreeNearest nearest = {};
+ nearest.index = -1;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(tree, co, &nearest, nearest_cb, treedata);
+
+ if (r_co) {
+ copy_v3_v3(r_co, nearest.co);
+ }
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ }
+ if (r_index) {
+ *r_index = nearest.index;
+ }
+ if (r_dist_sq) {
+ float diff[3];
+ sub_v3_v3v3(diff, co, nearest.co);
+ *r_dist_sq = len_squared_v3(diff);
+ }
+}
+
+static bool nearest_world_tree(SnapObjectContext *UNUSED(sctx),
+ const struct SnapObjectParams *params,
+ BVHTree *tree,
+ BVHTree_NearestPointCallback nearest_cb,
+ void *treedata,
+ const float (*obmat)[4],
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ if (curr_co == nullptr || init_co == nullptr) {
+ /* No location to work with, so just return. */
+ return false;
+ }
+
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ transpose_m3_m4(timat, imat);
+
+ /* compute offset between init co and prev co in local space */
+ float init_co_local[3], curr_co_local[3];
+ float delta_local[3];
+ mul_v3_m4v3(init_co_local, imat, init_co);
+ mul_v3_m4v3(curr_co_local, imat, curr_co);
+ sub_v3_v3v3(delta_local, curr_co_local, init_co_local);
+
+ float dist_sq;
+ if (params->keep_on_same_target) {
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, init_co_local, nullptr, nullptr, nullptr, &dist_sq);
+ }
+ else {
+ /* NOTE: when `params->face_nearest_steps == 1`, the return variables of function below contain
+ * the answer. We could return immediately after updating r_loc, r_no, r_index, but that would
+ * also complicate the code. Foregoing slight optimization for code clarity. */
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq);
+ }
+ if (*r_dist_sq <= dist_sq) {
+ return false;
+ }
+ *r_dist_sq = dist_sq;
+
+ /* scale to make `snap_face_nearest_steps` steps */
+ float step_scale_factor = 1.0f / max_ff(1.0f, (float)params->face_nearest_steps);
+ mul_v3_fl(delta_local, step_scale_factor);
+
+ float co_local[3];
+ float no_local[3];
+ int index;
+
+ copy_v3_v3(co_local, init_co_local);
+
+ for (int i = 0; i < params->face_nearest_steps; i++) {
+ add_v3_v3(co_local, delta_local);
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, co_local, co_local, no_local, &index, nullptr);
+ }
+
+ mul_v3_m4v3(r_loc, obmat, co_local);
+
+ if (r_no) {
+ mul_v3_m3v3(r_no, timat, no_local);
+ normalize_v3(r_no);
+ }
+
+ if (r_index) {
+ *r_index = index;
+ }
+
+ return true;
+}
+
+static bool nearest_world_mesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float (*obmat)[4],
+ bool use_hide,
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ BVHTreeFromMesh *treedata = snap_object_data_mesh_treedata_get(sctx, ob_eval, me_eval, use_hide);
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return false;
+ }
+
+ return nearest_world_tree(sctx,
+ params,
+ treedata->tree,
+ treedata->nearest_callback,
+ treedata,
+ obmat,
+ init_co,
+ curr_co,
+ r_dist_sq,
+ r_loc,
+ r_no,
+ r_index);
+}
+
+static bool nearest_world_editmesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float (*obmat)[4],
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return false;
+ }
+
+ return nearest_world_tree(sctx,
+ params,
+ treedata->tree,
+ treedata->nearest_callback,
+ treedata,
+ obmat,
+ init_co,
+ curr_co,
+ r_dist_sq,
+ r_loc,
+ r_no,
+ r_index);
+}
+static void nearest_world_object_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ void *data)
+{
+ struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data);
+
+ bool retval = false;
+ switch (ob_eval->type) {
+ case OB_MESH: {
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
+ bool use_hide = false;
+ const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval) {
+ retval = nearest_world_mesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ use_hide,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
+ "Make sure there is only one pointer for looptris");
+ retval = nearest_world_editmesh(sctx,
+ params,
+ ob_eval,
+ em,
+ obmat,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ break;
+ }
+ case OB_CURVES_LEGACY:
+ case OB_SURF:
+ case OB_FONT:
+ if (!is_object_active) {
+ const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
+ if (me_eval) {
+ retval = nearest_world_mesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ false,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ }
+ break;
+ }
+
+ if (retval) {
+ if (dt->r_ob) {
+ *dt->r_ob = ob_eval;
+ }
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
+ }
+ dt->ret = true;
+ }
+}
+
+/**
+ * Main Nearest World Surface Function
+ * ===================================
+ *
+ * Walks through all objects in the scene to find the nearest location on target surface.
+ *
+ * \param sctx: Snap context to store data.
+ * \param params: Settings for snapping.
+ * \param init_co: Initial location of source point.
+ * \param prev_co: Current location of source point after transformation but before snapping.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Location of nearest point on target surface.
+ * \param r_no: Normal of nearest point on target surface.
+ * \param r_index: Index of nearest polygon on target surface.
+ * \param r_ob: Nearest target object.
+ * \param r_obmat: Nearest target matrix (may not be #Object.obmat with dupli-instances).
+ */
+static bool nearestWorldObjects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_loc /* NOLINT */,
+ float *r_no /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
+{
+ NearestWorldObjUserData data = {};
+ data.init_co = init_co;
+ data.curr_co = curr_co;
+ data.r_loc = r_loc;
+ data.r_no = r_no;
+ data.r_index = r_index;
+ data.r_dist_sq = FLT_MAX;
+ data.r_ob = r_ob;
+ data.r_obmat = r_obmat;
+ data.ret = false;
+
+ iter_snap_objects(sctx, params, nearest_world_object_fn, &data);
+ return data.ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Snap Nearest utilities
* \{ */
@@ -1842,7 +2203,8 @@ static eSnapMode snapArmature(SnapObjectContext *sctx,
{
eSnapMode retval = SCE_SNAP_MODE_NONE;
- if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
+ if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE_RAYCAST) {
+ /* Currently only edge and vert */
return retval;
}
@@ -2268,7 +2630,7 @@ static eSnapMode snapCamera(const SnapObjectContext *sctx,
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
BKE_tracking_camera_get_reconstructed_interpolate(
- tracking, tracking_object, CFRA, reconstructed_camera_mat);
+ tracking, tracking_object, scene->r.cfra, reconstructed_camera_mat);
invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
}
@@ -2328,7 +2690,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
float r_no[3],
int *r_index)
{
- BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
if (me_eval->totvert == 0) {
return SCE_SNAP_MODE_NONE;
}
@@ -2506,9 +2868,9 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
float r_no[3],
int *r_index)
{
- BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
- if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
+ if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE_RAYCAST) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
return SCE_SNAP_MODE_NONE;
}
@@ -2811,7 +3173,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
@@ -3014,6 +3376,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
const View3D *v3d,
const eSnapMode snap_to_flag,
const SnapObjectParams *params,
+ const float init_co[3],
const float mval[2],
const float prev_co[3],
float *dist_px,
@@ -3045,11 +3408,36 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
- if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
+ /* NOTE: if both face ray-cast and face nearest are enabled, first find result of nearest, then
+ * override with ray-cast. */
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) {
+ has_hit = nearestWorldObjects(
+ sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat);
+
+ if (has_hit) {
+ retval = SCE_SNAP_MODE_FACE_NEAREST;
+
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob_eval;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
+ }
+ }
+
+ if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) {
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) {
- return SCE_SNAP_MODE_NONE;
+ return retval;
}
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
@@ -3071,8 +3459,8 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
copy_v3_v3(r_face_nor, no);
}
- if ((snap_to_flag & SCE_SNAP_MODE_FACE)) {
- retval = SCE_SNAP_MODE_FACE;
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ retval = SCE_SNAP_MODE_FACE_RAYCAST;
copy_v3_v3(r_loc, loc);
if (r_no) {
@@ -3179,10 +3567,6 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
if (r_index) {
*r_index = index;
}
- if (r_face_nor && !has_hit) {
- /* Fallback. */
- copy_v3_v3(r_face_nor, no);
- }
*dist_px = dist_px_tmp;
}
@@ -3197,6 +3581,7 @@ eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
const View3D *v3d,
const eSnapMode snap_to,
const SnapObjectParams *params,
+ const float init_co[3],
const float mval[2],
const float prev_co[3],
float *dist_px,
@@ -3213,6 +3598,7 @@ eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
v3d,
snap_to,
params,
+ init_co,
mval,
prev_co,
dist_px,
@@ -3230,6 +3616,7 @@ eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
const View3D *v3d,
const eSnapMode snap_to,
const SnapObjectParams *params,
+ const float init_co[3],
const float mval[2],
const float prev_co[3],
float *dist_px,
@@ -3242,6 +3629,7 @@ eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
v3d,
snap_to,
params,
+ init_co,
mval,
prev_co,
dist_px,
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index dbcae2b6320..06d9bb05206 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -28,6 +28,7 @@
#include "SEQ_time.h"
#include "transform.h"
+#include "transform_convert.h"
#include "transform_snap.h"
typedef struct TransSeqSnapData {
@@ -59,21 +60,23 @@ static int cmp_fn(const void *a, const void *b)
return (*(int *)a - *(int *)b);
}
-static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollection *snap_sources)
+static void seq_snap_source_points_build(const Scene *scene,
+ TransSeqSnapData *snap_data,
+ SeqCollection *snap_sources)
{
int i = 0;
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, snap_sources) {
int left = 0, right = 0;
if (seq->flag & SEQ_LEFTSEL) {
- left = right = SEQ_time_left_handle_frame_get(seq);
+ left = right = SEQ_time_left_handle_frame_get(scene, seq);
}
else if (seq->flag & SEQ_RIGHTSEL) {
- left = right = SEQ_time_right_handle_frame_get(seq);
+ left = right = SEQ_time_right_handle_frame_get(scene, seq);
}
else {
- left = SEQ_time_left_handle_frame_get(seq);
- right = SEQ_time_right_handle_frame_get(seq);
+ left = SEQ_time_left_handle_frame_get(scene, seq);
+ right = SEQ_time_right_handle_frame_get(scene, seq);
}
snap_data->source_snap_points[i] = left;
@@ -92,7 +95,8 @@ static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollect
* \{ */
/* Add effect strips directly or indirectly connected to `seq_reference` to `collection`. */
-static void query_strip_effects_fn(Sequence *seq_reference,
+static void query_strip_effects_fn(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
@@ -103,7 +107,7 @@ static void query_strip_effects_fn(Sequence *seq_reference,
/* Find all strips connected to `seq_reference`. */
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
if (SEQ_relation_is_effect_of_strip(seq_test, seq_reference)) {
- query_strip_effects_fn(seq_test, seqbase, collection);
+ query_strip_effects_fn(scene, seq_test, seqbase, collection);
}
}
}
@@ -145,7 +149,7 @@ static SeqCollection *query_snap_targets(Scene *scene,
/* Effects will always change position with strip to which they are connected and they don't have
* to be selected. Remove such strips from `snap_targets` collection. */
SeqCollection *snap_sources_temp = SEQ_collection_duplicate(snap_sources);
- SEQ_collection_expand(seqbase, snap_sources_temp, query_strip_effects_fn);
+ SEQ_collection_expand(scene, seqbase, snap_sources_temp, query_strip_effects_fn);
SeqCollection *snap_sources_effects = seq_collection_extract_effects(snap_sources_temp);
SEQ_collection_exclude(snap_targets, snap_sources_effects);
SEQ_collection_free(snap_sources_temp);
@@ -188,30 +192,31 @@ static void seq_snap_target_points_build(Scene *scene,
int i = 0;
if (snap_mode & SEQ_SNAP_TO_CURRENT_FRAME) {
- snap_data->target_snap_points[i] = CFRA;
+ snap_data->target_snap_points[i] = scene->r.cfra;
i++;
}
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, snap_targets) {
- snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(seq);
- snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(seq);
+ snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(scene, seq);
+ snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(scene, seq);
i += 2;
if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
- int content_start = min_ii(SEQ_time_right_handle_frame_get(seq), seq->start);
- int content_end = max_ii(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len);
+ int content_start = min_ii(SEQ_time_right_handle_frame_get(scene, seq), seq->start);
+ int content_end = max_ii(SEQ_time_left_handle_frame_get(scene, seq), seq->start + seq->len);
/* Effects and single image strips produce incorrect content length. Skip these strips. */
if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) {
- content_start = SEQ_time_left_handle_frame_get(seq);
- content_end = SEQ_time_right_handle_frame_get(seq);
+ content_start = SEQ_time_left_handle_frame_get(scene, seq);
+ content_end = SEQ_time_right_handle_frame_get(scene, seq);
}
CLAMP(content_start,
- SEQ_time_left_handle_frame_get(seq),
- SEQ_time_right_handle_frame_get(seq));
- CLAMP(
- content_end, SEQ_time_left_handle_frame_get(seq), SEQ_time_right_handle_frame_get(seq));
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq));
+ CLAMP(content_end,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq));
snap_data->target_snap_points[i] = content_start;
snap_data->target_snap_points[i + 1] = content_end;
@@ -240,7 +245,7 @@ static int seq_snap_threshold_get_frame_distance(const TransInfo *t)
TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
{
- if (t->data_type == TC_SEQ_IMAGE_DATA) {
+ if (t->data_type == &TransConvertType_SequencerImage) {
return NULL;
}
@@ -260,7 +265,7 @@ TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
/* Build arrays of snap points. */
seq_snap_source_points_alloc(snap_data, snap_sources);
- seq_snap_source_points_build(snap_data, snap_sources);
+ seq_snap_source_points_build(scene, snap_data, snap_sources);
SEQ_collection_free(snap_sources);
short snap_mode = t->tsnap.mode;
@@ -371,7 +376,7 @@ bool ED_transform_snap_sequencer_to_closest_strip_calc(Scene *scene,
t.scene = scene;
t.region = region;
t.values[0] = 0;
- t.data_type = TC_SEQ_DATA;
+ t.data_type = &TransConvertType_Sequencer;
t.tsnap.mode = SEQ_tool_settings_snap_mode_get(scene);
*r_snap_distance = transform_snap_sequencer_to_closest_strip_ex(&t, frame_1, frame_2);
diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt
index 284b725cdf0..271d05e9c04 100644
--- a/source/blender/editors/undo/CMakeLists.txt
+++ b/source/blender/editors/undo/CMakeLists.txt
@@ -11,6 +11,7 @@ set(INC
../../windowmanager
../../../../intern/clog
../../../../intern/guardedalloc
+ ../../bmesh
)
set(SRC
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index ce14e6b180f..40dcb646367 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -269,7 +269,7 @@ static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportLis
CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
- /* TODO(campbell): undo_system: use undo system */
+ /* TODO(@campbellbarton): undo_system: use undo system */
/* grease pencil can be can be used in plenty of spaces, so check it first */
/* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
* or index is fully not implemented.
@@ -435,7 +435,7 @@ bool ED_undo_is_memfile_compatible(const bContext *C)
* (this matches 2.7x behavior). */
ViewLayer *view_layer = CTX_data_view_layer(C);
if (view_layer != NULL) {
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
if (obact != NULL) {
if (obact->mode & OB_MODE_EDIT) {
return false;
@@ -449,7 +449,7 @@ bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
if (view_layer != NULL) {
- Object *obact = OBACT(view_layer);
+ Object *obact = BKE_view_layer_active_object_get(view_layer);
if (obact != NULL) {
if (obact->mode & OB_MODE_ALL_PAINT) {
/* Don't store property changes when painting
@@ -800,7 +800,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
void ED_undo_object_set_active_or_warn(
Scene *scene, ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
{
- Object *ob_prev = OBACT(view_layer);
+ Object *ob_prev = BKE_view_layer_active_object_get(view_layer);
if (ob_prev != ob) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base != NULL) {
@@ -887,7 +887,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
{
- Base *baseact = BASACT(view_layer);
+ Base *baseact = view_layer->basact;
if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
return MEM_mallocN(0, __func__);
}
@@ -897,7 +897,7 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
/* Base iteration, starting with the active-base to ensure it's the first item in the array.
* Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
- for (Base *base = baseact, *base_next = FIRSTBASE(view_layer); base;
+ for (Base *base = baseact, *base_next = view_layer->object_bases.first; base;
base = base_next, base_next = base_next ? base_next->next : NULL) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
@@ -916,7 +916,7 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
{
- Base *baseact = BASACT(view_layer);
+ Base *baseact = view_layer->basact;
if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
return MEM_mallocN(0, __func__);
}
@@ -926,7 +926,7 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len
Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
/* Base iteration, starting with the active-base to ensure it's the first item in the array.
* Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
- for (Base *base = BASACT(view_layer), *base_next = FIRSTBASE(view_layer); base;
+ for (Base *base = view_layer->basact, *base_next = view_layer->object_bases.first; base;
base = base_next, base_next = base_next ? base_next->next : NULL) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 5c2a3374aa1..a9e6adc6e60 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -16,7 +16,6 @@ set(INC
../../sequencer
../../windowmanager
../../../../intern/clog
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -83,7 +82,6 @@ set(SRC
../include/ED_transform.h
../include/ED_transform_snap_object_context.h
../include/ED_transverts.h
- ../include/ED_types.h
../include/ED_undo.h
../include/ED_userpref.h
../include/ED_util.h
@@ -91,6 +89,7 @@ set(SRC
../include/ED_uvedit.h
../include/ED_view3d.h
../include/ED_view3d_offscreen.h
+ ../include/UI_abstract_view.hh
../include/UI_grid_view.hh
../include/UI_icons.h
../include/UI_interface.h
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index 1b6a3efe19c..7ec3d3c1ef4 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -95,7 +95,7 @@ static void draw_overshoot_triangle(const uint8_t color[4],
{
const uint shdr_pos_2d = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
GPU_polygon_smooth(true);
immUniformColor3ubvAlpha(color, 225);
@@ -370,11 +370,13 @@ tSlider *ED_slider_create(struct bContext *C)
slider->factor = 0.5;
/* Add draw callback. Always in header. */
- LISTBASE_FOREACH (ARegion *, region, &slider->area->regionbase) {
- if (region->regiontype == RGN_TYPE_HEADER) {
- slider->region_header = region;
- slider->draw_handle = ED_region_draw_cb_activate(
- region->type, slider_draw, slider, REGION_DRAW_POST_PIXEL);
+ if (slider->area) {
+ LISTBASE_FOREACH (ARegion *, region, &slider->area->regionbase) {
+ if (region->regiontype == RGN_TYPE_HEADER) {
+ slider->region_header = region;
+ slider->draw_handle = ED_region_draw_cb_activate(
+ region->type, slider_draw, slider, REGION_DRAW_POST_PIXEL);
+ }
}
}
@@ -465,7 +467,9 @@ void ED_slider_status_string_get(const struct tSlider *slider,
void ED_slider_destroy(struct bContext *C, tSlider *slider)
{
/* Remove draw callback. */
- ED_region_draw_cb_exit(slider->region_header->type, slider->draw_handle);
+ if (slider->draw_handle) {
+ ED_region_draw_cb_exit(slider->region_header->type, slider->draw_handle);
+ }
ED_area_status_text(slider->area, NULL);
ED_workspace_status_text(C, NULL);
MEM_freeN(slider);
@@ -512,7 +516,7 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_
GPU_line_width(1.0f);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -778,7 +782,7 @@ void ED_region_image_metadata_draw(
/* draw top box */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_METADATA_BG);
immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
immUnbindProgram();
@@ -803,7 +807,7 @@ void ED_region_image_metadata_draw(
/* draw top box */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor(TH_METADATA_BG);
immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
immUnbindProgram();
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 3cfe6bd61a4..2f268d4ae23 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -61,7 +61,7 @@ void ED_editors_init_for_undo(Main *bmain)
wmWindowManager *wm = bmain->wm.first;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Base *base = BASACT(view_layer);
+ Base *base = view_layer->basact;
if (base != NULL) {
Object *ob = base->object;
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
@@ -176,7 +176,7 @@ void ED_editors_init(bContext *C)
}
}
else {
- /* TODO(campbell): avoid operator calls. */
+ /* TODO(@campbellbarton): avoid operator calls. */
if (obact == ob) {
ED_object_mode_set(C, mode);
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index cf6f26652a7..f222f93d2b6 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -291,7 +291,7 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
ARegion *region = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, region, depsgraph, scene, sseq, CFRA, 0, NULL);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, region, depsgraph, scene, sseq, scene->r.cfra, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;
@@ -428,10 +428,10 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const float color[3] = {1, 1, 1};
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(color);
- /* TODO(campbell): lock to pixels. */
+ /* TODO(@campbellbarton): lock to pixels. */
rctf sample_rect_fl;
BLI_rctf_init_pt_radius(
&sample_rect_fl,
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index be6ac6e13e6..60cbc2a2df6 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -311,6 +311,7 @@ static bool editstr_is_simple_numinput(const char ascii)
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
{
const char *utf8_buf = NULL;
+ const char event_ascii = WM_event_utf8_to_ascii(event);
char ascii[2] = {'\0', '\0'};
bool updated = false;
short idx = n->idx, idx_max = n->idx_max;
@@ -321,8 +322,8 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
if (U.flag & USER_FLAG_NUMINPUT_ADVANCED)
#endif
{
- if (((event->modifier & (KM_CTRL | KM_ALT)) == 0) && (event->ascii != '\0') &&
- strchr("01234567890@%^&*-+/{}()[]<>.|", event->ascii)) {
+ if (((event->modifier & (KM_CTRL | KM_ALT)) == 0) && (event_ascii != '\0') &&
+ strchr("01234567890@%^&*-+/{}()[]<>.|", event_ascii)) {
if (!(n->flag & NUM_EDIT_FULL)) {
n->flag |= NUM_EDITED;
n->flag |= NUM_EDIT_FULL;
@@ -333,7 +334,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
#ifdef USE_FAKE_EDIT
/* XXX Hack around keyboards without direct access to '=' nor '*'... */
- if (ELEM(event->ascii, '=', '*')) {
+ if (ELEM(event_ascii, '=', '*')) {
if (!(n->flag & NUM_EDIT_FULL)) {
n->flag |= NUM_EDIT_FULL;
n->val_flag[idx] |= NUM_EDITED;
@@ -357,7 +358,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
else {
/* might be a char too... */
utf8_buf = event->utf8_buf;
- ascii[0] = event->ascii;
+ ascii[0] = event_ascii;
}
break;
case EVT_BACKSPACEKEY:
@@ -523,9 +524,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
break;
}
- if (!updated && !utf8_buf && (event->utf8_buf[0] || event->ascii)) {
+ if (!updated && !utf8_buf && event->utf8_buf[0]) {
utf8_buf = event->utf8_buf;
- ascii[0] = event->ascii;
+ ascii[0] = event_ascii;
}
/* Up to this point, if we have a ctrl modifier, skip.
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 263ef06718f..b29afdb5a9f 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -10,6 +10,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_windowmanager_types.h"
#include "RNA_access.h"
@@ -66,15 +68,18 @@ eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
return sel_op;
}
-int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
+bool ED_select_similar_compare_float(const float delta,
+ const float thresh,
+ const eSimilarCmp compare)
{
+ BLI_assert(thresh >= 0.0f);
switch (compare) {
case SIM_CMP_EQ:
return (fabsf(delta) <= thresh);
case SIM_CMP_GT:
- return ((delta + thresh) >= 0.0);
+ return ((delta + thresh) >= 0.0f);
case SIM_CMP_LT:
- return ((delta - thresh) <= 0.0);
+ return ((delta - thresh) <= 0.0f);
default:
BLI_assert_unreachable();
return 0;
@@ -84,8 +89,10 @@ int ED_select_similar_compare_float(const float delta, const float thresh, const
bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
const float length,
const float thresh,
- const int compare)
+ const eSimilarCmp compare)
{
+ BLI_assert(compare == SIM_CMP_EQ || length >= 0.0f); /* See precision note below. */
+
/* Length of the edge we want to compare against. */
float nearest_edge_length;
@@ -112,6 +119,7 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
KDTreeNearest_1d nearest;
if (BLI_kdtree_1d_find_nearest(tree, &nearest_edge_length, &nearest) != -1) {
+ BLI_assert(compare == SIM_CMP_EQ || nearest.co[0] >= 0.0f); /* See precision note above. */
float delta = length - nearest.co[0];
return ED_select_similar_compare_float(delta, thresh, compare);
}
@@ -155,18 +163,18 @@ const char *ED_select_pick_get_name(wmOperatorType *UNUSED(ot), PointerRNA *ptr)
ED_select_pick_params_from_operator(ptr, &params);
switch (params.sel_op) {
case SEL_OP_ADD:
- return "Select (Extend)";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Select (Extend)");
case SEL_OP_SUB:
- return "Select (Deselect)";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Select (Deselect)");
case SEL_OP_XOR:
- return "Select (Toggle)";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Select (Toggle)");
case SEL_OP_AND:
BLI_assert_unreachable();
ATTR_FALLTHROUGH;
case SEL_OP_SET:
break;
}
- return "Select";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Select");
}
const char *ED_select_circle_get_name(wmOperatorType *UNUSED(ot), PointerRNA *ptr)
@@ -175,9 +183,9 @@ const char *ED_select_circle_get_name(wmOperatorType *UNUSED(ot), PointerRNA *pt
const eSelectOp sel_op = RNA_enum_get(ptr, "mode");
switch (sel_op) {
case SEL_OP_ADD:
- return "Circle Select (Extend)";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Circle Select (Extend)");
case SEL_OP_SUB:
- return "Circle Select (Deselect)";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Circle Select (Deselect)");
case SEL_OP_XOR:
ATTR_FALLTHROUGH;
case SEL_OP_AND:
@@ -186,7 +194,7 @@ const char *ED_select_circle_get_name(wmOperatorType *UNUSED(ot), PointerRNA *pt
case SEL_OP_SET:
break;
}
- return "Circle Select";
+ return CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Circle Select");
}
/** \} */
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 761e7cd091e..4574c745d93 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -13,7 +13,6 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/eigen
- ../../../../intern/glew-mx
../../../../intern/guardedalloc
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
@@ -23,7 +22,7 @@ set(INC
set(SRC
uvedit_buttons.c
uvedit_draw.c
- uvedit_islands.c
+ uvedit_islands.cc
uvedit_ops.c
uvedit_path.c
uvedit_rip.c
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 141b59e0355..9deeb27b259 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -39,7 +39,7 @@ void ED_image_draw_cursor(ARegion *region, const float cursor[2])
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 181982f0b2c..434bfbc64f9 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -14,9 +14,6 @@ struct Scene;
struct SpaceImage;
struct wmOperatorType;
-/* geometric utilities */
-void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len);
-
/* find nearest */
typedef struct UvNearestHit {
@@ -182,5 +179,6 @@ void UV_OT_select_circle(struct wmOperatorType *ot);
void UV_OT_select_more(struct wmOperatorType *ot);
void UV_OT_select_less(struct wmOperatorType *ot);
void UV_OT_select_overlap(struct wmOperatorType *ot);
+void UV_OT_select_similar(struct wmOperatorType *ot);
/* Used only when UV sync select is disabled. */
void UV_OT_select_mode(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.cc
index e1752ae5a29..42415be656a 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.cc
@@ -46,7 +46,7 @@ static void bm_face_uv_scale_y(BMFace *f, const float scale_y, const int cd_loop
BMLoop *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset));
luv->uv[1] *= scale_y;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -61,7 +61,7 @@ static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f,
BMLoop *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset));
for (int i = 0; i < 2; i++) {
luv->uv[i] = offset[i] + (((luv->uv[i] - pivot[i]) * scale[i]) + pivot[i]);
}
@@ -76,9 +76,10 @@ static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f,
static void bm_face_array_calc_bounds(BMFace **faces,
int faces_len,
- const uint cd_loop_uv_offset,
+ const int cd_loop_uv_offset,
rctf *r_bounds_rect)
{
+ BLI_assert(cd_loop_uv_offset >= 0);
float bounds_min[2], bounds_max[2];
INIT_MINMAX2(bounds_min, bounds_max);
for (int i = 0; i < faces_len; i++) {
@@ -96,8 +97,9 @@ static void bm_face_array_calc_bounds(BMFace **faces,
* without duplicating coordinates for loops that share a vertex.
*/
static float (*bm_face_array_calc_unique_uv_coords(
- BMFace **faces, int faces_len, const uint cd_loop_uv_offset, int *r_coords_len))[2]
+ BMFace **faces, int faces_len, const int cd_loop_uv_offset, int *r_coords_len))[2]
{
+ BLI_assert(cd_loop_uv_offset >= 0);
int coords_len_alloc = 0;
for (int i = 0; i < faces_len; i++) {
BMFace *f = faces[i];
@@ -109,7 +111,8 @@ static float (*bm_face_array_calc_unique_uv_coords(
coords_len_alloc += f->len;
}
- float(*coords)[2] = MEM_mallocN(sizeof(*coords) * coords_len_alloc, __func__);
+ float(*coords)[2] = static_cast<float(*)[2]>(
+ MEM_mallocN(sizeof(*coords) * coords_len_alloc, __func__));
int coords_len = 0;
for (int i = 0; i < faces_len; i++) {
@@ -123,7 +126,8 @@ static float (*bm_face_array_calc_unique_uv_coords(
}
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
- const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ const MLoopUV *luv = static_cast<const MLoopUV *>(
+ BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset));
copy_v2_v2(coords[coords_len++], luv->uv);
/* Un tag all connected so we don't add them twice.
@@ -138,7 +142,8 @@ static float (*bm_face_array_calc_unique_uv_coords(
do {
if (l_radial->v == l_iter->v) {
if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) {
- const MLoopUV *luv_radial = BM_ELEM_CD_GET_VOID_P(l_radial, cd_loop_uv_offset);
+ const MLoopUV *luv_radial = static_cast<const MLoopUV *>(
+ BM_ELEM_CD_GET_VOID_P(l_radial, cd_loop_uv_offset));
if (equals_v2v2(luv->uv, luv_radial->uv)) {
/* Don't add this UV when met in another face in `faces`. */
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
@@ -150,7 +155,6 @@ static float (*bm_face_array_calc_unique_uv_coords(
} while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != e_first);
} while ((l_iter = l_iter->next) != l_first);
}
- coords = MEM_reallocN(coords, sizeof(*coords) * coords_len);
*r_coords_len = coords_len;
return coords;
}
@@ -164,7 +168,7 @@ static float (*bm_face_array_calc_unique_uv_coords(
static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces,
int faces_len,
int align_to_axis,
- const uint cd_loop_uv_offset)
+ const int cd_loop_uv_offset)
{
/* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */
int coords_len;
@@ -209,7 +213,7 @@ static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces,
static void bm_face_array_uv_scale_y(BMFace **faces,
int faces_len,
const float scale_y,
- const uint cd_loop_uv_offset)
+ const int cd_loop_uv_offset)
{
for (int i = 0; i < faces_len; i++) {
BMFace *f = faces[i];
@@ -256,16 +260,11 @@ bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const floa
* Calculates distance to nearest UDIM image tile in UV space and its UDIM tile number.
*/
static float uv_nearest_image_tile_distance(const Image *image,
- float coords[2],
+ const float coords[2],
float nearest_tile_co[2])
{
- int nearest_image_tile_index = BKE_image_find_nearest_tile(image, coords);
- if (nearest_image_tile_index == -1) {
- nearest_image_tile_index = 1001;
- }
+ BKE_image_find_nearest_tile_with_offset(image, coords, nearest_tile_co);
- nearest_tile_co[0] = (nearest_image_tile_index - 1001) % 10;
- nearest_tile_co[1] = (nearest_image_tile_index - 1001) / 10;
/* Add 0.5 to get tile center coordinates. */
float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]};
add_v2_fl(nearest_tile_center_co, 0.5f);
@@ -313,31 +312,16 @@ static float uv_nearest_grid_tile_distance(const int udim_grid[2],
/* -------------------------------------------------------------------- */
/** \name Calculate UV Islands
- *
- * \note Currently this is a private API/type, it could be made public.
* \{ */
-struct FaceIsland {
- struct FaceIsland *next, *prev;
- BMFace **faces;
- int faces_len;
- rctf bounds_rect;
- /**
- * \note While this is duplicate information,
- * it allows islands from multiple meshes to be stored in the same list.
- */
- uint cd_loop_uv_offset;
- float aspect_y;
-};
-
struct SharedUVLoopData {
- uint cd_loop_uv_offset;
+ int cd_loop_uv_offset;
bool use_seams;
};
static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, void *user_data)
{
- const struct SharedUVLoopData *data = user_data;
+ const struct SharedUVLoopData *data = static_cast<const struct SharedUVLoopData *>(user_data);
if (data->use_seams) {
if (BM_elem_flag_test(l_a->e, BM_ELEM_SEAM)) {
@@ -351,24 +335,21 @@ static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, v
/**
* Calculate islands and add them to \a island_list returning the number of items added.
*/
-static int bm_mesh_calc_uv_islands(const Scene *scene,
- BMesh *bm,
- ListBase *island_list,
- const bool only_selected_faces,
- const bool only_selected_uvs,
- const bool use_seams,
- const float aspect_y,
- const uint cd_loop_uv_offset)
+int bm_mesh_calc_uv_islands(const Scene *scene,
+ BMesh *bm,
+ ListBase *island_list,
+ const bool only_selected_faces,
+ const bool only_selected_uvs,
+ const bool use_seams,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
{
+ BLI_assert(cd_loop_uv_offset >= 0);
int island_added = 0;
BM_mesh_elem_table_ensure(bm, BM_FACE);
- struct SharedUVLoopData user_data = {
- .cd_loop_uv_offset = cd_loop_uv_offset,
- .use_seams = use_seams,
- };
-
- int *groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__);
+ int *groups_array = static_cast<int *>(
+ MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__));
int(*group_index)[2];
@@ -393,6 +374,10 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
}
}
+ struct SharedUVLoopData user_data = {0};
+ user_data.cd_loop_uv_offset = cd_loop_uv_offset;
+ user_data.use_seams = use_seams;
+
const int group_len = BM_mesh_calc_face_groups(bm,
groups_array,
&group_index,
@@ -405,7 +390,7 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
for (int i = 0; i < group_len; i++) {
const int faces_start = group_index[i][0];
const int faces_len = group_index[i][1];
- BMFace **faces = MEM_mallocN(sizeof(*faces) * faces_len, __func__);
+ BMFace **faces = static_cast<BMFace **>(MEM_mallocN(sizeof(*faces) * faces_len, __func__));
float bounds_min[2], bounds_max[2];
INIT_MINMAX2(bounds_min, bounds_max);
@@ -414,7 +399,8 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
faces[j] = BM_face_at_index(bm, groups_array[faces_start + j]);
}
- struct FaceIsland *island = MEM_callocN(sizeof(*island), __func__);
+ struct FaceIsland *island = static_cast<struct FaceIsland *>(
+ MEM_callocN(sizeof(*island), __func__));
island->faces = faces;
island->faces_len = faces_len;
island->cd_loop_uv_offset = cd_loop_uv_offset;
@@ -483,9 +469,10 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
float margin = scene->toolsettings->uvcalc_margin;
double area = 0.0f;
- struct FaceIsland **island_array = MEM_mallocN(sizeof(*island_array) * island_list_len,
- __func__);
- BoxPack *boxarray = MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__);
+ struct FaceIsland **island_array = static_cast<struct FaceIsland **>(
+ MEM_mallocN(sizeof(*island_array) * island_list_len, __func__));
+ BoxPack *boxarray = static_cast<BoxPack *>(
+ MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__));
int index;
/* Coordinates of bounding box containing all selected UVs. */
@@ -637,7 +624,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
}
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index fe6f9f0d513..c0dd7623ade 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -189,15 +189,6 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
/** \name Geometric Utilities
* \{ */
-void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
-{
- int i;
- for (i = 0; i < len; i++) {
- uv[i][0] = uv_orig[i][0] * aspx;
- uv[i][1] = uv_orig[i][1] * aspy;
- }
-}
-
bool ED_uvedit_minmax_multi(
const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
{
@@ -372,6 +363,195 @@ typedef enum eUVWeldAlign {
UV_WELD,
} eUVWeldAlign;
+static bool uvedit_uv_align_weld(Scene *scene,
+ BMesh *bm,
+ const eUVWeldAlign tool,
+ const float cent[2])
+{
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
+ if (luv->uv[0] != cent[0]) {
+ luv->uv[0] = cent[0];
+ changed = true;
+ }
+ }
+ if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
+ if (luv->uv[1] != cent[1]) {
+ luv->uv[1] = cent[1];
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+/** Bitwise-or together, then choose #MLoopUV with highest value. */
+typedef enum eUVEndPointPrecedence {
+ UVEP_INVALID = 0,
+ UVEP_SELECTED = (1 << 0),
+ UVEP_PINNED = (1 << 1), /* i.e. Pinned verts are preferred to selected. */
+} eUVEndPointPrecedence;
+
+static eUVEndPointPrecedence uvedit_line_update_get_precedence(const MLoopUV *luv)
+{
+ eUVEndPointPrecedence precedence = UVEP_SELECTED;
+ if (luv->flag & MLOOPUV_PINNED) {
+ precedence |= UVEP_PINNED;
+ }
+ return precedence;
+}
+
+/**
+ * Helper to find two endpoints (`a` and `b`) which have higher precedence, and are far apart.
+ * Note that is only a heuristic and won't always find the best two endpoints.
+ */
+static bool uvedit_line_update_endpoint(const MLoopUV *luv,
+ float uv_a[2],
+ eUVEndPointPrecedence *prec_a,
+ float uv_b[2],
+ eUVEndPointPrecedence *prec_b)
+{
+ eUVEndPointPrecedence flags = uvedit_line_update_get_precedence(luv);
+
+ float len_sq_a = len_squared_v2v2(uv_a, luv->uv);
+ float len_sq_b = len_squared_v2v2(uv_b, luv->uv);
+
+ /* Caching the value of `len_sq_ab` is unlikely to be faster than recalculating.
+ * Profile before optimizing. */
+ float len_sq_ab = len_squared_v2v2(uv_a, uv_b);
+
+ if ((*prec_a < flags && 0.0f < len_sq_b) || (*prec_a == flags && len_sq_ab < len_sq_b)) {
+ *prec_a = flags;
+ copy_v2_v2(uv_a, luv->uv);
+ return true;
+ }
+
+ if ((*prec_b < flags && 0.0f < len_sq_a) || (*prec_b == flags && len_sq_ab < len_sq_a)) {
+ *prec_b = flags;
+ copy_v2_v2(uv_b, luv->uv);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Find two end extreme points to specify a line, then straighten `len` elements
+ * by moving UVs on the X-axis, Y-axis, or the closest point on the line segment.
+ */
+static bool uvedit_uv_straighten_elements(const UvElement *element,
+ const int len,
+ const int cd_loop_uv_offset,
+ const eUVWeldAlign tool)
+{
+ float uv_start[2];
+ float uv_end[2];
+ eUVEndPointPrecedence prec_start = UVEP_INVALID;
+ eUVEndPointPrecedence prec_end = UVEP_INVALID;
+
+ /* Find start and end of line. */
+ for (int i = 0; i < 10; i++) { /* Heuristic to prevent infinite loop. */
+ bool update = false;
+ for (int j = 0; j < len; j++) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset);
+ update |= uvedit_line_update_endpoint(luv, uv_start, &prec_start, uv_end, &prec_end);
+ }
+ if (!update) {
+ break;
+ }
+ }
+
+ if (prec_start == UVEP_INVALID || prec_end == UVEP_INVALID) {
+ return false; /* Unable to find two endpoints. */
+ }
+
+ float a = 0.0f; /* Similar to "slope". */
+ eUVWeldAlign tool_local = tool;
+
+ if (tool_local == UV_STRAIGHTEN_X) {
+ if (uv_start[1] == uv_end[1]) {
+ /* Caution, different behavior outside line segment. */
+ tool_local = UV_STRAIGHTEN;
+ }
+ else {
+ a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
+ }
+ }
+ else if (tool_local == UV_STRAIGHTEN_Y) {
+ if (uv_start[0] == uv_end[0]) {
+ /* Caution, different behavior outside line segment. */
+ tool_local = UV_STRAIGHTEN;
+ }
+ else {
+ a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
+ }
+ }
+
+ bool changed = false;
+ for (int j = 0; j < len; j++) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset);
+ /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
+ * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
+ * Maybe this should be a BLI func? Or is it already existing?
+ * Could use interp_v2_v2v2, but not sure it's worth it here. */
+ if (tool_local == UV_STRAIGHTEN_X) {
+ luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
+ }
+ else if (tool_local == UV_STRAIGHTEN_Y) {
+ luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
+ }
+ else {
+ closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
+ }
+ changed = true; /* TODO: Did the UV actually move? */
+ }
+ return changed;
+}
+
+/**
+ * Group selected UVs into islands, then apply uvedit_uv_straighten_elements to each island.
+ */
+static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool)
+{
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ return false;
+ }
+
+ UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true);
+ if (element_map == NULL) {
+ return false;
+ }
+
+ bool changed = false;
+ for (int i = 0; i < element_map->total_islands; i++) {
+ changed |= uvedit_uv_straighten_elements(element_map->storage + element_map->island_indices[i],
+ element_map->island_total_uvs[i],
+ cd_loop_uv_offset,
+ tool);
+ }
+
+ BM_uv_element_map_free(element_map);
+ return changed;
+}
+
static void uv_weld_align(bContext *C, eUVWeldAlign tool)
{
Scene *scene = CTX_data_scene(C);
@@ -429,194 +609,12 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
continue;
}
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = cent[0];
- changed = true;
- }
- }
- }
- }
-
- if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = cent[1];
- changed = true;
- }
- }
- }
+ if (ELEM(tool, UV_ALIGN_AUTO, UV_ALIGN_X, UV_ALIGN_Y, UV_WELD)) {
+ changed |= uvedit_uv_align_weld(scene, em->bm, tool, cent);
}
if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) {
- BMEdge *eed;
- BMLoop *l;
- BMVert *eve;
- BMVert *eve_start;
- BMIter iter, liter, eiter;
-
- /* clear tag */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- /* tag verts with a selected UV */
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, l->f)) {
- continue;
- }
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- BM_elem_flag_enable(eve, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- /* flush vertex tags to edges */
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- eed,
- BM_ELEM_TAG,
- (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
- }
-
- /* find a vertex with only one tagged edge */
- eve_start = NULL;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- int tot_eed_tag = 0;
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- tot_eed_tag++;
- }
- }
-
- if (tot_eed_tag == 1) {
- eve_start = eve;
- break;
- }
- }
-
- if (eve_start) {
- BMVert **eve_line = NULL;
- BMVert *eve_next = NULL;
- BLI_array_declare(eve_line);
- int i;
-
- eve = eve_start;
-
- /* walk over edges, building an array of verts in a line */
- while (eve) {
- BLI_array_append(eve_line, eve);
- /* don't touch again */
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
-
- eve_next = NULL;
-
- /* find next eve */
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- BMVert *eve_other = BM_edge_other_vert(eed, eve);
- if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
- /* this is a tagged vert we didn't walk over yet, step onto it */
- eve_next = eve_other;
- break;
- }
- }
- }
-
- eve = eve_next;
- }
-
- /* now we have all verts, make into a line */
- if (BLI_array_len(eve_line) > 2) {
-
- /* we know the returns from these must be valid */
- const float *uv_start = uvedit_first_selected_uv_from_vertex(
- scene, eve_line[0], cd_loop_uv_offset);
- const float *uv_end = uvedit_first_selected_uv_from_vertex(
- scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
- /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
- float a = 0.0f;
- eUVWeldAlign tool_local = tool;
-
- if (tool_local == UV_STRAIGHTEN_X) {
- if (uv_start[1] == uv_end[1]) {
- tool_local = UV_STRAIGHTEN;
- }
- else {
- a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
- }
- }
- else if (tool_local == UV_STRAIGHTEN_Y) {
- if (uv_start[0] == uv_end[0]) {
- tool_local = UV_STRAIGHTEN;
- }
- else {
- a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
- }
- }
-
- /* go over all verts except for endpoints */
- for (i = 0; i < BLI_array_len(eve_line); i++) {
- BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, l->f)) {
- continue;
- }
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
- * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
- * Maybe this should be a BLI func? Or is it already existing?
- * Could use interp_v2_v2v2, but not sure it's worth it here. */
- if (tool_local == UV_STRAIGHTEN_X) {
- luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
- }
- else if (tool_local == UV_STRAIGHTEN_Y) {
- luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
- }
- else {
- closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
- }
- changed = true;
- }
- }
- }
- }
- else {
- /* error - not a line, needs 3+ points. */
- }
-
- if (eve_line) {
- MEM_freeN(eve_line);
- }
- }
- else {
- /* error - can't find an endpoint. */
- }
+ changed |= uvedit_uv_straighten(scene, em->bm, tool);
}
if (changed) {
@@ -1026,6 +1024,12 @@ static bool uv_snap_cursor_to_selection(Scene *scene,
return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
}
+static void uv_snap_cursor_to_origin(float uvco[2])
+{
+ uvco[0] = 0;
+ uvco[1] = 0;
+}
+
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -1048,6 +1052,10 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
MEM_freeN(objects);
break;
}
+ case 2:
+ uv_snap_cursor_to_origin(sima->cursor);
+ changed = true;
+ break;
}
if (!changed) {
@@ -1064,6 +1072,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
static const EnumPropertyItem target_items[] = {
{0, "PIXELS", 0, "Pixels", ""},
{1, "SELECTED", 0, "Selected", ""},
+ {2, "ORIGIN", 0, "Origin", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1488,7 +1497,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
if (bm_face_is_all_uv_sel(efa, !swap, cd_loop_uv_offset)) {
BM_face_select_set(em->bm, efa, false);
}
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
}
else {
if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
@@ -1505,7 +1514,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
}
}
if (!swap) {
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
}
}
}
@@ -1527,7 +1536,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
break;
}
}
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
}
else {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1551,7 +1560,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
}
}
if (!swap) {
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
}
}
}
@@ -2044,6 +2053,7 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_select_pinned);
WM_operatortype_append(UV_OT_select_box);
WM_operatortype_append(UV_OT_select_lasso);
+ WM_operatortype_append(UV_OT_select_similar);
WM_operatortype_append(UV_OT_select_circle);
WM_operatortype_append(UV_OT_select_more);
WM_operatortype_append(UV_OT_select_less);
diff --git a/source/blender/editors/uvedit/uvedit_path.c b/source/blender/editors/uvedit/uvedit_path.c
index 7c6960a634a..19218259b95 100644
--- a/source/blender/editors/uvedit/uvedit_path.c
+++ b/source/blender/editors/uvedit/uvedit_path.c
@@ -56,75 +56,6 @@
#include "bmesh_tools.h"
/* -------------------------------------------------------------------- */
-/** \name Local Utilities
- * \{ */
-
-/**
- * Support edge-path using vert-path calculation code.
- *
- * Cheat! Pick 2 closest loops and do vertex path,
- * in practices only obscure/contrived cases will make give noticeably worse behavior.
- *
- * While the code below is a bit awkward, it's significantly less overhead than
- * adding full edge selection which is nearly the same as vertex path in the case of UV's.
- *
- * \param use_nearest: When false use the post distant pair of loops,
- * use when filling a region as we want both verts from each edge to be included in the region.
- */
-static void bm_loop_calc_vert_pair_from_edge_pair(const bool use_nearest,
- const int cd_loop_uv_offset,
- const float aspect_y,
- BMElem **ele_src_p,
- BMElem **ele_dst_p,
- BMElem **r_ele_dst_final)
-{
- BMLoop *l_src = (BMLoop *)*ele_src_p;
- BMLoop *l_dst = (BMLoop *)*ele_dst_p;
-
- const MLoopUV *luv_src_v1 = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
- const MLoopUV *luv_src_v2 = BM_ELEM_CD_GET_VOID_P(l_src->next, cd_loop_uv_offset);
- const MLoopUV *luv_dst_v1 = BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_uv_offset);
- const MLoopUV *luv_dst_v2 = BM_ELEM_CD_GET_VOID_P(l_dst->next, cd_loop_uv_offset);
-
- const float uv_src_v1[2] = {luv_src_v1->uv[0], luv_src_v1->uv[1] / aspect_y};
- const float uv_src_v2[2] = {luv_src_v2->uv[0], luv_src_v2->uv[1] / aspect_y};
- const float uv_dst_v1[2] = {luv_dst_v1->uv[0], luv_dst_v1->uv[1] / aspect_y};
- const float uv_dst_v2[2] = {luv_dst_v2->uv[0], luv_dst_v2->uv[1] / aspect_y};
-
- struct {
- int src_index;
- int dst_index;
- float len_sq;
- } tests[4] = {
- {0, 0, len_squared_v2v2(uv_src_v1, uv_dst_v1)},
- {0, 1, len_squared_v2v2(uv_src_v1, uv_dst_v2)},
- {1, 0, len_squared_v2v2(uv_src_v2, uv_dst_v1)},
- {1, 1, len_squared_v2v2(uv_src_v2, uv_dst_v2)},
- };
- int i_best = 0;
- for (int i = 1; i < ARRAY_SIZE(tests); i++) {
- if (use_nearest) {
- if (tests[i].len_sq < tests[i_best].len_sq) {
- i_best = i;
- }
- }
- else {
- if (tests[i].len_sq > tests[i_best].len_sq) {
- i_best = i;
- }
- }
- }
-
- *ele_src_p = (BMElem *)(tests[i_best].src_index ? l_src->next : l_src);
- *ele_dst_p = (BMElem *)(tests[i_best].dst_index ? l_dst->next : l_dst);
-
- /* Ensure the edge is selected, not just the vertices up until we hit it. */
- *r_ele_dst_final = (BMElem *)(tests[i_best].dst_index ? l_dst : l_dst->next);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Path Select Struct & Properties
* \{ */
@@ -140,7 +71,7 @@ struct PathSelectParams {
struct UserData_UV {
Scene *scene;
BMEditMesh *em;
- uint cd_loop_uv_offset;
+ int cd_loop_uv_offset;
};
static void path_select_properties(wmOperatorType *ot)
@@ -180,22 +111,22 @@ static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *
* \{ */
/* callbacks */
-static bool looptag_filter_cb(BMLoop *l, void *user_data_v)
+static bool verttag_filter_cb(BMLoop *l, void *user_data_v)
{
struct UserData_UV *user_data = user_data_v;
return uvedit_face_visible_test(user_data->scene, l->f);
}
-static bool looptag_test_cb(BMLoop *l, void *user_data_v)
+static bool verttag_test_cb(BMLoop *l, void *user_data_v)
{
/* All connected loops are selected or we return false. */
struct UserData_UV *user_data = user_data_v;
const Scene *scene = user_data->scene;
- const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ const int cd_loop_uv_offset = user_data->cd_loop_uv_offset;
const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BMIter iter;
BMLoop *l_iter;
BM_ITER_ELEM (l_iter, &iter, l->v, BM_LOOPS_OF_VERT) {
- if (looptag_filter_cb(l_iter, user_data)) {
+ if (verttag_filter_cb(l_iter, user_data)) {
const MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
if (equals_v2v2(luv->uv, luv_iter->uv)) {
if (!uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
@@ -206,20 +137,20 @@ static bool looptag_test_cb(BMLoop *l, void *user_data_v)
}
return true;
}
-static void looptag_set_cb(BMLoop *l, bool val, void *user_data_v)
+static void verttag_set_cb(BMLoop *l, bool val, void *user_data_v)
{
struct UserData_UV *user_data = user_data_v;
const Scene *scene = user_data->scene;
BMEditMesh *em = user_data->em;
- const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ const int cd_loop_uv_offset = user_data->cd_loop_uv_offset;
const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BMIter iter;
BMLoop *l_iter;
BM_ITER_ELEM (l_iter, &iter, l->v, BM_LOOPS_OF_VERT) {
- if (looptag_filter_cb(l_iter, user_data)) {
+ if (verttag_filter_cb(l_iter, user_data)) {
MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
if (equals_v2v2(luv->uv, luv_iter->uv)) {
- uvedit_uv_select_set(scene, em, l_iter, val, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l_iter, val, false, cd_loop_uv_offset);
}
}
}
@@ -233,42 +164,10 @@ static int mouse_mesh_uv_shortest_path_vert(Scene *scene,
const float aspect_y,
const int cd_loop_uv_offset)
{
- const char uv_selectmode = ED_uvedit_select_mode_get(scene);
- /* TODO(@sidd017): Implement logic to calculate shortest path for UV edges, since we now support
- * proper edge selection for UVs (D12028).
- * Till then continue using vertex path to fake shortest path calculation for edges. */
- const bool use_fake_edge_select = (uv_selectmode & UV_SELECT_EDGE);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
int flush = 0;
- /* Variables to use when `use_fake_edge_select` is set. */
- struct {
- BMLoop *l_dst_activate;
- BMLoop *l_dst_add_to_path;
- } fake_edge_select = {NULL};
-
- if (use_fake_edge_select) {
- fake_edge_select.l_dst_activate = l_dst;
-
- /* Use most distant when doing region selection.
- * without this we get dangling edges outside the region. */
- bool use_neaerst = (op_params->use_fill == false);
- BMElem *ele_src = (BMElem *)l_src;
- BMElem *ele_dst = (BMElem *)l_dst;
- BMElem *ele_dst_final = NULL;
- bm_loop_calc_vert_pair_from_edge_pair(
- use_neaerst, cd_loop_uv_offset, aspect_y, &ele_src, &ele_dst, &ele_dst_final);
-
- if (op_params->use_fill == false) {
- /* Always activate the item under the cursor. */
- fake_edge_select.l_dst_add_to_path = (BMLoop *)ele_dst_final;
- }
-
- l_src = (BMLoop *)ele_src;
- l_dst = (BMLoop *)ele_dst;
- }
-
struct UserData_UV user_data = {
.scene = scene,
.em = em,
@@ -291,33 +190,23 @@ static int mouse_mesh_uv_shortest_path_vert(Scene *scene,
(BMElem *)l_src,
(BMElem *)l_dst,
params.cd_loop_uv_offset,
- looptag_filter_cb,
+ verttag_filter_cb,
&user_data);
}
else {
is_path_ordered = true;
- path = BM_mesh_calc_path_uv_vert(bm, l_src, l_dst, &params, looptag_filter_cb, &user_data);
+ path = BM_mesh_calc_path_uv_vert(bm, l_src, l_dst, &params, verttag_filter_cb, &user_data);
}
}
BMLoop *l_dst_last = l_dst;
if (path) {
- if (use_fake_edge_select) {
- if ((fake_edge_select.l_dst_add_to_path != NULL) &&
- (BLI_linklist_index(path, fake_edge_select.l_dst_add_to_path) == -1)) {
- /* Append, this isn't optimal compared to #BLI_linklist_append, it's a one-off lookup. */
- LinkNode *path_last = BLI_linklist_find_last(path);
- BLI_linklist_insert_after(&path_last, fake_edge_select.l_dst_add_to_path);
- BLI_assert(BLI_linklist_find_last(path)->link == fake_edge_select.l_dst_add_to_path);
- }
- }
-
/* toggle the flag */
bool all_set = true;
LinkNode *node = path;
do {
- if (!looptag_test_cb((BMLoop *)node->link, &user_data)) {
+ if (!verttag_test_cb((BMLoop *)node->link, &user_data)) {
all_set = false;
break;
}
@@ -328,7 +217,7 @@ static int mouse_mesh_uv_shortest_path_vert(Scene *scene,
do {
if ((is_path_ordered == false) ||
WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
- looptag_set_cb((BMLoop *)node->link, !all_set, &user_data);
+ verttag_set_cb((BMLoop *)node->link, !all_set, &user_data);
if (is_path_ordered) {
l_dst_last = node->link;
}
@@ -339,23 +228,133 @@ static int mouse_mesh_uv_shortest_path_vert(Scene *scene,
flush = all_set ? -1 : 1;
}
else {
- const bool is_act = !looptag_test_cb(l_dst, &user_data);
- looptag_set_cb(l_dst, is_act, &user_data); /* switch the face option */
+ const bool is_act = !verttag_test_cb(l_dst, &user_data);
+ verttag_set_cb(l_dst, is_act, &user_data); /* switch the face option */
}
if (op_params->track_active) {
- /* Fake edge selection. */
- if (use_fake_edge_select) {
- BMLoop *l_dst_activate = fake_edge_select.l_dst_activate;
- /* TODO(campbell): Search for an active loop attached to 'l_dst'.
- * when `BLI_linklist_index(path, l_dst_activate) == -1`
- * In practice this rarely happens though. */
- ED_uvedit_active_edge_loop_set(bm, l_dst_activate);
+ ED_uvedit_active_vert_loop_set(bm, l_dst_last);
+ }
+ return flush;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name UV Edge Path
+ * \{ */
+
+/* callbacks */
+static bool edgetag_filter_cb(BMLoop *l, void *user_data_v)
+{
+ struct UserData_UV *user_data = user_data_v;
+ return uvedit_face_visible_test(user_data->scene, l->f);
+}
+static bool edgetag_test_cb(BMLoop *l, void *user_data_v)
+{
+ /* All connected loops (UV) are selected or we return false. */
+ struct UserData_UV *user_data = user_data_v;
+ const Scene *scene = user_data->scene;
+ const int cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ BMIter iter;
+ BMLoop *l_iter;
+ BM_ITER_ELEM (l_iter, &iter, l->e, BM_LOOPS_OF_EDGE) {
+ if (edgetag_filter_cb(l_iter, user_data)) {
+ if (BM_loop_uv_share_edge_check(l, l_iter, cd_loop_uv_offset)) {
+ if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+static void edgetag_set_cb(BMLoop *l, bool val, void *user_data_v)
+{
+ struct UserData_UV *user_data = user_data_v;
+ const Scene *scene = user_data->scene;
+ BMEditMesh *em = user_data->em;
+ const int cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ uvedit_edge_select_set_with_sticky(scene, em, l, val, false, cd_loop_uv_offset);
+}
+
+static int mouse_mesh_uv_shortest_path_edge(Scene *scene,
+ Object *obedit,
+ const struct PathSelectParams *op_params,
+ BMLoop *l_src,
+ BMLoop *l_dst,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int flush = 0;
+
+ struct UserData_UV user_data = {
+ .scene = scene,
+ .em = em,
+ .cd_loop_uv_offset = cd_loop_uv_offset,
+ };
+
+ const struct BMCalcPathUVParams params = {
+ .use_topology_distance = op_params->use_topology_distance,
+ .use_step_face = op_params->use_face_step,
+ .aspect_y = aspect_y,
+ .cd_loop_uv_offset = cd_loop_uv_offset,
+ };
+
+ LinkNode *path = NULL;
+ bool is_path_ordered = false;
+
+ if (l_src != l_dst) {
+ if (op_params->use_fill) {
+ path = BM_mesh_calc_path_uv_region_edge(bm,
+ (BMElem *)l_src,
+ (BMElem *)l_dst,
+ params.cd_loop_uv_offset,
+ edgetag_filter_cb,
+ &user_data);
}
else {
- ED_uvedit_active_vert_loop_set(bm, l_dst_last);
+ is_path_ordered = true;
+ path = BM_mesh_calc_path_uv_edge(bm, l_src, l_dst, &params, edgetag_filter_cb, &user_data);
}
}
+
+ BMLoop *l_dst_last = l_dst;
+
+ if (path) {
+ /* toggle the flag */
+ bool all_set = true;
+ LinkNode *node = path;
+ do {
+ if (!edgetag_test_cb((BMLoop *)node->link, &user_data)) {
+ all_set = false;
+ break;
+ }
+ } while ((node = node->next));
+
+ int depth = -1;
+ node = path;
+ do {
+ if ((is_path_ordered == false) ||
+ WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
+ edgetag_set_cb((BMLoop *)node->link, !all_set, &user_data);
+ if (is_path_ordered) {
+ l_dst_last = node->link;
+ }
+ }
+ } while ((void)depth++, (node = node->next));
+
+ BLI_linklist_free(path, NULL);
+ flush = all_set ? -1 : 1;
+ }
+ else {
+ const bool is_act = !edgetag_test_cb(l_dst, &user_data);
+ edgetag_set_cb(l_dst, is_act, &user_data); /* switch the face option */
+ }
+
+ if (op_params->track_active) {
+ ED_uvedit_active_edge_loop_set(bm, l_dst_last);
+ }
return flush;
}
@@ -376,7 +375,7 @@ static bool facetag_test_cb(BMFace *f, void *user_data_v)
/* All connected loops are selected or we return false. */
struct UserData_UV *user_data = user_data_v;
const Scene *scene = user_data->scene;
- const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ const int cd_loop_uv_offset = user_data->cd_loop_uv_offset;
BMIter iter;
BMLoop *l_iter;
BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) {
@@ -391,7 +390,7 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
struct UserData_UV *user_data = user_data_v;
const Scene *scene = user_data->scene;
BMEditMesh *em = user_data->em;
- const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
+ const int cd_loop_uv_offset = user_data->cd_loop_uv_offset;
uvedit_face_select_set_with_sticky(scene, em, f, val, false, cd_loop_uv_offset);
}
@@ -514,13 +513,24 @@ static bool uv_shortest_path_pick_ex(Scene *scene,
ok = true;
}
else if (ele_src->head.htype == BM_LOOP) {
- flush = mouse_mesh_uv_shortest_path_vert(scene,
- obedit,
- op_params,
- (BMLoop *)ele_src,
- (BMLoop *)ele_dst,
- aspect_y,
- cd_loop_uv_offset);
+ if (uv_selectmode & UV_SELECT_EDGE) {
+ flush = mouse_mesh_uv_shortest_path_edge(scene,
+ obedit,
+ op_params,
+ (BMLoop *)ele_src,
+ (BMLoop *)ele_dst,
+ aspect_y,
+ cd_loop_uv_offset);
+ }
+ else {
+ flush = mouse_mesh_uv_shortest_path_vert(scene,
+ obedit,
+ op_params,
+ (BMLoop *)ele_src,
+ (BMLoop *)ele_dst,
+ aspect_y,
+ cd_loop_uv_offset);
+ }
ok = true;
}
@@ -529,24 +539,9 @@ static bool uv_shortest_path_pick_ex(Scene *scene,
const bool select = (flush == 1);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (uv_selectmode & UV_SELECT_EDGE) {
- /* Special case as we don't use true edge selection,
- * flush the selection from the vertices. */
- BM_mesh_select_mode_flush_ex(em->bm, SCE_SELECT_VERTEX, BM_SELECT_LEN_FLUSH_RECALC_ALL);
- }
ED_uvedit_select_sync_flush(scene->toolsettings, em, select);
}
else {
- if (uv_selectmode & UV_SELECT_EDGE) {
- /* TODO(@sidd017): Remove this case when adding proper uv edge support for this operator.
- * In the meantime, this case helps ensures proper UV selection states for edge mode. */
- if (select) {
- uvedit_select_flush(scene, em);
- }
- else {
- uvedit_deselect_flush(scene, em);
- }
- }
ED_uvedit_selectmode_flush(scene, em);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c
index 545cc57e3c4..52e92b2e3c5 100644
--- a/source/blender/editors/uvedit/uvedit_rip.c
+++ b/source/blender/editors/uvedit/uvedit_rip.c
@@ -848,7 +848,7 @@ static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const
BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter);
ULData *ul = UL(l_iter);
if (ul->side == side_from_cursor) {
- uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset);
+ uvedit_uv_select_disable(scene, em->bm, l_iter, cd_loop_uv_offset);
changed = true;
}
/* Ensure we don't operate on these again. */
@@ -866,7 +866,7 @@ static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const
BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter);
ULData *ul = UL(l_iter);
if (ul->side == side_from_cursor) {
- uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset);
+ uvedit_uv_select_disable(scene, em->bm, l_iter, cd_loop_uv_offset);
changed = true;
}
/* Ensure we don't operate on these again. */
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index cea2bb05547..cecf0ff7914 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -12,6 +12,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_image_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -22,6 +23,7 @@
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_kdopbvh.h"
+#include "BLI_kdtree.h"
#include "BLI_lasso_2d.h"
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
@@ -31,6 +33,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_report.h"
@@ -75,6 +78,17 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
const ToolSettings *ts,
Object *obedit);
+typedef enum {
+ UV_SSIM_AREA_UV = 1000,
+ UV_SSIM_AREA_3D,
+ UV_SSIM_FACE,
+ UV_SSIM_LENGTH_UV,
+ UV_SSIM_LENGTH_3D,
+ UV_SSIM_SIDES,
+ UV_SSIM_PIN,
+ UV_SSIM_MATERIAL,
+} eUVSelectSimilar;
+
/* -------------------------------------------------------------------- */
/** \name Active Selection Tracking
*
@@ -193,7 +207,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em,
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
}
}
}
@@ -251,7 +265,7 @@ void uvedit_face_select_set_with_sticky(const Scene *scene,
const ToolSettings *ts = scene->toolsettings;
const char sticky = ts->uv_sticky;
if (ts->uv_flag & UV_SYNC_SELECTION) {
- uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset);
+ uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset);
return;
}
if (!uvedit_face_visible_test(scene, efa)) {
@@ -261,7 +275,7 @@ void uvedit_face_select_set_with_sticky(const Scene *scene,
* (not part of any face selections). This now uses the sticky location mode logic instead. */
switch (sticky) {
case SI_STICKY_DISABLE: {
- uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset);
+ uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset);
break;
}
default: {
@@ -299,32 +313,30 @@ void uvedit_face_select_shared_vert(const Scene *scene,
}
void uvedit_face_select_set(const Scene *scene,
- BMEditMesh *em,
+ BMesh *bm,
BMFace *efa,
const bool select,
const bool do_history,
const int cd_loop_uv_offset)
{
if (select) {
- uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
+ uvedit_face_select_enable(scene, bm, efa, do_history, cd_loop_uv_offset);
}
else {
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ uvedit_face_select_disable(scene, bm, efa, cd_loop_uv_offset);
}
}
-void uvedit_face_select_enable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset)
+void uvedit_face_select_enable(
+ const Scene *scene, BMesh *bm, BMFace *efa, const bool do_history, const int cd_loop_uv_offset)
{
+ BLI_assert(cd_loop_uv_offset >= 0);
const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, true);
+ BM_face_select_set(bm, efa, true);
if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)efa);
+ BM_select_history_store(bm, (BMElem *)efa);
}
}
else {
@@ -340,14 +352,15 @@ void uvedit_face_select_enable(const Scene *scene,
}
void uvedit_face_select_disable(const Scene *scene,
- BMEditMesh *em,
+ BMesh *bm,
BMFace *efa,
const int cd_loop_uv_offset)
{
+ BLI_assert(cd_loop_uv_offset >= 0);
const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, false);
+ BM_face_select_set(bm, efa, false);
}
else {
BMLoop *l;
@@ -393,11 +406,11 @@ void uvedit_edge_select_set_with_sticky(const Scene *scene,
BMLoop *l,
const bool select,
const bool do_history,
- const uint cd_loop_uv_offset)
+ const int cd_loop_uv_offset)
{
const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
- uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
+ uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset);
return;
}
@@ -405,7 +418,7 @@ void uvedit_edge_select_set_with_sticky(const Scene *scene,
switch (sticky) {
case SI_STICKY_DISABLE: {
if (uvedit_face_visible_test(scene, l->f)) {
- uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
+ uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset);
}
break;
}
@@ -487,7 +500,7 @@ void uvedit_edge_select_set_noflush(const Scene *scene,
}
void uvedit_edge_select_set(const Scene *scene,
- BMEditMesh *em,
+ BMesh *bm,
BMLoop *l,
const bool select,
const bool do_history,
@@ -495,36 +508,33 @@ void uvedit_edge_select_set(const Scene *scene,
{
if (select) {
- uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset);
+ uvedit_edge_select_enable(scene, bm, l, do_history, cd_loop_uv_offset);
}
else {
- uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset);
+ uvedit_edge_select_disable(scene, bm, l, cd_loop_uv_offset);
}
}
-void uvedit_edge_select_enable(const Scene *scene,
- BMEditMesh *em,
- BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset)
+void uvedit_edge_select_enable(
+ const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
{
const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, true);
+ BM_face_select_set(bm, l->f, true);
}
else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->bm, l->e, true);
+ BM_edge_select_set(bm, l->e, true);
}
else {
- BM_vert_select_set(em->bm, l->e->v1, true);
- BM_vert_select_set(em->bm, l->e->v2, true);
+ BM_vert_select_set(bm, l->e->v1, true);
+ BM_vert_select_set(bm, l->e->v2, true);
}
if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)l->e);
+ BM_select_history_store(bm, (BMElem *)l->e);
}
}
else {
@@ -538,7 +548,7 @@ void uvedit_edge_select_enable(const Scene *scene,
}
void uvedit_edge_select_disable(const Scene *scene,
- BMEditMesh *em,
+ BMesh *bm,
BMLoop *l,
const int cd_loop_uv_offset)
@@ -547,14 +557,14 @@ void uvedit_edge_select_disable(const Scene *scene,
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, false);
+ BM_face_select_set(bm, l->f, false);
}
else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->bm, l->e, false);
+ BM_edge_select_set(bm, l->e, false);
}
else {
- BM_vert_select_set(em->bm, l->e->v1, false);
- BM_vert_select_set(em->bm, l->e->v2, false);
+ BM_vert_select_set(bm, l->e->v1, false);
+ BM_vert_select_set(bm, l->e->v2, false);
}
}
else {
@@ -586,12 +596,25 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo
if (ts->selectmode & SCE_SELECT_FACE) {
return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
}
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_test(...)` instead? */
+ }
return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
}
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ /* Are you looking for `uvedit_face_select_test(...)` instead? */
+ }
+
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_test(...)` instead? */
+ }
+
return (luv->flag & MLOOPUV_VERTSEL) != 0;
}
+
bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
@@ -602,11 +625,11 @@ void uvedit_uv_select_set_with_sticky(const Scene *scene,
BMLoop *l,
const bool select,
const bool do_history,
- const uint cd_loop_uv_offset)
+ const int cd_loop_uv_offset)
{
const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
- uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset);
return;
}
@@ -614,7 +637,7 @@ void uvedit_uv_select_set_with_sticky(const Scene *scene,
switch (sticky) {
case SI_STICKY_DISABLE: {
if (uvedit_face_visible_test(scene, l->f)) {
- uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset);
}
break;
}
@@ -668,7 +691,8 @@ void uvedit_uv_select_shared_vert(const Scene *scene,
}
if (do_select) {
- uvedit_uv_select_set(scene, em, l_radial_iter, select, do_history, cd_loop_uv_offset);
+ uvedit_uv_select_set(
+ scene, em->bm, l_radial_iter, select, do_history, cd_loop_uv_offset);
}
}
}
@@ -677,38 +701,39 @@ void uvedit_uv_select_shared_vert(const Scene *scene,
}
void uvedit_uv_select_set(const Scene *scene,
- BMEditMesh *em,
+ BMesh *bm,
BMLoop *l,
const bool select,
const bool do_history,
const int cd_loop_uv_offset)
{
if (select) {
- uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset);
+ uvedit_uv_select_enable(scene, bm, l, do_history, cd_loop_uv_offset);
}
else {
- uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset);
+ uvedit_uv_select_disable(scene, bm, l, cd_loop_uv_offset);
}
}
-void uvedit_uv_select_enable(const Scene *scene,
- BMEditMesh *em,
- BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset)
+void uvedit_uv_select_enable(
+ const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
{
const ToolSettings *ts = scene->toolsettings;
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_set(...)` instead? */
+ }
+
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, true);
+ BM_face_select_set(bm, l->f, true);
}
else {
- BM_vert_select_set(em->bm, l->v, true);
+ BM_vert_select_set(bm, l->v, true);
}
if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)l->v);
+ BM_select_history_store(bm, (BMElem *)l->v);
}
}
else {
@@ -718,7 +743,7 @@ void uvedit_uv_select_enable(const Scene *scene,
}
void uvedit_uv_select_disable(const Scene *scene,
- BMEditMesh *em,
+ BMesh *bm,
BMLoop *l,
const int cd_loop_uv_offset)
{
@@ -726,10 +751,10 @@ void uvedit_uv_select_disable(const Scene *scene,
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, false);
+ BM_face_select_set(bm, l->f, false);
}
else {
- BM_vert_select_set(em->bm, l->v, false);
+ BM_vert_select_set(bm, l->v, false);
}
}
else {
@@ -1109,7 +1134,7 @@ BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene,
const float co[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BMIter liter;
BMLoop *l;
@@ -1137,7 +1162,8 @@ BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene,
const float co[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BLI_assert(cd_loop_uv_offset >= 0);
BMIter eiter;
BMLoop *l;
@@ -1391,7 +1417,7 @@ static BMLoop *bm_select_edgeloop_single_side_next(const Scene *scene,
scene, l_step, v_from_next, cd_loop_uv_offset);
}
-/* TODO(campbell): support this in the BMesh API, as we have for clearing other types. */
+/* TODO(@campbellbarton): support this in the BMesh API, as we have for clearing other types. */
static void bm_loop_tags_clear(BMesh *bm)
{
BMIter iter;
@@ -1944,7 +1970,7 @@ static void uv_select_linked_multi(Scene *scene,
BM_face_select_set(em->bm, efa, value); \
} \
else { \
- uvedit_face_select_set(scene, em, efa, value, false, cd_loop_uv_offset); \
+ uvedit_face_select_set(scene, em->bm, efa, value, false, cd_loop_uv_offset); \
} \
(void)0
@@ -2905,12 +2931,14 @@ void UV_OT_select_edge_ring(wmOperatorType *ot)
ot->poll = ED_operator_uvedit; /* requires space image */
/* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_float_vector(
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_float_vector(
ot->srna,
"location",
2,
@@ -2921,6 +2949,7 @@ void UV_OT_select_edge_ring(wmOperatorType *ot)
"Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
-100.0f,
100.0f);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -3213,7 +3242,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene,
UvMapVert *start_vlist = NULL, *vlist_iter;
BMFace *efa_vlist;
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
@@ -3231,7 +3260,6 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene,
vlist_iter = start_vlist;
while (vlist_iter) {
-
if (vlist_iter != start_vlist && vlist_iter->separate) {
break;
}
@@ -3244,7 +3272,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene,
l_other = BM_iter_at_index(
em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
- uvedit_uv_select_set(scene, em, l_other, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l_other, select, false, cd_loop_uv_offset);
}
vlist_iter = vlist_iter->next;
}
@@ -3311,7 +3339,7 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co
else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
+ uvedit_face_select_set(scene, em->bm, efa, select, false, cd_loop_uv_offset);
}
}
}
@@ -3360,7 +3388,7 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
}
}
}
@@ -3389,7 +3417,7 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
}
}
}
@@ -3549,6 +3577,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
}
}
else if (use_edge && !pinned) {
+ bool do_second_pass = true;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
@@ -3563,11 +3592,35 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
uvedit_edge_select_set_with_sticky(
scene, em, l_prev, select, false, cd_loop_uv_offset);
changed = true;
+ do_second_pass = false;
}
l_prev = l;
luv_prev = luv;
}
}
+ /* Do a second pass if no complete edges could be selected.
+ * This matches wire-frame edit-mesh selection in the 3D view. */
+ if (do_second_pass) {
+ /* Second pass to check if edges partially overlap with the selection area (box). */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (BLI_rctf_isect_segment(&rectf, luv_prev->uv, luv->uv)) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ l_prev = l;
+ luv_prev = luv;
+ }
+ }
+ }
}
else {
/* other selection modes */
@@ -3585,14 +3638,14 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
/* UV_SYNC_SELECTION - can't do pinned selection */
if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
BM_elem_flag_enable(l->v, BM_ELEM_TAG);
has_selected = true;
}
}
else if (pinned) {
if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
BM_elem_flag_enable(l->v, BM_ELEM_TAG);
}
}
@@ -3659,9 +3712,9 @@ void UV_OT_select_box(wmOperatorType *ot)
/** \name Circle Select Operator
* \{ */
-static int uv_circle_select_is_point_inside(const float uv[2],
- const float offset[2],
- const float ellipse[2])
+static bool uv_circle_select_is_point_inside(const float uv[2],
+ const float offset[2],
+ const float ellipse[2])
{
/* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
const float co[2] = {
@@ -3671,10 +3724,10 @@ static int uv_circle_select_is_point_inside(const float uv[2],
return len_squared_v2(co) < 1.0f;
}
-static int uv_circle_select_is_edge_inside(const float uv_a[2],
- const float uv_b[2],
- const float offset[2],
- const float ellipse[2])
+static bool uv_circle_select_is_edge_inside(const float uv_a[2],
+ const float uv_b[2],
+ const float offset[2],
+ const float ellipse[2])
{
/* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
const float co_a[2] = {
@@ -3805,7 +3858,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) {
changed = true;
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
BM_elem_flag_enable(l->v, BM_ELEM_TAG);
has_selected = true;
}
@@ -3887,6 +3940,24 @@ static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region,
return false;
}
+static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region,
+ const rcti *clip_rect,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const float co_test_a[2],
+ const float co_test_b[2])
+{
+ int co_screen_a[2], co_screen_b[2];
+ if (UI_view2d_view_to_region_segment_clip(
+ &region->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
+ BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
+ BLI_lasso_is_edge_inside(
+ mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) {
+ return true;
+ }
+ return false;
+}
+
static bool do_lasso_select_mesh_uv(bContext *C,
const int mcoords[][2],
const int mcoords_len,
@@ -3955,6 +4026,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
}
}
else if (use_edge) {
+ bool do_second_pass = true;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
@@ -3971,12 +4043,37 @@ static bool do_lasso_select_mesh_uv(bContext *C,
region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
uvedit_edge_select_set_with_sticky(
scene, em, l_prev, select, false, cd_loop_uv_offset);
+ do_second_pass = false;
changed = true;
}
l_prev = l;
luv_prev = luv;
}
}
+ /* Do a second pass if no complete edges could be selected.
+ * This matches wire-frame edit-mesh selection in the 3D view. */
+ if (do_second_pass) {
+ /* Second pass to check if edges partially overlap with the selection area (lasso). */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_edge_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv, luv_prev->uv)) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ l_prev = l;
+ luv_prev = luv;
+ }
+ }
+ }
}
else { /* Vert Selection. */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
@@ -3991,7 +4088,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (do_lasso_select_mesh_uv_is_point_inside(
region, &rect, mcoords, mcoords_len, luv->uv)) {
- uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
changed = true;
BM_elem_flag_enable(l->v, BM_ELEM_TAG);
has_selected = true;
@@ -4111,7 +4208,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *op)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (luv->flag & MLOOPUV_PINNED) {
- uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset);
+ uvedit_uv_select_enable(scene, em->bm, l, false, cd_loop_uv_offset);
changed = true;
}
}
@@ -4364,8 +4461,8 @@ static int uv_select_overlap(bContext *C, const bool extend)
/* Main tri-tri overlap test. */
const float endpoint_bias = -1e-4f;
if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) {
- uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
- uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
+ uvedit_face_select_enable(scene, em_a->bm, face_a, false, cd_loop_uv_offset_a);
+ uvedit_face_select_enable(scene, em_b->bm, face_b, false, cd_loop_uv_offset_b);
}
}
@@ -4412,6 +4509,716 @@ void UV_OT_select_overlap(wmOperatorType *ot)
}
/** \} */
+/** \name Select Similar Operator
+ * \{ */
+
+static float get_uv_vert_needle(const eUVSelectSimilar type,
+ BMVert *vert,
+ const float ob_m3[3][3],
+ MLoopUV *luv,
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
+ result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
+ }
+ } break;
+ case UV_SSIM_AREA_3D: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
+ result += BM_face_calc_area_with_mat3(f, ob_m3);
+ }
+ } break;
+ case UV_SSIM_SIDES: {
+ BMEdge *e;
+ BMIter iter;
+ BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) {
+ result += 1.0f;
+ }
+ } break;
+ case UV_SSIM_PIN:
+ return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ return result;
+}
+
+static float get_uv_edge_needle(const eUVSelectSimilar type,
+ BMEdge *edge,
+ const float ob_m3[3][3],
+ MLoopUV *luv_a,
+ MLoopUV *luv_b,
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
+ result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
+ }
+ } break;
+ case UV_SSIM_AREA_3D: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
+ result += BM_face_calc_area_with_mat3(f, ob_m3);
+ }
+ } break;
+ case UV_SSIM_LENGTH_UV:
+ return len_v2v2(luv_a->uv, luv_b->uv);
+ case UV_SSIM_LENGTH_3D:
+ return len_v3v3(edge->v1->co, edge->v2->co);
+ case UV_SSIM_SIDES: {
+ BMEdge *e;
+ BMIter iter;
+ BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) {
+ result += 1.0f;
+ }
+ } break;
+ case UV_SSIM_PIN:
+ if (luv_a->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ if (luv_b->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ break;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ return result;
+}
+
+static float get_uv_face_needle(const eUVSelectSimilar type,
+ BMFace *face,
+ const float ob_m3[3][3],
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV:
+ return BM_face_calc_area_uv(face, cd_loop_uv_offset);
+ case UV_SSIM_AREA_3D:
+ return BM_face_calc_area_with_mat3(face, ob_m3);
+ case UV_SSIM_SIDES:
+ return face->len;
+ case UV_SSIM_PIN: {
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ }
+ } break;
+ case UV_SSIM_MATERIAL:
+ return face->mat_nr;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+ return result;
+}
+
+static float get_uv_island_needle(const eUVSelectSimilar type,
+ const struct FaceIsland *island,
+ const float ob_m3[3][3],
+ const int cd_loop_uv_offset)
+
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV:
+ for (int i = 0; i < island->faces_len; i++) {
+ result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset);
+ }
+ break;
+ case UV_SSIM_AREA_3D:
+ for (int i = 0; i < island->faces_len; i++) {
+ result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3);
+ }
+ break;
+ case UV_SSIM_FACE:
+ return island->faces_len;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+ return result;
+}
+
+static int uv_select_similar_vert_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_verts_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ max_verts_selected_all += face->len;
+ }
+ /* TODO: Get a tighter bounds */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_verts_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue; /* Already selected. */
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_similar_edge_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_edges_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ max_edges_selected_all += face->len;
+ }
+ /* TODO: Get a tighter bounds. */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_edges_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ continue; /* Already selected. */
+ }
+
+ MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_edge_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_similar_face_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_faces_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ max_faces_selected_all += em->bm->totfacesel;
+ /* TODO: Get a tighter bounds */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_faces_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ bool changed = false;
+ bool do_history = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
+
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_face_select_set(scene, em->bm, face, select, do_history, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static bool uv_island_selected(const Scene *scene, struct FaceIsland *island)
+{
+ BLI_assert(island && island->faces_len);
+ return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset);
+}
+
+static int uv_select_similar_island_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__);
+ int island_list_len = 0;
+
+ const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ continue;
+ }
+
+ float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */
+ island_list_len += bm_mesh_calc_uv_islands(scene,
+ em->bm,
+ &island_list_ptr[ob_index],
+ face_selected,
+ false,
+ false,
+ aspect_y,
+ cd_loop_uv_offset);
+ }
+
+ struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len,
+ __func__);
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ continue;
+ }
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, obedit->obmat);
+
+ int index;
+ LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) {
+ island_array[index] = island;
+ if (!uv_island_selected(scene, island)) {
+ continue;
+ }
+ float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ int tot_island_index = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ continue;
+ }
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, obedit->obmat);
+
+ bool changed = false;
+ int index;
+ LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) {
+ island_array[tot_island_index++] = island; /* To deallocate later. */
+ if (uv_island_selected(scene, island)) {
+ continue;
+ }
+ float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (!select) {
+ continue;
+ }
+ bool do_history = false;
+ for (int j = 0; j < island->faces_len; j++) {
+ uvedit_face_select_set(
+ scene, em->bm, island->faces[j], select, do_history, island->cd_loop_uv_offset);
+ }
+ changed = true;
+ }
+
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+
+ BLI_assert(tot_island_index == island_list_len);
+ for (int i = 0; i < island_list_len; i++) {
+ MEM_SAFE_FREE(island_array[i]->faces);
+ MEM_SAFE_FREE(island_array[i]);
+ }
+
+ MEM_SAFE_FREE(island_array);
+ MEM_SAFE_FREE(island_list_ptr);
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Select similar UV faces/edges/verts based on current selection. */
+static int uv_select_similar_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, ts->select_thresh);
+ }
+ else {
+ ts->select_thresh = RNA_property_float_get(op->ptr, prop);
+ }
+
+ int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
+ if (selectmode & UV_SELECT_EDGE) {
+ return uv_select_similar_edge_exec(C, op);
+ }
+ if (selectmode & UV_SELECT_FACE) {
+ return uv_select_similar_face_exec(C, op);
+ }
+ if (selectmode & UV_SELECT_ISLAND) {
+ return uv_select_similar_island_exec(C, op);
+ }
+
+ return uv_select_similar_vert_exec(C, op);
+}
+
+static EnumPropertyItem prop_vert_similar_types[] = {{UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, {0}};
+
+static EnumPropertyItem prop_edge_similar_types[] = {
+ {UV_SSIM_LENGTH_UV, "LENGTH", 0, "Length", ""},
+ {UV_SSIM_LENGTH_3D, "LENGTH_3D", 0, "Length 3D", ""},
+ {UV_SSIM_PIN, "PIN", 0, "Pinned", ""},
+ {0}};
+
+static EnumPropertyItem prop_face_similar_types[] = {
+ {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""},
+ {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""},
+ {UV_SSIM_SIDES, "SIDES", 0, "Polygon Sides", ""},
+ {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""},
+ {0}};
+
+static EnumPropertyItem prop_island_similar_types[] = {
+ {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""},
+ {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""},
+ {UV_SSIM_FACE, "FACE", 0, "Amount of Faces in Island", ""},
+ {0}};
+
+static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
+ {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
+ {SIM_CMP_LT, "LESS", 0, "Less", ""},
+ {0}};
+
+static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ const ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts) {
+ int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
+ if (selectmode & UV_SELECT_EDGE) {
+ return prop_edge_similar_types;
+ }
+ if (selectmode & UV_SELECT_FACE) {
+ return prop_face_similar_types;
+ }
+ if (selectmode & UV_SELECT_ISLAND) {
+ return prop_island_similar_types;
+ }
+ }
+
+ return prop_vert_similar_types;
+}
+void UV_OT_select_similar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->description = "Select similar UVs by property types";
+ ot->idname = "UV_OT_select_similar";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = uv_select_similar_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop = ot->prop = RNA_def_enum(
+ ot->srna, "type", prop_vert_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, uv_select_similar_type_itemf);
+ RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+ RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
@@ -4577,12 +5384,12 @@ static void uv_isolate_selected_islands(const Scene *scene,
BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0);
BMFace *efa;
BMIter iter, liter;
- UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, true, false, false, true);
+ UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true);
if (elementmap == NULL) {
return;
}
- int num_islands = elementmap->totalIslands;
+ int num_islands = elementmap->total_islands;
/* Boolean array that tells if island with index i is completely selected or not. */
bool *is_island_not_selected = MEM_callocN(sizeof(bool) * (num_islands), __func__);
@@ -4674,7 +5481,7 @@ void ED_uvedit_selectmode_clean(const Scene *scene, Object *obedit)
if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- uvedit_face_select_set(scene, em, efa, false, false, cd_loop_uv_offset);
+ uvedit_face_select_set(scene, em->bm, efa, false, false, cd_loop_uv_offset);
}
}
uv_select_flush_from_tag_face(scene, obedit, true);
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 55e44607f6f..e89f99fc412 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -287,14 +287,6 @@ static void stitch_update_header(StitchStateContainer *ssc, bContext *C)
}
}
-static int getNumOfIslandUvs(UvElementMap *elementMap, int island)
-{
- if (island == elementMap->totalIslands - 1) {
- return elementMap->totalUVs - elementMap->islandIndices[island];
- }
- return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island];
-}
-
static void stitch_uv_rotate(const float mat[2][2],
const float medianPoint[2],
float uv[2],
@@ -419,10 +411,9 @@ static void stitch_calculate_island_snapping(StitchState *state,
int final)
{
BMesh *bm = state->em->bm;
- int i;
UvElement *element;
- for (i = 0; i < state->element_map->totalIslands; i++) {
+ for (int i = 0; i < state->element_map->total_islands; i++) {
if (island_stitch_data[i].addedForPreview) {
int numOfIslandUVs = 0, j;
int totelem = island_stitch_data[i].num_rot_elements_neg +
@@ -464,8 +455,8 @@ static void stitch_calculate_island_snapping(StitchState *state,
}
angle_to_mat2(rotation_mat, rotation);
- numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
- element = &state->element_map->buf[state->element_map->islandIndices[i]];
+ numOfIslandUVs = state->element_map->island_total_uvs[i];
+ element = &state->element_map->storage[state->element_map->island_indices[i]];
for (j = 0; j < numOfIslandUVs; j++, element++) {
/* stitchable uvs have already been processed, don't process */
if (!(element->flag & STITCH_PROCESSED)) {
@@ -527,8 +518,8 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge,
luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV);
if (ssc->mode == STITCH_VERT) {
- index1 = uvfinal_map[element1 - state->element_map->buf];
- index2 = uvfinal_map[element2 - state->element_map->buf];
+ index1 = uvfinal_map[element1 - state->element_map->storage];
+ index2 = uvfinal_map[element2 - state->element_map->storage];
}
else {
index1 = edge->uv1;
@@ -569,27 +560,17 @@ static void stitch_island_calculate_vert_rotation(UvElement *element,
StitchState *state,
IslandStitchData *island_stitch_data)
{
- float edgecos = 1.0f, edgesin = 0.0f;
- int index;
- UvElement *element_iter;
float rotation = 0, rotation_neg = 0;
int rot_elem = 0, rot_elem_neg = 0;
- BMLoop *l;
if (element->island == ssc->static_island && !ssc->midpoints) {
return;
}
- l = element->l;
-
- index = BM_elem_index_get(l->v);
-
- element_iter = state->element_map->vert[index];
-
+ UvElement *element_iter = BM_uv_element_get_head(state->element_map, element);
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate &&
stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
- int index_tmp1, index_tmp2;
float normal[2];
/* only calculate rotation against static island uv verts */
@@ -597,14 +578,14 @@ static void stitch_island_calculate_vert_rotation(UvElement *element,
continue;
}
- index_tmp1 = element_iter - state->element_map->buf;
+ int index_tmp1 = element_iter - state->element_map->storage;
index_tmp1 = state->map[index_tmp1];
- index_tmp2 = element - state->element_map->buf;
+ int index_tmp2 = element - state->element_map->storage;
index_tmp2 = state->map[index_tmp2];
negate_v2_v2(normal, state->normals + index_tmp2 * 2);
- edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
- edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
+ float edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
+ float edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
if (edgesin > 0.0f) {
rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
rot_elem++;
@@ -653,9 +634,8 @@ static void state_delete(StitchState *state)
if (state->edges) {
MEM_freeN(state->edges);
}
- if (state->stitch_preview) {
- stitch_preview_delete(state->stitch_preview);
- }
+ stitch_preview_delete(state->stitch_preview);
+ state->stitch_preview = NULL;
if (state->edge_hash) {
BLI_ghash_free(state->edge_hash, NULL, NULL);
}
@@ -680,10 +660,7 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *
UvEdge *edges = state->edges;
const int *map = state->map;
UvElementMap *element_map = state->element_map;
- UvElement *first_element = element_map->buf;
- int i;
-
- for (i = 0; i < state->total_separate_edges; i++) {
+ for (int i = 0; i < state->total_separate_edges; i++) {
UvEdge *edge = edges + i;
if (edge->first) {
@@ -696,7 +673,7 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *
UvElement *element2 = state->uvs[edge->uv2];
/* Now iterate through all faces and try to find edges sharing the same vertices */
- UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)];
+ UvElement *iter1 = BM_uv_element_get_head(state->element_map, element1);
UvEdge *last_set = edge;
int elemindex2 = BM_elem_index_get(element2->l->v);
@@ -714,8 +691,8 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *
}
if (iter2) {
- int index1 = map[iter1 - first_element];
- int index2 = map[iter2 - first_element];
+ int index1 = map[iter1 - element_map->storage];
+ int index2 = map[iter2 - element_map->storage];
UvEdge edgetmp;
UvEdge *edge2, *eiter;
bool valid = true;
@@ -764,15 +741,7 @@ static void determine_uv_stitchability(UvElement *element,
StitchState *state,
IslandStitchData *island_stitch_data)
{
- int vert_index;
- UvElement *element_iter;
- BMLoop *l;
-
- l = element->l;
-
- vert_index = BM_elem_index_get(l->v);
- element_iter = state->element_map->vert[vert_index];
-
+ UvElement *element_iter = BM_uv_element_get_head(state->element_map, element);
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) {
@@ -853,16 +822,7 @@ static void stitch_validate_uv_stitchability(UvElement *element,
return;
}
- UvElement *element_iter;
- int vert_index;
- BMLoop *l;
-
- l = element->l;
-
- vert_index = BM_elem_index_get(l->v);
-
- element_iter = state->element_map->vert[vert_index];
-
+ UvElement *element_iter = BM_uv_element_get_head(state->element_map, element);
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
if (element_iter == element) {
@@ -956,7 +916,7 @@ static void stitch_propagate_uv_final_position(Scene *scene,
if (final) {
copy_v2_v2(luv->uv, final_position[index].uv);
- uvedit_uv_select_enable(scene, state->em, l, false, cd_loop_uv_offset);
+ uvedit_uv_select_enable(scene, state->em->bm, l, false, cd_loop_uv_offset);
}
else {
int face_preview_pos =
@@ -1015,7 +975,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
preview_position[i].data_position = STITCH_NO_PREVIEW;
}
- island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands,
+ island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->total_islands,
"stitch_island_data");
if (!island_stitch_data) {
return 0;
@@ -1040,7 +1000,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
}
/* Remember stitchable candidates as places the 'I' button will stop at. */
- for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) {
+ for (int island_idx = 0; island_idx < state->element_map->total_islands; island_idx++) {
state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ?
true :
false;
@@ -1048,10 +1008,10 @@ static int stitch_process_data(StitchStateContainer *ssc,
if (is_active_state) {
/* set static island to one that is added for preview */
- ssc->static_island %= state->element_map->totalIslands;
+ ssc->static_island %= state->element_map->total_islands;
while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) {
ssc->static_island++;
- ssc->static_island %= state->element_map->totalIslands;
+ ssc->static_island %= state->element_map->total_islands;
/* this is entirely possible if for example limit stitching
* with no stitchable verts or no selection */
if (ssc->static_island == previous_island) {
@@ -1172,13 +1132,11 @@ static int stitch_process_data(StitchStateContainer *ssc,
* Setup preview for stitchable islands *
****************************************/
if (ssc->snap_islands) {
- for (i = 0; i < state->element_map->totalIslands; i++) {
+ for (i = 0; i < state->element_map->total_islands; i++) {
if (island_stitch_data[i].addedForPreview) {
- int numOfIslandUVs = 0, j;
- UvElement *element;
- numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
- element = &state->element_map->buf[state->element_map->islandIndices[i]];
- for (j = 0; j < numOfIslandUVs; j++, element++) {
+ int numOfIslandUVs = state->element_map->island_total_uvs[i];
+ UvElement *element = &state->element_map->storage[state->element_map->island_indices[i]];
+ for (int j = 0; j < numOfIslandUVs; j++, element++) {
stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
}
}
@@ -1263,7 +1221,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
if (ssc->mode == STITCH_VERT) {
final_position = MEM_callocN(state->selection_size * sizeof(*final_position),
"stitch_uv_average");
- uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map),
+ uvfinal_map = MEM_mallocN(state->element_map->total_uvs * sizeof(*uvfinal_map),
"stitch_uv_final_map");
}
else {
@@ -1279,12 +1237,11 @@ static int stitch_process_data(StitchStateContainer *ssc,
if (element->flag & STITCH_STITCHABLE) {
BMLoop *l;
MLoopUV *luv;
- UvElement *element_iter;
l = element->l;
luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- uvfinal_map[element - state->element_map->buf] = i;
+ uvfinal_map[element - state->element_map->storage] = i;
copy_v2_v2(final_position[i].uv, luv->uv);
final_position[i].count = 1;
@@ -1293,8 +1250,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
continue;
}
- element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
-
+ UvElement *element_iter = state->element_map->vertex[BM_elem_index_get(l->v)];
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
@@ -1542,6 +1498,7 @@ static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int
static uint uv_edge_hash(const void *key)
{
const UvEdge *edge = key;
+ BLI_assert(edge->uv1 < edge->uv2);
return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
}
@@ -1549,6 +1506,8 @@ static bool uv_edge_compare(const void *a, const void *b)
{
const UvEdge *edge1 = a;
const UvEdge *edge2 = b;
+ BLI_assert(edge1->uv1 < edge1->uv2);
+ BLI_assert(edge2->uv1 < edge2->uv2);
if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
return 0;
@@ -1588,13 +1547,8 @@ static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_sele
/* Select all common uvs */
static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
{
- BMLoop *l;
- UvElement *element_iter;
UvElement **selection_stack = (UvElement **)state->selection_stack;
-
- l = element->l;
-
- element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
+ UvElement *element_iter = BM_uv_element_get_head(state->element_map, element);
/* first deselect all common uvs */
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
@@ -1710,7 +1664,7 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4])
{
GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4fv(batch, "color", col);
GPU_batch_draw(batch);
GPU_batch_discard(batch);
@@ -1850,8 +1804,8 @@ static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l);
UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next);
- int uv1 = state->map[element1 - state->element_map->buf];
- int uv2 = state->map[element2 - state->element_map->buf];
+ int uv1 = state->map[element1 - state->element_map->storage];
+ int uv2 = state->map[element2 - state->element_map->storage];
if (uv1 < uv2) {
tmp_edge.uv1 = uv1;
@@ -1878,7 +1832,6 @@ static StitchState *stitch_init(bContext *C,
int total_edges;
/* maps uvelements to their first coincident uv */
int *map;
- int counter = 0, i;
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1902,15 +1855,7 @@ static StitchState *stitch_init(bContext *C,
* for stitch this isn't useful behavior, see T86924. */
const int selectmode_orig = scene->toolsettings->selectmode;
scene->toolsettings->selectmode = SCE_SELECT_VERTEX;
-
- /* in uv synch selection, all uv's are visible */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true);
- }
- else {
- state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
- }
-
+ state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true);
scene->toolsettings->selectmode = selectmode_orig;
if (!state->element_map) {
@@ -1921,45 +1866,39 @@ static StitchState *stitch_init(bContext *C,
ED_uvedit_get_aspect(obedit, &aspx, &aspy);
state->aspect = aspx / aspy;
- /* Count 'unique' uvs */
- for (i = 0; i < state->element_map->totalUVs; i++) {
- if (state->element_map->buf[i].separate) {
- counter++;
- }
- }
+ int unique_uvs = state->element_map->total_unique_uvs;
+ state->total_separate_uvs = unique_uvs;
- /* explicitly set preview to NULL,
- * to avoid deleting an invalid pointer on stitch_process_data */
- state->stitch_preview = NULL;
/* Allocate the unique uv buffers */
- state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs");
+ state->uvs = MEM_mallocN(sizeof(*state->uvs) * unique_uvs, "uv_stitch_unique_uvs");
/* internal uvs need no normals but it is hard and slow to keep a map of
- * normals only for boundary uvs, so allocating for all uvs */
- state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals");
- state->total_separate_uvs = counter;
- state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs,
+ * normals only for boundary uvs, so allocating for all uvs.
+ * Times 2 because each `float[2]` is stored as `{n[2 * i], n[2*i + 1]}`. */
+ state->normals = MEM_callocN(sizeof(*state->normals) * 2 * unique_uvs, "uv_stitch_normals");
+ state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->total_uvs,
"uv_stitch_unique_map");
/* Allocate the edge stack */
edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
- all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges");
+ all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->total_uvs, "ssc_edges");
+ BLI_assert(!state->stitch_preview); /* Paranoia. */
if (!state->uvs || !map || !edge_hash || !all_edges) {
state_delete(state);
return NULL;
}
- /* So that we can use this as index for the UvElements */
- counter = -1;
+ /* Index for the UvElements. */
+ int counter = -1;
/* initialize the unique UVs and map */
- for (i = 0; i < em->bm->totvert; i++) {
- UvElement *element = state->element_map->vert[i];
+ for (int i = 0; i < em->bm->totvert; i++) {
+ UvElement *element = state->element_map->vertex[i];
for (; element; element = element->next) {
if (element->separate) {
counter++;
state->uvs[counter] = element;
}
/* Pointer arithmetic to the rescue, as always :). */
- map[element - state->element_map->buf] = counter;
+ map[element - state->element_map->storage] = counter;
}
}
@@ -1973,13 +1912,13 @@ static StitchState *stitch_init(bContext *C,
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
UvElement *element = BM_uv_element_get(state->element_map, efa, l);
- int offset1, itmp1 = element - state->element_map->buf;
- int offset2,
- itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf;
+ int itmp1 = element - state->element_map->storage;
+ int itmp2 = BM_uv_element_get(state->element_map, efa, l->next) -
+ state->element_map->storage;
UvEdge *edge;
- offset1 = map[itmp1];
- offset2 = map[itmp2];
+ int offset1 = map[itmp1];
+ int offset2 = map[itmp2];
all_edges[counter].next = NULL;
all_edges[counter].first = NULL;
@@ -2020,7 +1959,7 @@ static StitchState *stitch_init(bContext *C,
state->total_separate_edges = total_edges;
/* fill the edges with data */
- i = 0;
+ int i = 0;
GHASH_ITER (gh_iter, edge_hash) {
edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
}
@@ -2099,13 +2038,13 @@ static StitchState *stitch_init(bContext *C,
efa = BM_face_at_index(em->bm, faceIndex);
element = BM_uv_element_get(
state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
- uv1 = map[element - state->element_map->buf];
+ uv1 = map[element - state->element_map->storage];
element = BM_uv_element_get(
state->element_map,
efa,
BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len));
- uv2 = map[element - state->element_map->buf];
+ uv2 = map[element - state->element_map->storage];
if (uv1 < uv2) {
tmp_edge.uv1 = uv1;
@@ -2170,8 +2109,8 @@ static StitchState *stitch_init(bContext *C,
/***** initialize static island preview data *****/
state->tris_per_island = MEM_mallocN(
- sizeof(*state->tris_per_island) * state->element_map->totalIslands, "stitch island tris");
- for (i = 0; i < state->element_map->totalIslands; i++) {
+ sizeof(*state->tris_per_island) * state->element_map->total_islands, "stitch island tris");
+ for (i = 0; i < state->element_map->total_islands; i++) {
state->tris_per_island[i] = 0;
}
@@ -2183,7 +2122,7 @@ static StitchState *stitch_init(bContext *C,
}
}
- state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands,
+ state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->total_islands,
"stitch I stops");
if (!state->island_is_stitchable) {
state_delete(state);
@@ -2207,7 +2146,7 @@ static bool goto_next_island(StitchStateContainer *ssc)
do {
ssc->static_island++;
- if (ssc->static_island >= active_state->element_map->totalIslands) {
+ if (ssc->static_island >= active_state->element_map->total_islands) {
/* go to next object */
ssc->active_object_index++;
ssc->active_object_index %= ssc->objects_len;
@@ -2357,7 +2296,7 @@ static int stitch_init_all(bContext *C, wmOperator *op)
ssc->static_island = RNA_int_get(op->ptr, "static_island");
StitchState *state = ssc->states[ssc->active_object_index];
- ssc->static_island %= state->element_map->totalIslands;
+ ssc->static_island %= state->element_map->total_islands;
/* If the initial active object doesn't have any stitchable islands
* then no active island will be seen in the UI.
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 3618286ec01..b01a24af68f 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -204,6 +204,8 @@ typedef struct UnwrapOptions {
bool fill_holes;
/** Correct for mapped image texture aspect ratio. */
bool correct_aspect;
+ /** Treat unselected uvs as if they were pinned. */
+ bool pin_unselected;
} UnwrapOptions;
typedef struct UnwrapResultInfo {
@@ -240,7 +242,7 @@ static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const Unwr
}
}
- if (options->topology_from_uvs && !l) {
+ if (options->only_selected_uvs && !l) {
continue;
}
@@ -311,8 +313,14 @@ static bool uvedit_is_face_affected(const Scene *scene,
return false;
}
- if (options->topology_from_uvs && options->only_selected_uvs &&
- !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ if (options->only_selected_uvs) {
+ BMLoop *l;
+ BMIter iter;
+ BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ return true;
+ }
+ }
return false;
}
@@ -322,14 +330,20 @@ static bool uvedit_is_face_affected(const Scene *scene,
/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert.
*/
static void uvedit_prepare_pinned_indices(ParamHandle *handle,
+ const Scene *scene,
BMFace *efa,
+ const UnwrapOptions *options,
const int cd_loop_uv_offset)
{
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_PINNED) {
+ bool pin = luv->flag & MLOOPUV_PINNED;
+ if (options->pin_unselected && !pin) {
+ pin = !uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ }
+ if (pin) {
int bmvertindex = BM_elem_index_get(l->v);
GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv);
}
@@ -340,6 +354,7 @@ static void construct_param_handle_face_add(ParamHandle *handle,
const Scene *scene,
BMFace *efa,
ParamKey face_index,
+ const UnwrapOptions *options,
const int cd_loop_uv_offset)
{
ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
@@ -362,12 +377,56 @@ static void construct_param_handle_face_add(ParamHandle *handle,
uv[i] = luv->uv;
pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if (options->pin_unselected && !select[i]) {
+ pin[i] = true;
+ }
}
GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select);
}
-/* See: construct_param_handle_multi to handle multiple objects at once. */
+/* Set seams on UV Parametrizer based on options. */
+static void construct_param_edge_set_seams(ParamHandle *handle,
+ BMesh *bm,
+ const UnwrapOptions *options)
+{
+ if (options->topology_from_uvs && !options->topology_from_uvs_use_seams) {
+ return; /* Seams are not required with these options. */
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ return; /* UVs aren't present on BMesh. Nothing to do. */
+ }
+
+ BMEdge *edge;
+ BMIter iter;
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
+ continue; /* No seam on this edge, nothing to do. */
+ }
+
+ /* Pinned vertices might have more than one ParamKey per BMVert.
+ * Check all the BM_LOOPS_OF_EDGE to find all the ParamKeys.
+ */
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, edge, BM_LOOPS_OF_EDGE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ ParamKey vkeys[2];
+ vkeys[0] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
+ vkeys[1] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->next->v), luv_next->uv);
+
+ /* Set the seam. */
+ GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
+ }
+ }
+}
+
+/*
+ * Version of #construct_param_handle_multi with a separate BMesh parameter.
+ */
static ParamHandle *construct_param_handle(const Scene *scene,
Object *ob,
BMesh *bm,
@@ -375,7 +434,6 @@ static ParamHandle *construct_param_handle(const Scene *scene,
UnwrapResultInfo *result_info)
{
BMFace *efa;
- BMEdge *eed;
BMIter iter;
int i;
@@ -397,26 +455,17 @@ static ParamHandle *construct_param_handle(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
- uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
+ uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset);
}
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
- construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
+ construct_param_handle_face_add(handle, scene, efa, i, options, cd_loop_uv_offset);
}
}
- if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
- vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
- GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
- }
- }
- }
+ construct_param_edge_set_seams(handle, bm, options);
GEO_uv_parametrizer_construct_end(handle,
options->fill_holes,
@@ -427,16 +476,14 @@ static ParamHandle *construct_param_handle(const Scene *scene,
}
/**
- * Version of #construct_param_handle_single that handles multiple objects.
+ * Version of #construct_param_handle that handles multiple objects.
*/
static ParamHandle *construct_param_handle_multi(const Scene *scene,
Object **objects,
const uint objects_len,
- const UnwrapOptions *options,
- int *count_fail)
+ const UnwrapOptions *options)
{
BMFace *efa;
- BMEdge *eed;
BMIter iter;
int i;
@@ -470,31 +517,23 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
- uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
+ uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset);
}
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
- construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
+ construct_param_handle_face_add(
+ handle, scene, efa, i + offset, options, cd_loop_uv_offset);
}
}
- if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
- vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
- GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
- }
- }
- }
+ construct_param_edge_set_seams(handle, bm, options);
+
offset += bm->totface;
}
- GEO_uv_parametrizer_construct_end(
- handle, options->fill_holes, options->topology_from_uvs, count_fail);
+ GEO_uv_parametrizer_construct_end(handle, options->fill_holes, options->topology_from_uvs, NULL);
return handle;
}
@@ -773,7 +812,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
ms->blend = RNA_float_get(op->ptr, "blend");
ms->iterations = RNA_int_get(op->ptr, "iterations");
ms->i = 0;
- ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL);
+ ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options);
ms->lasttime = PIL_check_seconds_timer();
GEO_uv_parametrizer_stretch_begin(ms->handle);
@@ -1043,7 +1082,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
bool rotate,
bool ignore_pinned)
{
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1152,7 +1191,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
/** \name Average UV Islands Scale Operator
* \{ */
-static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
+static int average_islands_scale_exec(bContext *C, wmOperator *op)
{
const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1176,8 +1215,12 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL);
- GEO_uv_parametrizer_average(handle, false);
+ /* RNA props */
+ const bool scale_uv = RNA_boolean_get(op->ptr, "scale_uv");
+ const bool shear = RNA_boolean_get(op->ptr, "shear");
+
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options);
+ GEO_uv_parametrizer_average(handle, false, scale_uv, shear);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1208,6 +1251,10 @@ void UV_OT_average_islands_scale(wmOperatorType *ot)
/* api callbacks */
ot->exec = average_islands_scale_exec;
ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "scale_uv", false, "Non-Uniform", "Scale U and V independently");
+ RNA_def_boolean(ot->srna, "shear", false, "Shear", "Reduce shear within islands");
}
/** \} */
@@ -1237,7 +1284,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
const UnwrapOptions options = {
.topology_from_uvs = false,
.only_selected_faces = false,
- .only_selected_uvs = true,
+ .only_selected_uvs = false,
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
@@ -1667,10 +1714,12 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
* such as "Unwrap" & "Smart UV Projections" will need to handle aspect correction themselves.
* For now keep using a single aspect for all faces in this case.
*/
-static void uv_map_clip_correct_multi(Object **objects,
- uint objects_len,
- wmOperator *op,
- bool per_face_aspect)
+static void uv_map_clip_correct(const Scene *scene,
+ Object **objects,
+ uint objects_len,
+ wmOperator *op,
+ bool per_face_aspect,
+ bool only_selected_uvs)
{
BMFace *efa;
BMLoop *l;
@@ -1707,6 +1756,10 @@ static void uv_map_clip_correct_multi(Object **objects,
continue;
}
+ if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ continue;
+ }
+
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
minmax_v2v2_v2(min, max, luv->uv);
@@ -1720,6 +1773,10 @@ static void uv_map_clip_correct_multi(Object **objects,
continue;
}
+ if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ continue;
+ }
+
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
clamp_v2(luv->uv, 0.0f, 1.0f);
@@ -1756,6 +1813,10 @@ static void uv_map_clip_correct_multi(Object **objects,
continue;
}
+ if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ continue;
+ }
+
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
@@ -1767,11 +1828,6 @@ static void uv_map_clip_correct_multi(Object **objects,
}
}
-static void uv_map_clip_correct(Object *ob, wmOperator *op)
-{
- uv_map_clip_correct_multi(&ob, 1, op, true);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1806,7 +1862,7 @@ static void uvedit_unwrap(const Scene *scene,
result_info ? &result_info->count_failed : NULL);
GEO_uv_parametrizer_lscm_end(handle);
- GEO_uv_parametrizer_average(handle, true);
+ GEO_uv_parametrizer_average(handle, true, false, false);
GEO_uv_parametrizer_flush(handle);
@@ -1833,7 +1889,7 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
const UnwrapOptions options = {
.topology_from_uvs = false,
.only_selected_faces = false,
- .only_selected_uvs = true,
+ .only_selected_uvs = false,
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
@@ -1866,16 +1922,21 @@ static int unwrap_exec(bContext *C, wmOperator *op)
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
view_layer, CTX_wm_view3d(C), &objects_len);
- const UnwrapOptions options = {
+ UnwrapOptions options = {
.topology_from_uvs = false,
.only_selected_faces = true,
- .only_selected_uvs = true,
+ .only_selected_uvs = false,
.fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
.correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
};
bool rotate = true;
bool ignore_pinned = true;
+ if (CTX_wm_space_image(C)) {
+ /* Inside the UV Editor, only unwrap selected UVs. */
+ options.only_selected_uvs = true;
+ options.pin_unselected = true;
+ }
if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
MEM_freeN(objects);
@@ -2193,6 +2254,12 @@ static int smart_project_exec(bContext *C, wmOperator *op)
/* May be NULL. */
View3D *v3d = CTX_wm_view3d(C);
+ bool only_selected_uvs = false;
+ if (CTX_wm_space_image(C)) {
+ /* Inside the UV Editor, only project selected UVs. */
+ only_selected_uvs = true;
+ }
+
const float project_angle_limit = RNA_float_get(op->ptr, "angle_limit");
const float island_margin = RNA_float_get(op->ptr, "island_margin");
const float area_weight = RNA_float_get(op->ptr, "area_weight");
@@ -2223,7 +2290,8 @@ static int smart_project_exec(bContext *C, wmOperator *op)
continue;
}
- const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BLI_assert(cd_loop_uv_offset >= 0);
ThickFace *thick_faces = MEM_mallocN(sizeof(*thick_faces) * em->bm->totface, __func__);
uint thick_faces_len = 0;
@@ -2231,6 +2299,14 @@ static int smart_project_exec(bContext *C, wmOperator *op)
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
+
+ if (only_selected_uvs) {
+ if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
+ continue;
+ }
+ }
+
thick_faces[thick_faces_len].area = BM_face_calc_area(efa);
thick_faces[thick_faces_len].efa = efa;
thick_faces_len++;
@@ -2345,6 +2421,7 @@ static int smart_project_exec(bContext *C, wmOperator *op)
.rotate = true,
/* We could make this optional. */
.rotate_align_axis = 1,
+ .only_selected_uvs = true,
.only_selected_faces = true,
.correct_aspect = correct_aspect,
.use_seams = true,
@@ -2352,7 +2429,8 @@ static int smart_project_exec(bContext *C, wmOperator *op)
/* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
const bool per_face_aspect = false;
- uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect);
+ uv_map_clip_correct(
+ scene, objects_changed, object_changed_len, op, per_face_aspect, only_selected_uvs);
}
MEM_freeN(objects_changed);
@@ -2554,7 +2632,9 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if (changed_multi) {
- uv_map_clip_correct_multi(objects, objects_len, op, true);
+ const bool per_face_aspect = true;
+ const bool only_selected_uvs = false;
+ uv_map_clip_correct(scene, objects, objects_len, op, per_face_aspect, only_selected_uvs);
}
MEM_freeN(objects);
@@ -2714,6 +2794,12 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ bool only_selected_uvs = false;
+ if (CTX_wm_space_image(C)) {
+ /* Inside the UV Editor, only project selected UVs. */
+ only_selected_uvs = true;
+ }
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -2746,6 +2832,13 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
continue;
}
+ if (only_selected_uvs) {
+ if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
+ continue;
+ }
+ }
+
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
@@ -2755,7 +2848,8 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
uv_map_mirror(em, efa);
}
- uv_map_clip_correct(obedit, op);
+ const bool per_face_aspect = true;
+ uv_map_clip_correct(scene, &obedit, 1, op, per_face_aspect, only_selected_uvs);
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -2812,6 +2906,12 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ bool only_selected_uvs = false;
+ if (CTX_wm_space_image(C)) {
+ /* Inside the UV Editor, only project selected UVs. */
+ only_selected_uvs = true;
+ }
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -2844,16 +2944,21 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
continue;
}
+ if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset);
+ continue;
+ }
+
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
}
uv_map_mirror(em, efa);
}
- uv_map_clip_correct(obedit, op);
+ const bool per_face_aspect = true;
+ uv_map_clip_correct(scene, &obedit, 1, op, per_face_aspect, only_selected_uvs);
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -2887,9 +2992,11 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
/** \name Cube UV Project Operator
* \{ */
-static void uvedit_unwrap_cube_project(BMesh *bm,
+static void uvedit_unwrap_cube_project(const Scene *scene,
+ BMesh *bm,
float cube_size,
- bool use_select,
+ const bool use_select,
+ const bool only_selected_uvs,
const float center[3])
{
BMFace *efa;
@@ -2921,6 +3028,10 @@ static void uvedit_unwrap_cube_project(BMesh *bm,
if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
+ if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ uvedit_face_select_disable(scene, bm, efa, cd_loop_uv_offset);
+ continue;
+ }
axis_dominant_v3(&cox, &coy, efa->no);
@@ -2937,6 +3048,12 @@ static int cube_project_exec(bContext *C, wmOperator *op)
const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ bool only_selected_uvs = false;
+ if (CTX_wm_space_image(C)) {
+ /* Inside the UV Editor, only cube project selected UVs. */
+ only_selected_uvs = true;
+ }
+
PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
@@ -2979,9 +3096,10 @@ static int cube_project_exec(bContext *C, wmOperator *op)
}
}
- uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
+ uvedit_unwrap_cube_project(scene, em->bm, cube_size, true, only_selected_uvs, center);
- uv_map_clip_correct(obedit, op);
+ const bool per_face_aspect = true;
+ uv_map_clip_correct(scene, &obedit, 1, op, per_face_aspect, only_selected_uvs);
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -3048,7 +3166,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
ED_uvedit_select_all(bm);
/* A cube size of 2.0 maps [-1..1] vertex coords to [0.0..1.0] in UV coords. */
- uvedit_unwrap_cube_project(bm, 2.0, false, NULL);
+ uvedit_unwrap_cube_project(scene, bm, 2.0, false, false, NULL);
/* Set the margin really quickly before the packing operation. */
scene->toolsettings->uvcalc_margin = 0.001f;
uvedit_pack_islands(scene, ob, bm);